@arbidocs/react 0.5.73 → 0.5.75

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 (54) hide show
  1. package/README.md +85 -66
  2. package/dist/artifacts/index.cjs +9 -9
  3. package/dist/artifacts/index.js +3 -3
  4. package/dist/calls/livekit/index.cjs +48 -48
  5. package/dist/calls/livekit/index.js +3 -3
  6. package/dist/{chunk-M3SB5TZB.js → chunk-2MECTZLS.js} +9 -5
  7. package/dist/chunk-2MECTZLS.js.map +1 -0
  8. package/dist/{chunk-R7YNABZY.js → chunk-2Y6LJNWA.js} +2 -2
  9. package/dist/{chunk-R7YNABZY.js.map → chunk-2Y6LJNWA.js.map} +1 -1
  10. package/dist/{chunk-QGOYIYLI.js → chunk-33PVGKXT.js} +819 -509
  11. package/dist/chunk-33PVGKXT.js.map +1 -0
  12. package/dist/{chunk-Y7S2SQH3.cjs → chunk-5YGUBXXH.cjs} +2 -2
  13. package/dist/{chunk-Y7S2SQH3.cjs.map → chunk-5YGUBXXH.cjs.map} +1 -1
  14. package/dist/{chunk-RS6UUPD2.cjs → chunk-6RSVGLQY.cjs} +853 -536
  15. package/dist/chunk-6RSVGLQY.cjs.map +1 -0
  16. package/dist/{chunk-2LV53J46.js → chunk-JHN4PKWX.js} +3 -3
  17. package/dist/{chunk-2LV53J46.js.map → chunk-JHN4PKWX.js.map} +1 -1
  18. package/dist/{chunk-ZTPJNKF2.js → chunk-LC276BI7.js} +5 -5
  19. package/dist/chunk-LC276BI7.js.map +1 -0
  20. package/dist/{chunk-GOJHU7RZ.cjs → chunk-MWW54PY6.cjs} +25 -25
  21. package/dist/{chunk-GOJHU7RZ.cjs.map → chunk-MWW54PY6.cjs.map} +1 -1
  22. package/dist/{chunk-4DTTEUVY.js → chunk-O2HDONQE.js} +4 -4
  23. package/dist/{chunk-4DTTEUVY.js.map → chunk-O2HDONQE.js.map} +1 -1
  24. package/dist/{chunk-SI7DJWBT.js → chunk-OR6B7IL2.js} +3 -3
  25. package/dist/{chunk-SI7DJWBT.js.map → chunk-OR6B7IL2.js.map} +1 -1
  26. package/dist/{chunk-LMW46NBD.cjs → chunk-OY4PYCJH.cjs} +5 -5
  27. package/dist/chunk-OY4PYCJH.cjs.map +1 -0
  28. package/dist/{chunk-HXITD6DN.cjs → chunk-PMHFLOXY.cjs} +27 -22
  29. package/dist/chunk-PMHFLOXY.cjs.map +1 -0
  30. package/dist/{chunk-TGSEQGM3.cjs → chunk-QEVM3F5X.cjs} +4 -4
  31. package/dist/{chunk-TGSEQGM3.cjs.map → chunk-QEVM3F5X.cjs.map} +1 -1
  32. package/dist/{chunk-ZNQPUPX6.cjs → chunk-RDERZWMO.cjs} +16 -16
  33. package/dist/{chunk-ZNQPUPX6.cjs.map → chunk-RDERZWMO.cjs.map} +1 -1
  34. package/dist/document-tools/core.cjs +99 -99
  35. package/dist/document-tools/core.js +3 -3
  36. package/dist/document-tools/index.cjs +101 -101
  37. package/dist/document-tools/index.js +4 -4
  38. package/dist/index.cjs +1036 -891
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +411 -240
  41. package/dist/index.d.ts +411 -240
  42. package/dist/index.js +143 -32
  43. package/dist/index.js.map +1 -1
  44. package/dist/shell/index.cjs +32 -32
  45. package/dist/shell/index.js +1 -1
  46. package/dist/viewers/index.cjs +2 -2
  47. package/dist/viewers/index.js +1 -1
  48. package/package.json +3 -3
  49. package/dist/chunk-HXITD6DN.cjs.map +0 -1
  50. package/dist/chunk-LMW46NBD.cjs.map +0 -1
  51. package/dist/chunk-M3SB5TZB.js.map +0 -1
  52. package/dist/chunk-QGOYIYLI.js.map +0 -1
  53. package/dist/chunk-RS6UUPD2.cjs.map +0 -1
  54. package/dist/chunk-ZTPJNKF2.js.map +0 -1
@@ -1,13 +1,100 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkGQAXAZN7_cjs = require('./chunk-GQAXAZN7.cjs');
4
- var chunkY7S2SQH3_cjs = require('./chunk-Y7S2SQH3.cjs');
4
+ var chunk5YGUBXXH_cjs = require('./chunk-5YGUBXXH.cjs');
5
5
  var chunkN73IMVFF_cjs = require('./chunk-N73IMVFF.cjs');
6
6
  var chunkZWFMFOGP_cjs = require('./chunk-ZWFMFOGP.cjs');
7
7
  var client = require('@arbidocs/client');
8
8
  var react = require('react');
9
9
  var reactQuery = require('@tanstack/react-query');
10
10
 
11
+ // src/chat/run-state.ts
12
+ var MIN_QUEUED_MESSAGE_VISIBILITY_MS = 800;
13
+ var mapQueues = (queues, update) => Object.fromEntries(Object.entries(queues).map(([id, messages]) => [id, update(messages)]));
14
+ function findConsumedMessages(messages, combinedContent) {
15
+ const text = combinedContent.trim();
16
+ const taken = /* @__PURE__ */ new Set();
17
+ let cursor = 0;
18
+ for (const message of messages) {
19
+ if (cursor >= text.length) break;
20
+ const content = message.content.trim();
21
+ if (!content) continue;
22
+ const separator = cursor === 0 ? "" : "\n\n";
23
+ if (text.startsWith(separator + content, cursor)) {
24
+ taken.add(message.clientId);
25
+ cursor += separator.length + content.length;
26
+ }
27
+ }
28
+ return cursor === text.length ? taken : /* @__PURE__ */ new Set();
29
+ }
30
+ var queuedMessages = {
31
+ add: (q, responseId, message) => ({
32
+ ...q,
33
+ [responseId]: [...q[responseId] ?? [], message]
34
+ }),
35
+ acknowledge: (q, clientId, serverId) => mapQueues(
36
+ q,
37
+ (messages) => messages.map((m) => m.clientId === clientId ? { ...m, serverId, acknowledged: true } : m)
38
+ ),
39
+ remove: (q, clientId) => mapQueues(q, (messages) => messages.filter((m) => m.clientId !== clientId)),
40
+ removeByServerId: (q, serverId) => mapQueues(q, (messages) => messages.filter((m) => m.serverId !== serverId)),
41
+ removeByContent: (q, responseId, content) => {
42
+ let removed = false;
43
+ return {
44
+ ...q,
45
+ [responseId]: (q[responseId] ?? []).filter((m) => {
46
+ if (!removed && m.content === content) {
47
+ removed = true;
48
+ return false;
49
+ }
50
+ return true;
51
+ })
52
+ };
53
+ },
54
+ /** Take out the prompts a steering interjection delivered into the run. */
55
+ consume: (q, responseId, combinedContent) => {
56
+ const messages = q[responseId] ?? [];
57
+ const consumed = findConsumedMessages(messages, combinedContent);
58
+ return { ...q, [responseId]: messages.filter((m) => !consumed.has(m.clientId)) };
59
+ },
60
+ clear: (q, responseId) => ({ ...q, [responseId]: [] }),
61
+ /** Move the entries still waiting on a finished turn to the turn that is now running. */
62
+ move: (q, fromResponseId, toResponseId) => {
63
+ const waiting = q[fromResponseId] ?? [];
64
+ if (fromResponseId === toResponseId || waiting.length === 0) return q;
65
+ return { ...q, [fromResponseId]: [], [toResponseId]: [...q[toResponseId] ?? [], ...waiting] };
66
+ },
67
+ /** Find a queued follow-up by its client id, under whichever turn holds it. */
68
+ find: (q, clientId) => Object.values(q).flat().find((m) => m.clientId === clientId)
69
+ };
70
+ var without = (record, key) => {
71
+ const next = { ...record };
72
+ delete next[key];
73
+ return next;
74
+ };
75
+ var agentControl = {
76
+ setState: (c, id, state) => ({
77
+ ...c,
78
+ agentControlStates: { ...c.agentControlStates, [id]: state }
79
+ }),
80
+ /** A probe answered: the latest answer, and nothing pending any more. */
81
+ setProbeAnswer: (c, id, probe) => ({
82
+ ...c,
83
+ agentProbeAnswers: { ...c.agentProbeAnswers, [id]: probe },
84
+ agentProbePending: { ...c.agentProbePending, [id]: false }
85
+ }),
86
+ setProbePending: (c, id, pending) => ({
87
+ ...c,
88
+ agentProbePending: { ...c.agentProbePending, [id]: pending }
89
+ }),
90
+ /** The turn is over: drop its control state. */
91
+ clear: (c, id) => ({
92
+ agentControlStates: without(c.agentControlStates, id),
93
+ agentProbeAnswers: without(c.agentProbeAnswers, id),
94
+ agentProbePending: without(c.agentProbePending, id)
95
+ })
96
+ };
97
+
11
98
  // src/session/thread-tabs.ts
12
99
  var threadTabId = (tab) => tab.conversationId ?? "new";
13
100
  var MAX_THREAD_TABS = 12;
@@ -86,16 +173,6 @@ function renameThreadTabIn(tabs, fromId, toId) {
86
173
  )
87
174
  };
88
175
  }
89
- function withThreadDrafts(threads, drafts) {
90
- let changed = false;
91
- const next = threads.map((tab) => {
92
- const draft = drafts[threadTabId(tab)];
93
- if (!draft || !tab.view || tab.view.draft) return tab;
94
- changed = true;
95
- return { ...tab, view: { ...tab.view, draft } };
96
- });
97
- return changed ? next : threads;
98
- }
99
176
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
100
177
  var stringOrNull = (v) => typeof v === "string" ? v : null;
101
178
  var stringOrUndefined = (v) => typeof v === "string" ? v : void 0;
@@ -103,7 +180,6 @@ function parseView(value) {
103
180
  if (!isRecord(value)) return void 0;
104
181
  return {
105
182
  cursor: stringOrNull(value.cursor),
106
- draft: "",
107
183
  editingMessageId: stringOrNull(value.editingMessageId),
108
184
  preEditDraft: null,
109
185
  preEditCursor: stringOrNull(value.preEditCursor),
@@ -128,9 +204,509 @@ function parseSavedThreadTabs(threads, activeThread) {
128
204
  activeThread: active && tabs.some((tab) => threadTabId(tab) === active) ? active : null
129
205
  };
130
206
  }
131
- var savedThreadTabs = (threads) => threads.map(
132
- (tab) => tab.view ? { ...tab, view: { ...tab.view, draft: "", preEditDraft: null } } : tab
133
- );
207
+ var savedThreadTabs = (threads) => threads.map((tab) => tab.view ? { ...tab, view: { ...tab.view, preEditDraft: null } } : tab);
208
+
209
+ // src/session/chat.ts
210
+ var EMPTY_CHAT_STATE = {
211
+ conversationId: null,
212
+ generating: {},
213
+ paMode: false,
214
+ conversationDocuments: {},
215
+ conversationDocumentAutoAdd: {},
216
+ conversationFacts: {},
217
+ cursor: null,
218
+ suggestedQuery: null,
219
+ queuedMessages: {},
220
+ agentControlStates: {},
221
+ agentProbeAnswers: {},
222
+ agentProbePending: {},
223
+ drafts: {},
224
+ editingMessageId: null,
225
+ deepLinkMessageId: null,
226
+ activeCitationKey: null,
227
+ chatModel: void 0,
228
+ chatModelName: void 0,
229
+ newConversationAssistantMode: "always",
230
+ pendingTools: null,
231
+ autoSendDraft: false,
232
+ agentChatOwners: {},
233
+ newAgentChat: null,
234
+ newChatDocumentId: null,
235
+ messageTimers: {}
236
+ };
237
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
238
+ var isString = (v) => typeof v === "string";
239
+ var stringOrNull2 = (v) => isString(v) ? v : null;
240
+ var recordOf = (value, read) => {
241
+ if (!isRecord2(value)) return {};
242
+ const out = {};
243
+ for (const [key, entry] of Object.entries(value)) {
244
+ const parsed = read(entry);
245
+ if (parsed !== null) out[key] = parsed;
246
+ }
247
+ return out;
248
+ };
249
+ var readDocuments = (value) => Array.isArray(value) ? value.filter((doc) => isRecord2(doc) && isString(doc.docId)).map((doc) => ({ docId: doc.docId, isPinned: doc.isPinned === true })) : null;
250
+ var readFacts = (value) => Array.isArray(value) ? Array.from(new Set(value.filter(isString))) : null;
251
+ function parseSavedChat(saved) {
252
+ if (!isRecord2(saved) || saved.version !== 1) return null;
253
+ return {
254
+ version: 1,
255
+ migrated: Array.isArray(saved.migrated) ? saved.migrated.filter(isString) : [],
256
+ conversationId: stringOrNull2(saved.conversationId),
257
+ cursor: stringOrNull2(saved.cursor),
258
+ conversationDocuments: recordOf(saved.conversationDocuments, readDocuments),
259
+ conversationDocumentAutoAdd: recordOf(
260
+ saved.conversationDocumentAutoAdd,
261
+ (v) => typeof v === "boolean" ? v : null
262
+ ),
263
+ conversationFacts: recordOf(saved.conversationFacts, readFacts),
264
+ agentChatOwners: recordOf(saved.agentChatOwners, (v) => isString(v) ? v : null),
265
+ agentChatOwnersUser: stringOrNull2(saved.agentChatOwnersUser),
266
+ chatModel: stringOrNull2(saved.chatModel)
267
+ };
268
+ }
269
+ function savedChatOf(state, migrated, agentChatOwnersUser = null) {
270
+ return {
271
+ version: 1,
272
+ migrated,
273
+ conversationId: state.conversationId,
274
+ cursor: state.cursor,
275
+ conversationDocuments: state.conversationDocuments,
276
+ conversationDocumentAutoAdd: { ...state.conversationDocumentAutoAdd },
277
+ conversationFacts: state.conversationFacts,
278
+ agentChatOwners: { ...state.agentChatOwners },
279
+ agentChatOwnersUser,
280
+ chatModel: state.chatModel ?? null
281
+ };
282
+ }
283
+ var SAVED_FIELDS = [
284
+ "conversationId",
285
+ "cursor",
286
+ "conversationDocuments",
287
+ "conversationDocumentAutoAdd",
288
+ "conversationFacts",
289
+ "agentChatOwners",
290
+ "chatModel"
291
+ ];
292
+ function withoutNew(record) {
293
+ const saved = { ...record };
294
+ delete saved.new;
295
+ return saved;
296
+ }
297
+ function moveKey(record, fromId, toId) {
298
+ if (!(fromId in record)) return record;
299
+ const next = { ...record, [toId]: record[fromId] };
300
+ delete next[fromId];
301
+ return next;
302
+ }
303
+ var NO_EDIT = { draft: "", cursor: null };
304
+ function createArbiChatStore({
305
+ layout,
306
+ persist,
307
+ draftStorage,
308
+ scrollTop = () => null,
309
+ user = () => draftStorage?.owner() ?? null,
310
+ initial
311
+ }) {
312
+ let state = { ...EMPTY_CHAT_STATE, ...initial };
313
+ let migrated = [];
314
+ let ownersUser = null;
315
+ let isHydrated = !persist;
316
+ const listeners = /* @__PURE__ */ new Set();
317
+ const waiting = /* @__PURE__ */ new Set();
318
+ let depth = 0;
319
+ const settle = (listener) => depth > 0 ? waiting.add(listener) : listener();
320
+ const notify = () => listeners.forEach(settle);
321
+ const batch = (change) => {
322
+ depth += 1;
323
+ try {
324
+ return change();
325
+ } finally {
326
+ depth -= 1;
327
+ if (depth === 0) {
328
+ const told = [...waiting];
329
+ waiting.clear();
330
+ told.forEach((listener) => listener());
331
+ }
332
+ }
333
+ };
334
+ const save = () => {
335
+ if (persist && isHydrated) persist.save(savedChatOf(state, migrated, ownersUser));
336
+ };
337
+ const update = (patch) => {
338
+ const next = { ...state, ...patch };
339
+ const saved = SAVED_FIELDS.some((key) => next[key] !== state[key]);
340
+ state = next;
341
+ notify();
342
+ if (saved) save();
343
+ };
344
+ let preEdit = NO_EDIT;
345
+ let draftsRestored = !draftStorage;
346
+ let restoring = false;
347
+ let draftsOwner = draftStorage?.owner() ?? null;
348
+ const setDrafts = (drafts) => {
349
+ if (drafts === state.drafts) return;
350
+ update({ drafts });
351
+ if (draftsRestored) draftStorage?.save(drafts);
352
+ };
353
+ const setDraftOf = (key, text) => {
354
+ if ((state.drafts[key] ?? "") === text) return;
355
+ const drafts = { ...state.drafts };
356
+ if (text) drafts[key] = text;
357
+ else delete drafts[key];
358
+ setDrafts(drafts);
359
+ };
360
+ const keptDrafts = (drafts) => {
361
+ const open = new Set(layout.getLayout().tabs.threads.map(threadTabId));
362
+ open.add(state.conversationId ?? "new");
363
+ const keys = Object.keys(drafts);
364
+ if (keys.every((key) => open.has(key))) return drafts;
365
+ return Object.fromEntries(keys.filter((key) => open.has(key)).map((key) => [key, drafts[key]]));
366
+ };
367
+ const restoreDrafts = () => {
368
+ if (!draftStorage) return;
369
+ const owner = draftStorage.owner();
370
+ if (owner !== draftsOwner) {
371
+ if (draftsOwner !== null) update({ drafts: {} });
372
+ draftsOwner = owner;
373
+ draftsRestored = false;
374
+ }
375
+ if (draftsRestored || restoring || owner === null) return;
376
+ restoring = true;
377
+ void Promise.all([layout.hydrated(), hydration]).then(() => draftStorage.load()).then(
378
+ (saved) => {
379
+ restoring = false;
380
+ if (!saved || draftStorage.owner() !== owner) return;
381
+ draftsRestored = true;
382
+ setDrafts(keptDrafts({ ...saved, ...state.drafts }));
383
+ draftStorage.save(state.drafts);
384
+ },
385
+ () => {
386
+ restoring = false;
387
+ }
388
+ );
389
+ };
390
+ draftStorage?.onClear(() => {
391
+ draftsRestored = false;
392
+ draftsOwner = null;
393
+ preEdit = NO_EDIT;
394
+ if (Object.keys(state.drafts).length > 0) update({ drafts: {} });
395
+ });
396
+ const composer = () => ({
397
+ conversationId: state.conversationId,
398
+ view: {
399
+ cursor: state.cursor,
400
+ editingMessageId: state.editingMessageId,
401
+ preEditDraft: state.editingMessageId ? preEdit.draft : null,
402
+ preEditCursor: state.editingMessageId ? preEdit.cursor : null,
403
+ chatModel: state.chatModel,
404
+ chatModelName: state.chatModelName,
405
+ scrollTop: scrollTop()
406
+ }
407
+ });
408
+ const show = (next) => {
409
+ if (next === null) return;
410
+ const target = next === "list" ? { conversationId: null, view: void 0 } : next;
411
+ const view = target.view;
412
+ preEdit = view ? { draft: view.preEditDraft ?? "", cursor: view.preEditCursor ?? null } : NO_EDIT;
413
+ update({
414
+ conversationId: target.conversationId,
415
+ cursor: view?.cursor ?? null,
416
+ editingMessageId: view?.editingMessageId ?? null,
417
+ chatModel: view?.chatModel,
418
+ chatModelName: view?.chatModelName
419
+ });
420
+ if (!view) setDraftOf(target.conversationId ?? "new", "");
421
+ };
422
+ const afterTabs = () => setDrafts(keptDrafts(state.drafts));
423
+ const openThreadTab = (conversationId) => batch(() => {
424
+ update(
425
+ conversationId === null ? { newAgentChat: null, newChatDocumentId: null } : { newAgentChat: null }
426
+ );
427
+ const { tabId, show: next } = layout.threads.open(conversationId, composer());
428
+ show(next);
429
+ layout.setPageTab("conversations", tabId);
430
+ afterTabs();
431
+ return tabId;
432
+ });
433
+ const hydration = persist ? persist.load().then(
434
+ (saved) => {
435
+ const parsed = parseSavedChat(saved);
436
+ if (parsed) {
437
+ migrated = parsed.migrated;
438
+ ownersUser ??= parsed.agentChatOwnersUser;
439
+ const conversationId = state.conversationId ?? parsed.conversationId;
440
+ const savedOpen = conversationId === parsed.conversationId;
441
+ state = {
442
+ ...state,
443
+ conversationId,
444
+ cursor: state.cursor ?? (savedOpen ? parsed.cursor : null),
445
+ chatModel: state.chatModel ?? (savedOpen ? parsed.chatModel ?? void 0 : void 0),
446
+ conversationDocuments: {
447
+ ...parsed.conversationDocuments,
448
+ ...state.conversationDocuments
449
+ },
450
+ conversationDocumentAutoAdd: {
451
+ ...parsed.conversationDocumentAutoAdd,
452
+ ...state.conversationDocumentAutoAdd
453
+ },
454
+ conversationFacts: { ...parsed.conversationFacts, ...state.conversationFacts },
455
+ agentChatOwners: { ...parsed.agentChatOwners, ...state.agentChatOwners }
456
+ };
457
+ }
458
+ isHydrated = true;
459
+ notify();
460
+ },
461
+ () => {
462
+ isHydrated = true;
463
+ notify();
464
+ }
465
+ ) : Promise.resolve();
466
+ void Promise.all([layout.hydrated(), hydration]).then(() => {
467
+ const { threads, activeThread } = layout.getLayout().tabs;
468
+ const tab = activeThread ? threads.find((t) => threadTabId(t) === activeThread) : null;
469
+ if (tab && state.conversationId !== tab.conversationId)
470
+ update({ conversationId: tab.conversationId });
471
+ });
472
+ const generationOf = (conversationId) => state.generating[conversationId];
473
+ const setGeneration = (conversationId, generation) => update({ generating: { ...state.generating, [conversationId]: generation } });
474
+ const stopAll = () => Object.values(state.generating).forEach((generation) => generation.abortController?.abort());
475
+ return {
476
+ getState: () => state,
477
+ subscribe: (listener) => {
478
+ listeners.add(listener);
479
+ return () => {
480
+ listeners.delete(listener);
481
+ waiting.delete(listener);
482
+ };
483
+ },
484
+ settled: (listener) => () => settle(listener),
485
+ forget: (listener) => void waiting.delete(listener),
486
+ batch,
487
+ hydrated: () => hydration,
488
+ isHydrated: () => isHydrated,
489
+ restoreDrafts,
490
+ leave: () => batch(() => {
491
+ stopAll();
492
+ preEdit = NO_EDIT;
493
+ update({
494
+ conversationId: null,
495
+ cursor: null,
496
+ editingMessageId: null,
497
+ chatModel: void 0,
498
+ chatModelName: void 0,
499
+ newConversationAssistantMode: "always",
500
+ paMode: false,
501
+ generating: {},
502
+ // Saved conversations keep their documents; the unsent new chat's belong to this workspace.
503
+ conversationDocuments: withoutNew(state.conversationDocuments),
504
+ conversationDocumentAutoAdd: withoutNew(state.conversationDocumentAutoAdd),
505
+ conversationFacts: {},
506
+ newAgentChat: null,
507
+ newChatDocumentId: null,
508
+ messageTimers: {}
509
+ });
510
+ layout.threads.clear();
511
+ setDrafts({});
512
+ }),
513
+ reset: () => batch(() => {
514
+ stopAll();
515
+ preEdit = NO_EDIT;
516
+ const signedIn = user();
517
+ const keepOwners = signedIn === null || ownersUser === null || signedIn === ownersUser;
518
+ if (signedIn !== null) ownersUser = signedIn;
519
+ update({ ...EMPTY_CHAT_STATE, agentChatOwners: keepOwners ? state.agentChatOwners : {} });
520
+ }),
521
+ setConversationId: (id) => void openThreadTab(id),
522
+ openThreadTab,
523
+ closeThreadTab: (tabId) => batch(() => {
524
+ show(layout.threads.close(tabId));
525
+ layout.setPageTab("conversations", layout.getLayout().tabs.activeThread ?? "history");
526
+ afterTabs();
527
+ }),
528
+ selectThreadTab: (tabId) => batch(() => {
529
+ if (tabId !== null) {
530
+ show(layout.threads.select(tabId, composer()));
531
+ layout.setPageTab("conversations", tabId);
532
+ return;
533
+ }
534
+ layout.threads.showList(composer());
535
+ preEdit = NO_EDIT;
536
+ update({ conversationId: null, cursor: null, editingMessageId: null });
537
+ layout.setPageTab("conversations", "history");
538
+ afterTabs();
539
+ }),
540
+ moveConversation: (fromId, toId) => batch(() => {
541
+ update({
542
+ generating: moveKey(state.generating, fromId, toId),
543
+ conversationDocuments: moveKey(state.conversationDocuments, fromId, toId),
544
+ conversationDocumentAutoAdd: moveKey(state.conversationDocumentAutoAdd, fromId, toId),
545
+ conversationFacts: moveKey(state.conversationFacts, fromId, toId),
546
+ conversationId: state.conversationId ?? toId
547
+ });
548
+ layout.threads.rename(fromId, toId);
549
+ setDrafts(moveKey(state.drafts, fromId, toId));
550
+ }),
551
+ setConversationGenerating: (conversationId, isGenerating, abortController) => {
552
+ const current = generationOf(conversationId);
553
+ setGeneration(conversationId, {
554
+ ...current,
555
+ isGenerating,
556
+ error: isGenerating ? null : current?.error ?? null,
557
+ // Starting with an explicit null means generation this client does not own (an attach to a
558
+ // run started elsewhere): it must not inherit a finished local turn's controller, or the
559
+ // view takes it for a local stream and detaches, which makes it attachable again (an
560
+ // endless loop that froze the tab after Stop). Stopping keeps the controller: the finished
561
+ // turn's bookkeeping still matches on it.
562
+ abortController: isGenerating && abortController === null ? null : abortController ?? current?.abortController ?? null,
563
+ // The run's start is set when the server names its answer (setStreamingAssistantId).
564
+ startTime: null,
565
+ streamingAssistantId: null,
566
+ ...isGenerating ? { lastFailedMessage: null, backendElapsed: null } : {}
567
+ });
568
+ },
569
+ setStreamingAssistantId: (conversationId, streamingAssistantId, startTime = Date.now()) => setGeneration(conversationId, {
570
+ ...generationOf(conversationId) ?? { isGenerating: false, error: null },
571
+ streamingAssistantId,
572
+ startTime
573
+ }),
574
+ setBackendElapsed: (conversationId, backendElapsed) => setGeneration(conversationId, {
575
+ ...generationOf(conversationId) ?? { isGenerating: false, error: null, startTime: null },
576
+ backendElapsed
577
+ }),
578
+ setConversationError: (conversationId, error, lastFailedMessage) => {
579
+ const current = generationOf(conversationId);
580
+ setGeneration(conversationId, {
581
+ ...current,
582
+ isGenerating: false,
583
+ error,
584
+ startTime: current?.startTime ?? null,
585
+ lastFailedMessage: lastFailedMessage ?? current?.lastFailedMessage ?? null
586
+ });
587
+ },
588
+ clearConversationError: (conversationId) => setGeneration(conversationId, {
589
+ ...generationOf(conversationId) ?? { isGenerating: false, startTime: null },
590
+ error: null,
591
+ lastFailedMessage: null
592
+ }),
593
+ abortConversationGeneration: (conversationId) => {
594
+ const current = generationOf(conversationId);
595
+ current?.abortController?.abort();
596
+ setGeneration(conversationId, {
597
+ ...current ?? { error: null, startTime: null },
598
+ isGenerating: false,
599
+ abortController: null
600
+ });
601
+ },
602
+ setPaMode: (paMode) => {
603
+ if (state.paMode !== paMode) update({ paMode });
604
+ },
605
+ setConversationDocuments: (conversationId, documents, autoAdd = false) => update({
606
+ conversationDocuments: { ...state.conversationDocuments, [conversationId]: documents },
607
+ conversationDocumentAutoAdd: {
608
+ ...state.conversationDocumentAutoAdd,
609
+ [conversationId]: autoAdd
610
+ }
611
+ }),
612
+ setConversationFacts: (conversationId, factIds) => update({
613
+ conversationFacts: {
614
+ ...state.conversationFacts,
615
+ [conversationId]: Array.from(new Set(factIds))
616
+ }
617
+ }),
618
+ setCursor: (cursor) => {
619
+ if (state.cursor !== cursor) update({ cursor });
620
+ },
621
+ setSuggestedQuery: (suggestedQuery) => update({ suggestedQuery }),
622
+ addQueuedMessage: (id, message) => update({ queuedMessages: queuedMessages.add(state.queuedMessages, id, message) }),
623
+ acknowledgeQueuedMessage: (clientId, serverId) => update({
624
+ queuedMessages: queuedMessages.acknowledge(state.queuedMessages, clientId, serverId)
625
+ }),
626
+ removeQueuedMessage: (clientId) => update({ queuedMessages: queuedMessages.remove(state.queuedMessages, clientId) }),
627
+ removeQueuedMessageByServerId: (serverId) => update({ queuedMessages: queuedMessages.removeByServerId(state.queuedMessages, serverId) }),
628
+ consumeQueuedMessage: (id, content) => update({ queuedMessages: queuedMessages.consume(state.queuedMessages, id, content) }),
629
+ clearQueuedMessages: (id) => update({ queuedMessages: queuedMessages.clear(state.queuedMessages, id) }),
630
+ moveQueuedMessages: (from, to) => update({ queuedMessages: queuedMessages.move(state.queuedMessages, from, to) }),
631
+ setAgentControlState: (id, control) => update(agentControl.setState(state, id, control)),
632
+ setAgentProbeAnswer: (id, probe) => update(agentControl.setProbeAnswer(state, id, probe)),
633
+ setAgentProbePending: (id, pending) => update(agentControl.setProbePending(state, id, pending)),
634
+ clearAgentControl: (id) => update(agentControl.clear(state, id)),
635
+ setDraft: (text) => setDraftOf(state.conversationId ?? "new", text),
636
+ setChatModel: (chatModel) => {
637
+ if (state.chatModel !== chatModel) update({ chatModel });
638
+ },
639
+ setChatModelName: (chatModelName) => {
640
+ if (state.chatModelName !== chatModelName) update({ chatModelName });
641
+ },
642
+ setNewConversationAssistantMode: (newConversationAssistantMode) => {
643
+ if (state.newConversationAssistantMode !== newConversationAssistantMode)
644
+ update({ newConversationAssistantMode });
645
+ },
646
+ setNewAgentChat: (newAgentChat) => {
647
+ const current = state.newAgentChat;
648
+ if (current?.agentId !== newAgentChat?.agentId || current?.workspaceId !== newAgentChat?.workspaceId)
649
+ update({ newAgentChat });
650
+ },
651
+ setNewChatDocumentId: (newChatDocumentId) => {
652
+ if (state.newChatDocumentId !== newChatDocumentId) update({ newChatDocumentId });
653
+ },
654
+ startEditing: (messageId, content) => batch(() => {
655
+ const key = state.conversationId ?? "new";
656
+ preEdit = { draft: state.drafts[key] ?? "", cursor: state.cursor };
657
+ update({ editingMessageId: messageId });
658
+ setDraftOf(key, content);
659
+ }),
660
+ cancelEditing: () => {
661
+ if (!state.editingMessageId) return;
662
+ const restore = preEdit;
663
+ preEdit = NO_EDIT;
664
+ batch(() => {
665
+ update({ editingMessageId: null, cursor: restore.cursor });
666
+ setDraftOf(state.conversationId ?? "new", restore.draft);
667
+ });
668
+ },
669
+ completeEditing: () => {
670
+ preEdit = NO_EDIT;
671
+ if (state.editingMessageId) update({ editingMessageId: null });
672
+ },
673
+ setDeepLinkMessageId: (deepLinkMessageId) => {
674
+ if (state.deepLinkMessageId !== deepLinkMessageId) update({ deepLinkMessageId });
675
+ },
676
+ setActiveCitationKey: (activeCitationKey) => {
677
+ if (state.activeCitationKey !== activeCitationKey) update({ activeCitationKey });
678
+ },
679
+ setPendingTools: (pendingTools) => update({ pendingTools }),
680
+ setAutoSendDraft: (autoSendDraft) => {
681
+ if (state.autoSendDraft !== autoSendDraft) update({ autoSendDraft });
682
+ },
683
+ setAgentChatOwner: (conversationId, agentId) => {
684
+ const signedIn = user();
685
+ ownersUser = signedIn ?? ownersUser;
686
+ update({ agentChatOwners: { ...state.agentChatOwners, [conversationId]: agentId } });
687
+ },
688
+ setMessageTimer: (key, timer) => update({ messageTimers: { ...state.messageTimers, [key]: timer } }),
689
+ clearMessageTimer: (key) => {
690
+ if (!(key in state.messageTimers)) return;
691
+ const messageTimers = { ...state.messageTimers };
692
+ delete messageTimers[key];
693
+ update({ messageTimers });
694
+ },
695
+ startNewConversation: () => batch(() => {
696
+ preEdit = NO_EDIT;
697
+ update({
698
+ conversationId: null,
699
+ cursor: null,
700
+ editingMessageId: null,
701
+ chatModel: void 0,
702
+ chatModelName: void 0,
703
+ newConversationAssistantMode: "always",
704
+ paMode: false,
705
+ newChatDocumentId: null
706
+ });
707
+ })
708
+ };
709
+ }
134
710
 
135
711
  // src/session/layout.ts
136
712
  var PANEL_MODES = ["main", "docked", "overlay", "popout"];
@@ -157,47 +733,47 @@ function defaultLayoutState() {
157
733
  grid: { states: {}, rowHeights: {}, labelWidths: {}, savedViews: {} }
158
734
  };
159
735
  }
160
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
161
- var recordOf = (value, keep) => isRecord2(value) ? Object.fromEntries(Object.entries(value).filter(([, v]) => keep(v))) : {};
162
- var isString = (v) => typeof v === "string";
736
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
737
+ var recordOf2 = (value, keep) => isRecord3(value) ? Object.fromEntries(Object.entries(value).filter(([, v]) => keep(v))) : {};
738
+ var isString2 = (v) => typeof v === "string";
163
739
  var isNumber = (v) => typeof v === "number" && Number.isFinite(v);
164
740
  var isAny = (v) => v !== void 0;
165
741
  var isMode = (v) => PANEL_MODES.includes(v);
166
- var isSize = (v) => isRecord2(v) && isNumber(v.width) && isNumber(v.height);
742
+ var isSize = (v) => isRecord3(v) && isNumber(v.width) && isNumber(v.height);
167
743
  var isList = (v) => Array.isArray(v);
168
- var stringOrNull2 = (v) => isString(v) ? v : null;
744
+ var stringOrNull3 = (v) => isString2(v) ? v : null;
169
745
  function parseSavedLayout(saved) {
170
- if (!isRecord2(saved) || saved.version !== 1) return null;
171
- const shell = isRecord2(saved.shell) ? saved.shell : {};
172
- const panels = isRecord2(shell.panels) ? shell.panels : {};
173
- const tabs = isRecord2(saved.tabs) ? saved.tabs : {};
174
- const views = isRecord2(saved.views) ? saved.views : {};
175
- const grid = isRecord2(saved.grid) ? saved.grid : {};
746
+ if (!isRecord3(saved) || saved.version !== 1) return null;
747
+ const shell = isRecord3(saved.shell) ? saved.shell : {};
748
+ const panels = isRecord3(shell.panels) ? shell.panels : {};
749
+ const tabs = isRecord3(saved.tabs) ? saved.tabs : {};
750
+ const views = isRecord3(saved.views) ? saved.views : {};
751
+ const grid = isRecord3(saved.grid) ? saved.grid : {};
176
752
  const defaults = defaultLayoutState();
177
753
  return {
178
754
  version: 1,
179
- migrated: isList(saved.migrated) ? saved.migrated.filter(isString) : [],
755
+ migrated: isList(saved.migrated) ? saved.migrated.filter(isString2) : [],
180
756
  shell: {
181
- page: isString(shell.page) ? shell.page : defaults.shell.page,
757
+ page: isString2(shell.page) ? shell.page : defaults.shell.page,
182
758
  sidebarPinned: typeof shell.sidebarPinned === "boolean" ? shell.sidebarPinned : defaults.shell.sidebar.pinned,
183
759
  panels: {
184
- main: stringOrNull2(panels.main),
185
- docked: stringOrNull2(panels.docked),
186
- modes: recordOf(panels.modes, isMode),
187
- sizes: recordOf(panels.sizes, isSize)
760
+ main: stringOrNull3(panels.main),
761
+ docked: stringOrNull3(panels.docked),
762
+ modes: recordOf2(panels.modes, isMode),
763
+ sizes: recordOf2(panels.sizes, isSize)
188
764
  }
189
765
  },
190
766
  tabs: parseSavedThreadTabs(tabs.threads, tabs.activeThread),
191
767
  views: {
192
- tabs: recordOf(views.tabs, isString),
193
- filters: recordOf(views.filters, isAny),
194
- values: recordOf(views.values, isAny)
768
+ tabs: recordOf2(views.tabs, isString2),
769
+ filters: recordOf2(views.filters, isAny),
770
+ values: recordOf2(views.values, isAny)
195
771
  },
196
772
  grid: {
197
- states: recordOf(grid.states, isRecord2),
198
- rowHeights: recordOf(grid.rowHeights, isNumber),
199
- labelWidths: recordOf(grid.labelWidths, isNumber),
200
- savedViews: recordOf(grid.savedViews, isList)
773
+ states: recordOf2(grid.states, isRecord3),
774
+ rowHeights: recordOf2(grid.rowHeights, isNumber),
775
+ labelWidths: recordOf2(grid.labelWidths, isNumber),
776
+ savedViews: recordOf2(grid.savedViews, isList)
201
777
  }
202
778
  };
203
779
  }
@@ -336,10 +912,6 @@ function createArbiLayoutStore({
336
912
  if (layout.tabs.threads.length > 0 || layout.tabs.activeThread !== null)
337
913
  tabs({ threads: [], activeThread: null });
338
914
  },
339
- restoreDrafts: (drafts) => {
340
- const threads = withThreadDrafts(layout.tabs.threads, drafts);
341
- if (threads !== layout.tabs.threads) tabs({ threads });
342
- },
343
915
  consumeScrollRestore: () => {
344
916
  const value = layout.tabs.threadScrollRestore;
345
917
  if (value !== null) tabs({ threadScrollRestore: null });
@@ -524,93 +1096,6 @@ function readWorkspaceLastOpened(lastOpenedKey = WORKSPACE_LAST_OPENED_KEY) {
524
1096
  }
525
1097
  }
526
1098
 
527
- // src/chat/run-state.ts
528
- var MIN_QUEUED_MESSAGE_VISIBILITY_MS = 800;
529
- var mapQueues = (queues, update) => Object.fromEntries(Object.entries(queues).map(([id, messages]) => [id, update(messages)]));
530
- function findConsumedMessages(messages, combinedContent) {
531
- const text = combinedContent.trim();
532
- const taken = /* @__PURE__ */ new Set();
533
- let cursor = 0;
534
- for (const message of messages) {
535
- if (cursor >= text.length) break;
536
- const content = message.content.trim();
537
- if (!content) continue;
538
- const separator = cursor === 0 ? "" : "\n\n";
539
- if (text.startsWith(separator + content, cursor)) {
540
- taken.add(message.clientId);
541
- cursor += separator.length + content.length;
542
- }
543
- }
544
- return cursor === text.length ? taken : /* @__PURE__ */ new Set();
545
- }
546
- var queuedMessages = {
547
- add: (q, responseId, message) => ({
548
- ...q,
549
- [responseId]: [...q[responseId] ?? [], message]
550
- }),
551
- acknowledge: (q, clientId, serverId) => mapQueues(
552
- q,
553
- (messages) => messages.map((m) => m.clientId === clientId ? { ...m, serverId, acknowledged: true } : m)
554
- ),
555
- remove: (q, clientId) => mapQueues(q, (messages) => messages.filter((m) => m.clientId !== clientId)),
556
- removeByServerId: (q, serverId) => mapQueues(q, (messages) => messages.filter((m) => m.serverId !== serverId)),
557
- removeByContent: (q, responseId, content) => {
558
- let removed = false;
559
- return {
560
- ...q,
561
- [responseId]: (q[responseId] ?? []).filter((m) => {
562
- if (!removed && m.content === content) {
563
- removed = true;
564
- return false;
565
- }
566
- return true;
567
- })
568
- };
569
- },
570
- /** Take out the prompts a steering interjection delivered into the run. */
571
- consume: (q, responseId, combinedContent) => {
572
- const messages = q[responseId] ?? [];
573
- const consumed = findConsumedMessages(messages, combinedContent);
574
- return { ...q, [responseId]: messages.filter((m) => !consumed.has(m.clientId)) };
575
- },
576
- clear: (q, responseId) => ({ ...q, [responseId]: [] }),
577
- /** Move the entries still waiting on a finished turn to the turn that is now running. */
578
- move: (q, fromResponseId, toResponseId) => {
579
- const waiting = q[fromResponseId] ?? [];
580
- if (fromResponseId === toResponseId || waiting.length === 0) return q;
581
- return { ...q, [fromResponseId]: [], [toResponseId]: [...q[toResponseId] ?? [], ...waiting] };
582
- },
583
- /** Find a queued follow-up by its client id, under whichever turn holds it. */
584
- find: (q, clientId) => Object.values(q).flat().find((m) => m.clientId === clientId)
585
- };
586
- var without = (record, key) => {
587
- const next = { ...record };
588
- delete next[key];
589
- return next;
590
- };
591
- var agentControl = {
592
- setState: (c, id, state) => ({
593
- ...c,
594
- agentControlStates: { ...c.agentControlStates, [id]: state }
595
- }),
596
- /** A probe answered: the latest answer, and nothing pending any more. */
597
- setProbeAnswer: (c, id, probe) => ({
598
- ...c,
599
- agentProbeAnswers: { ...c.agentProbeAnswers, [id]: probe },
600
- agentProbePending: { ...c.agentProbePending, [id]: false }
601
- }),
602
- setProbePending: (c, id, pending) => ({
603
- ...c,
604
- agentProbePending: { ...c.agentProbePending, [id]: pending }
605
- }),
606
- /** The turn is over: drop its control state. */
607
- clear: (c, id) => ({
608
- agentControlStates: without(c.agentControlStates, id),
609
- agentProbeAnswers: without(c.agentProbeAnswers, id),
610
- agentProbePending: without(c.agentProbePending, id)
611
- })
612
- };
613
-
614
1099
  // src/session/store.ts
615
1100
  var DEFAULT_DOCUMENT_VIEWER_STATE = {
616
1101
  tab: "pdf",
@@ -619,202 +1104,45 @@ var DEFAULT_DOCUMENT_VIEWER_STATE = {
619
1104
  textScale: 1,
620
1105
  phonePdfChosen: false
621
1106
  };
622
- var EMPTY_SESSION_STATE = {
623
- workspaceId: null,
624
- workspaceStatus: "closed",
625
- conversationId: null,
1107
+ var EMPTY_DOCUMENT_STATE = {
626
1108
  viewingDocument: null,
627
1109
  documentViewer: DEFAULT_DOCUMENT_VIEWER_STATE,
628
1110
  selectedDocumentIds: [],
629
- generating: {},
630
- paMode: false,
631
- conversationDocuments: {},
632
- conversationDocumentAutoAdd: {},
633
- conversationFacts: {},
634
- pinnedDocumentId: null,
635
- cursor: null,
636
- suggestedQuery: null,
637
- queuedMessages: {},
638
- agentControlStates: {},
639
- agentProbeAnswers: {},
640
- agentProbePending: {},
641
- drafts: {},
642
- editingMessageId: null,
643
- deepLinkMessageId: null,
644
- activeCitationKey: null,
645
- chatModel: void 0,
646
- chatModelName: void 0,
647
- newConversationAssistantMode: "always",
648
- pendingTools: null,
649
- autoSendDraft: false,
650
- agentChatOwners: {},
651
- newAgentChat: null,
652
- newChatDocumentId: null,
653
- messageTimers: {},
1111
+ pinnedDocumentId: null
1112
+ };
1113
+ var EMPTY_SESSION_STATE = {
1114
+ workspaceId: null,
1115
+ workspaceStatus: "closed",
1116
+ ...EMPTY_CHAT_STATE,
1117
+ ...EMPTY_DOCUMENT_STATE,
654
1118
  ...defaultLayoutState()
655
1119
  };
656
1120
  var selectViewingDocumentId = (state) => state.viewingDocument ? chunkZWFMFOGP_cjs.parseVersionRef(state.viewingDocument.id).docId : null;
657
- var conversationKey = (state) => state.conversationId ?? "new";
658
- var selectDraft = (state) => state.drafts[conversationKey(state)] ?? "";
659
- var selectIsGenerating = (conversationId) => (state) => !!conversationId && !!state.generating[conversationId]?.isGenerating;
660
- function nextViewingDocument(current, input) {
661
- if (!input) return null;
662
- const same = current?.id === input.id;
663
- return {
664
- id: input.id,
665
- page: input.page !== void 0 ? input.page : same ? current?.page ?? null : null,
666
- passageId: input.passageId !== void 0 ? input.passageId : current?.passageId ?? null
667
- };
668
- }
669
- function layoutActionsOf(layout) {
670
- const actions = { ...layout };
671
- delete actions.getLayout;
672
- delete actions.subscribe;
673
- delete actions.hydrated;
674
- delete actions.isHydrated;
675
- delete actions.reset;
676
- delete actions.threads;
677
- return actions;
678
- }
679
- function withoutNew(record) {
680
- const { new: _new, ...saved } = record;
681
- return saved;
682
- }
683
- function createArbiSessionStore(initial = {}, {
684
- draftStorage,
685
- persist,
686
- workspace = createArbiWorkspaceStore({ workspaceId: initial.workspaceId ?? null })
687
- } = {}) {
688
- const { shell, tabs, views, grid, ...rest } = initial;
689
- const layout = createArbiLayoutStore({
690
- persist,
691
- initial: Object.fromEntries(
692
- Object.entries({ shell, tabs, views, grid }).filter(([, part]) => part !== void 0)
693
- )
694
- });
695
- if (initial.workspaceStatus) workspace.setWorkspaceStatus(initial.workspaceStatus);
696
- let state = {
697
- ...EMPTY_SESSION_STATE,
698
- ...rest,
699
- ...layout.getLayout(),
700
- ...workspace.getState()
1121
+ var conversationKey = (state) => state.conversationId ?? "new";
1122
+ var selectDraft = (state) => state.drafts[conversationKey(state)] ?? "";
1123
+ var selectIsGenerating = (conversationId) => (state) => !!conversationId && !!state.generating[conversationId]?.isGenerating;
1124
+ function nextViewingDocument(current, input) {
1125
+ if (!input) return null;
1126
+ const same = current?.id === input.id;
1127
+ return {
1128
+ id: input.id,
1129
+ page: input.page !== void 0 ? input.page : same ? current?.page ?? null : null,
1130
+ passageId: input.passageId !== void 0 ? input.passageId : current?.passageId ?? null
701
1131
  };
1132
+ }
1133
+ function createArbiDocumentSessionStore(initial = {}) {
1134
+ let state = { ...EMPTY_DOCUMENT_STATE, ...initial };
702
1135
  const listeners = /* @__PURE__ */ new Set();
703
1136
  const update = (patch) => {
704
1137
  state = { ...state, ...patch };
705
1138
  listeners.forEach((listener) => listener());
706
1139
  };
707
- layout.subscribe(() => update(layout.getLayout()));
708
- workspace.subscribe(() => update(workspace.getState()));
709
- let preEdit = { draft: "", cursor: null };
710
- let draftsRestored = !draftStorage;
711
- let draftsOwner = draftStorage?.owner() ?? null;
712
- const restoreDrafts = () => {
713
- if (!draftStorage) return;
714
- const owner = draftStorage.owner();
715
- if (owner !== draftsOwner) {
716
- if (draftsOwner !== null) update({ drafts: {} });
717
- draftsOwner = owner;
718
- draftsRestored = false;
719
- }
720
- if (draftsRestored) return;
721
- draftsRestored = true;
722
- void draftStorage.load().then(
723
- (saved) => {
724
- if (saved && draftStorage.owner() === owner)
725
- update({ drafts: { ...saved, ...state.drafts } });
726
- else draftsRestored = false;
727
- },
728
- () => {
729
- draftsRestored = false;
730
- }
731
- );
732
- };
733
- draftStorage?.onClear(() => {
734
- draftsRestored = false;
735
- draftsOwner = null;
736
- preEdit = { draft: "", cursor: null };
737
- if (Object.keys(state.drafts).length > 0) update({ drafts: {} });
738
- });
739
- restoreDrafts();
740
- const setDrafts = (drafts) => {
741
- update({ drafts });
742
- draftStorage?.save(drafts);
743
- };
744
- const setDraftOf = (key, text) => {
745
- if ((state.drafts[key] ?? "") === text) return;
746
- const drafts = { ...state.drafts };
747
- if (text) drafts[key] = text;
748
- else delete drafts[key];
749
- setDrafts(drafts);
750
- };
751
- const composer = () => ({
752
- conversationId: state.conversationId,
753
- view: {
754
- cursor: state.cursor,
755
- draft: selectDraft(state),
756
- editingMessageId: state.editingMessageId,
757
- preEditDraft: state.editingMessageId ? preEdit.draft : null,
758
- preEditCursor: state.editingMessageId ? preEdit.cursor : null,
759
- chatModel: state.chatModel,
760
- chatModelName: state.chatModelName,
761
- scrollTop: null
762
- }
763
- });
764
- const show = (next) => {
765
- if (next === null) return;
766
- if (next === "list") {
767
- preEdit = { draft: "", cursor: null };
768
- return update({ conversationId: null, cursor: null, editingMessageId: null });
769
- }
770
- const view = next.view;
771
- preEdit = { draft: view?.preEditDraft ?? "", cursor: view?.preEditCursor ?? null };
772
- update({
773
- conversationId: next.conversationId,
774
- cursor: view?.cursor ?? null,
775
- editingMessageId: view?.editingMessageId ?? null,
776
- chatModel: view?.chatModel,
777
- chatModelName: view?.chatModelName
778
- });
779
- };
780
1140
  return {
781
- ...layoutActionsOf(layout),
782
- layoutHydrated: () => layout.hydrated(),
783
- isLayoutHydrated: () => layout.isHydrated(),
784
1141
  getState: () => state,
785
1142
  subscribe: (listener) => {
786
1143
  listeners.add(listener);
787
1144
  return () => listeners.delete(listener);
788
1145
  },
789
- setWorkspaceId: (workspaceId) => {
790
- workspace.setWorkspaceId(workspaceId);
791
- restoreDrafts();
792
- },
793
- setWorkspaceStatus: (workspaceStatus) => workspace.setWorkspaceStatus(workspaceStatus),
794
- leaveWorkspace: () => {
795
- Object.values(state.generating).forEach((generation) => generation.abortController?.abort());
796
- workspace.setWorkspaceStatus("closed");
797
- update({
798
- conversationId: null,
799
- cursor: null,
800
- viewingDocument: null,
801
- selectedDocumentIds: [],
802
- generating: {},
803
- // Saved conversations keep their documents; the unsent new chat's belong to this workspace.
804
- conversationDocuments: withoutNew(state.conversationDocuments),
805
- conversationDocumentAutoAdd: withoutNew(state.conversationDocumentAutoAdd),
806
- conversationFacts: {},
807
- pinnedDocumentId: null,
808
- newAgentChat: null,
809
- newChatDocumentId: null,
810
- messageTimers: {}
811
- });
812
- layout.threads.clear();
813
- },
814
- setConversationId: (conversationId) => {
815
- if (state.conversationId !== conversationId)
816
- update({ conversationId, cursor: null, editingMessageId: null });
817
- },
818
1146
  setViewingDocument: (input) => update({ viewingDocument: nextViewingDocument(state.viewingDocument, input) }),
819
1147
  setDocumentViewer: (change) => {
820
1148
  const next = { ...state.documentViewer, ...change };
@@ -823,209 +1151,117 @@ function createArbiSessionStore(initial = {}, {
823
1151
  update({ documentViewer: next });
824
1152
  },
825
1153
  setSelectedDocumentIds: (ids) => update({ selectedDocumentIds: ids }),
826
- setConversationGenerating: (conversationId, isGenerating, abortController = null) => {
827
- const current = state.generating[conversationId];
828
- update({
829
- generating: {
830
- ...state.generating,
831
- [conversationId]: {
832
- ...current,
833
- isGenerating,
834
- error: isGenerating ? null : current?.error ?? null,
835
- startTime: isGenerating ? Date.now() : null,
836
- streamingAssistantId: isGenerating ? current?.streamingAssistantId ?? null : null,
837
- backendElapsed: isGenerating ? current?.backendElapsed ?? null : null,
838
- abortController
839
- }
840
- }
841
- });
842
- },
843
- setStreamingAssistantId: (conversationId, streamingAssistantId, startTime = Date.now()) => {
844
- const current = state.generating[conversationId];
845
- update({
846
- generating: {
847
- ...state.generating,
848
- [conversationId]: {
849
- ...current ?? { isGenerating: false, error: null },
850
- streamingAssistantId,
851
- startTime
852
- }
853
- }
854
- });
855
- },
856
- setBackendElapsed: (conversationId, backendElapsed) => {
857
- const current = state.generating[conversationId] ?? {
858
- isGenerating: false,
859
- error: null,
860
- startTime: null
861
- };
862
- update({
863
- generating: { ...state.generating, [conversationId]: { ...current, backendElapsed } }
864
- });
865
- },
866
- moveConversation: (fromId, toId) => {
867
- const move = (record) => {
868
- const next = { ...record };
869
- if (fromId in next) {
870
- next[toId] = next[fromId];
871
- delete next[fromId];
872
- }
873
- return next;
874
- };
875
- update({
876
- generating: move(state.generating),
877
- conversationDocuments: move(state.conversationDocuments),
878
- conversationDocumentAutoAdd: move(state.conversationDocumentAutoAdd),
879
- conversationFacts: move(state.conversationFacts),
880
- conversationId: state.conversationId ?? toId
881
- });
882
- layout.threads.rename(fromId, toId);
883
- if (fromId in state.drafts) setDrafts(move(state.drafts));
884
- },
885
- setConversationFacts: (conversationId, factIds) => update({ conversationFacts: { ...state.conversationFacts, [conversationId]: factIds } }),
886
1154
  setPinnedDocumentId: (pinnedDocumentId) => update({ pinnedDocumentId }),
887
- setCursor: (cursor) => {
888
- if (state.cursor !== cursor) update({ cursor });
889
- },
890
- setSuggestedQuery: (suggestedQuery) => update({ suggestedQuery }),
891
- addQueuedMessage: (id, message) => update({ queuedMessages: queuedMessages.add(state.queuedMessages, id, message) }),
892
- acknowledgeQueuedMessage: (clientId, serverId) => update({
893
- queuedMessages: queuedMessages.acknowledge(state.queuedMessages, clientId, serverId)
894
- }),
895
- removeQueuedMessage: (clientId) => update({ queuedMessages: queuedMessages.remove(state.queuedMessages, clientId) }),
896
- removeQueuedMessageByServerId: (serverId) => update({ queuedMessages: queuedMessages.removeByServerId(state.queuedMessages, serverId) }),
897
- consumeQueuedMessage: (id, content) => update({ queuedMessages: queuedMessages.consume(state.queuedMessages, id, content) }),
898
- clearQueuedMessages: (id) => update({ queuedMessages: queuedMessages.clear(state.queuedMessages, id) }),
899
- moveQueuedMessages: (from, to) => update({ queuedMessages: queuedMessages.move(state.queuedMessages, from, to) }),
900
- setAgentControlState: (id, control) => update(agentControl.setState(state, id, control)),
901
- setAgentProbeAnswer: (id, probe) => update(agentControl.setProbeAnswer(state, id, probe)),
902
- setAgentProbePending: (id, pending) => update(agentControl.setProbePending(state, id, pending)),
903
- clearAgentControl: (id) => update(agentControl.clear(state, id)),
904
- setDraft: (text) => setDraftOf(conversationKey(state), text),
905
- setChatModel: (chatModel) => {
906
- if (state.chatModel !== chatModel) update({ chatModel });
907
- },
908
- openThreadTab: (conversationId) => {
909
- if (conversationId === null) update({ newAgentChat: null, newChatDocumentId: null });
910
- else if (state.newAgentChat) update({ newAgentChat: null });
911
- const { tabId, show: next } = layout.threads.open(conversationId, composer());
912
- show(next);
913
- return tabId;
914
- },
915
- closeThreadTab: (tabId) => show(layout.threads.close(tabId)),
916
- selectThreadTab: (tabId) => {
917
- if (tabId !== null) return show(layout.threads.select(tabId, composer()));
918
- layout.threads.showList(composer());
919
- show("list");
920
- },
921
- setChatModelName: (chatModelName) => {
922
- if (state.chatModelName !== chatModelName) update({ chatModelName });
923
- },
924
- setNewConversationAssistantMode: (newConversationAssistantMode) => {
925
- if (state.newConversationAssistantMode !== newConversationAssistantMode)
926
- update({ newConversationAssistantMode });
927
- },
928
- setNewAgentChat: (newAgentChat) => {
929
- const current = state.newAgentChat;
930
- if (current?.agentId !== newAgentChat?.agentId || current?.workspaceId !== newAgentChat?.workspaceId)
931
- update({ newAgentChat });
932
- },
933
- setNewChatDocumentId: (newChatDocumentId) => {
934
- if (state.newChatDocumentId !== newChatDocumentId) update({ newChatDocumentId });
935
- },
936
- startEditing: (messageId, content) => {
937
- preEdit = { draft: selectDraft(state), cursor: state.cursor };
938
- update({ editingMessageId: messageId });
939
- setDraftOf(conversationKey(state), content);
940
- },
941
- cancelEditing: () => {
942
- if (!state.editingMessageId) return;
943
- update({ editingMessageId: null, cursor: preEdit.cursor });
944
- setDraftOf(conversationKey(state), preEdit.draft);
945
- preEdit = { draft: "", cursor: null };
946
- },
947
- completeEditing: () => {
948
- preEdit = { draft: "", cursor: null };
949
- if (state.editingMessageId) update({ editingMessageId: null });
950
- },
951
- setDeepLinkMessageId: (deepLinkMessageId) => {
952
- if (state.deepLinkMessageId !== deepLinkMessageId) update({ deepLinkMessageId });
953
- },
954
- setActiveCitationKey: (activeCitationKey) => {
955
- if (state.activeCitationKey !== activeCitationKey) update({ activeCitationKey });
956
- },
957
- setPendingTools: (pendingTools) => update({ pendingTools }),
958
- setAutoSendDraft: (autoSendDraft) => {
959
- if (state.autoSendDraft !== autoSendDraft) update({ autoSendDraft });
960
- },
961
- setAgentChatOwner: (conversationId, agentId) => update({ agentChatOwners: { ...state.agentChatOwners, [conversationId]: agentId } }),
962
- setMessageTimer: (key, timer) => update({ messageTimers: { ...state.messageTimers, [key]: timer } }),
963
- clearMessageTimer: (key) => {
964
- if (!(key in state.messageTimers)) return;
965
- const messageTimers = { ...state.messageTimers };
966
- delete messageTimers[key];
967
- update({ messageTimers });
968
- },
969
- setConversationError: (conversationId, error, lastFailedMessage) => {
970
- const current = state.generating[conversationId];
971
- update({
972
- generating: {
973
- ...state.generating,
974
- [conversationId]: {
975
- ...current,
976
- isGenerating: false,
977
- error,
978
- startTime: current?.startTime ?? null,
979
- lastFailedMessage: lastFailedMessage ?? current?.lastFailedMessage ?? null
980
- }
981
- }
982
- });
983
- },
984
- clearConversationError: (conversationId) => {
985
- const current = state.generating[conversationId];
986
- update({
987
- generating: {
988
- ...state.generating,
989
- [conversationId]: {
990
- ...current ?? { isGenerating: false, startTime: null },
991
- error: null,
992
- lastFailedMessage: null
993
- }
994
- }
995
- });
996
- },
997
- abortConversationGeneration: (conversationId) => {
998
- const current = state.generating[conversationId];
999
- current?.abortController?.abort();
1000
- update({
1001
- generating: {
1002
- ...state.generating,
1003
- [conversationId]: {
1004
- ...current ?? { error: null, startTime: null },
1005
- isGenerating: false,
1006
- abortController: null
1007
- }
1008
- }
1009
- });
1155
+ leave: () => update({ viewingDocument: null, selectedDocumentIds: [], pinnedDocumentId: null })
1156
+ };
1157
+ }
1158
+ function layoutActionsOf(layout) {
1159
+ const actions = { ...layout };
1160
+ delete actions.getLayout;
1161
+ delete actions.subscribe;
1162
+ delete actions.hydrated;
1163
+ delete actions.isHydrated;
1164
+ delete actions.reset;
1165
+ delete actions.threads;
1166
+ return actions;
1167
+ }
1168
+ function chatActionsOf(chat) {
1169
+ const actions = { ...chat };
1170
+ delete actions.getState;
1171
+ delete actions.subscribe;
1172
+ delete actions.settled;
1173
+ delete actions.forget;
1174
+ delete actions.batch;
1175
+ delete actions.hydrated;
1176
+ delete actions.isHydrated;
1177
+ delete actions.restoreDrafts;
1178
+ delete actions.leave;
1179
+ delete actions.reset;
1180
+ return actions;
1181
+ }
1182
+ function composeArbiSessionStore({
1183
+ layout,
1184
+ workspace,
1185
+ chat,
1186
+ documents
1187
+ }) {
1188
+ let last = null;
1189
+ const getState = () => {
1190
+ const parts = [
1191
+ layout.getLayout(),
1192
+ workspace.getState(),
1193
+ documents.getState(),
1194
+ chat.getState()
1195
+ ];
1196
+ if (last && parts.every((part, i) => part === last.parts[i])) return last.state;
1197
+ const [l, w, d, c] = parts;
1198
+ last = { parts, state: { ...l, ...w, ...d, ...c } };
1199
+ return last.state;
1200
+ };
1201
+ chat.restoreDrafts();
1202
+ workspace.subscribe(() => chat.restoreDrafts());
1203
+ return {
1204
+ ...layoutActionsOf(layout),
1205
+ ...chatActionsOf(chat),
1206
+ getState,
1207
+ layoutHydrated: () => layout.hydrated(),
1208
+ isLayoutHydrated: () => layout.isHydrated(),
1209
+ subscribe: (onChange) => {
1210
+ const told = chat.settled(onChange);
1211
+ const unsubscribe = [
1212
+ chat.subscribe(onChange),
1213
+ layout.subscribe(told),
1214
+ workspace.subscribe(told),
1215
+ documents.subscribe(told)
1216
+ ];
1217
+ return () => {
1218
+ chat.forget(onChange);
1219
+ unsubscribe.forEach((stop) => stop());
1220
+ };
1010
1221
  },
1011
- startNewConversation: () => update({
1012
- conversationId: null,
1013
- cursor: null,
1014
- editingMessageId: null,
1015
- newChatDocumentId: null
1222
+ setWorkspaceId: (id) => workspace.setWorkspaceId(id),
1223
+ setWorkspaceStatus: (status) => workspace.setWorkspaceStatus(status),
1224
+ leaveWorkspace: () => chat.batch(() => {
1225
+ workspace.setWorkspaceStatus("closed");
1226
+ chat.leave();
1227
+ documents.leave();
1016
1228
  }),
1017
- setPaMode: (paMode) => {
1018
- if (state.paMode !== paMode) update({ paMode });
1019
- },
1020
- setConversationDocuments: (conversationId, documents, autoAdd = false) => update({
1021
- conversationDocuments: { ...state.conversationDocuments, [conversationId]: documents },
1022
- conversationDocumentAutoAdd: {
1023
- ...state.conversationDocumentAutoAdd,
1024
- [conversationId]: autoAdd
1025
- }
1026
- })
1229
+ setViewingDocument: (input) => documents.setViewingDocument(input),
1230
+ setDocumentViewer: (change) => documents.setDocumentViewer(change),
1231
+ setSelectedDocumentIds: (ids) => documents.setSelectedDocumentIds(ids),
1232
+ setPinnedDocumentId: (id) => documents.setPinnedDocumentId(id)
1027
1233
  };
1028
1234
  }
1235
+ function createArbiSessionStore(initial = {}, {
1236
+ draftStorage,
1237
+ persist,
1238
+ workspace = createArbiWorkspaceStore({ workspaceId: initial.workspaceId ?? null })
1239
+ } = {}) {
1240
+ const {
1241
+ shell,
1242
+ tabs,
1243
+ views,
1244
+ grid,
1245
+ workspaceStatus,
1246
+ viewingDocument,
1247
+ documentViewer,
1248
+ selectedDocumentIds,
1249
+ pinnedDocumentId,
1250
+ ...chatInitial
1251
+ } = initial;
1252
+ delete chatInitial.workspaceId;
1253
+ const defined = (parts) => Object.fromEntries(Object.entries(parts).filter(([, part]) => part !== void 0));
1254
+ const layout = createArbiLayoutStore({ persist, initial: defined({ shell, tabs, views, grid }) });
1255
+ if (workspaceStatus) workspace.setWorkspaceStatus(workspaceStatus);
1256
+ return composeArbiSessionStore({
1257
+ layout,
1258
+ workspace,
1259
+ chat: createArbiChatStore({ layout, draftStorage, initial: chatInitial }),
1260
+ documents: createArbiDocumentSessionStore(
1261
+ defined({ viewingDocument, documentViewer, selectedDocumentIds, pinnedDocumentId })
1262
+ )
1263
+ });
1264
+ }
1029
1265
  var SAVE_DELAY_MS = 500;
1030
1266
  var encoder = new TextEncoder();
1031
1267
  var decoder = new TextDecoder();
@@ -1134,7 +1370,7 @@ var createOwnStore = (host) => createArbiSessionStore(
1134
1370
  var moduleDefault = null;
1135
1371
  var defaultStore = () => moduleDefault ??= createArbiSessionStore();
1136
1372
  function useArbiSessionStore() {
1137
- const host = chunkY7S2SQH3_cjs.useArbiHost();
1373
+ const host = chunk5YGUBXXH_cjs.useArbiHost();
1138
1374
  if (host.session) return host.session;
1139
1375
  const own = host[chunkN73IMVFF_cjs.OWN_SESSION_SLOT];
1140
1376
  if (own) return own.current ??= createOwnStore(host);
@@ -1173,7 +1409,7 @@ var SIGNED_OUT = {
1173
1409
  var noSubscription = () => () => {
1174
1410
  };
1175
1411
  function useArbiSession() {
1176
- return useSignedInSession(chunkY7S2SQH3_cjs.useArbiHost().arbi?.session ?? null);
1412
+ return useSignedInSession(chunk5YGUBXXH_cjs.useArbiHost().arbi?.session ?? null);
1177
1413
  }
1178
1414
  function useSignedInSession(session) {
1179
1415
  const state = react.useSyncExternalStore(
@@ -1295,13 +1531,87 @@ function createStoragePersist({
1295
1531
  };
1296
1532
  }
1297
1533
 
1534
+ // src/session/ui-state-storage.ts
1535
+ function createUiStateStorage(options = {}) {
1536
+ const debounceMs = options.debounceMs ?? 250;
1537
+ const maxWaitMs = options.maxWaitMs ?? 1e3;
1538
+ const backing = options.backing ?? (() => {
1539
+ try {
1540
+ return typeof localStorage === "undefined" ? void 0 : localStorage;
1541
+ } catch {
1542
+ return void 0;
1543
+ }
1544
+ });
1545
+ const pending = /* @__PURE__ */ new Map();
1546
+ let timer = null;
1547
+ let firstQueuedAt = null;
1548
+ const write = (name, value) => {
1549
+ try {
1550
+ backing()?.setItem(name, JSON.stringify(value));
1551
+ } catch (error) {
1552
+ console.warn("[ui-state] Could not save UI state; keeping it in memory", error);
1553
+ }
1554
+ };
1555
+ const flush = () => {
1556
+ if (timer) clearTimeout(timer);
1557
+ timer = null;
1558
+ firstQueuedAt = null;
1559
+ const due = Array.from(pending.entries());
1560
+ pending.clear();
1561
+ for (const [name, value] of due) write(name, value);
1562
+ };
1563
+ return {
1564
+ getItem: (name) => {
1565
+ const unsaved = pending.get(name);
1566
+ if (unsaved) return unsaved;
1567
+ let raw;
1568
+ try {
1569
+ raw = backing()?.getItem(name);
1570
+ return raw ? JSON.parse(raw) : null;
1571
+ } catch (error) {
1572
+ console.warn("[ui-state] Saved UI state is unreadable; starting from defaults", error);
1573
+ if (raw !== void 0) {
1574
+ try {
1575
+ backing()?.removeItem(name);
1576
+ } catch {
1577
+ }
1578
+ }
1579
+ return null;
1580
+ }
1581
+ },
1582
+ setItem: (name, value) => {
1583
+ pending.set(name, value);
1584
+ if (timer) clearTimeout(timer);
1585
+ firstQueuedAt ??= Date.now();
1586
+ timer = setTimeout(
1587
+ flush,
1588
+ Math.max(0, Math.min(debounceMs, firstQueuedAt + maxWaitMs - Date.now()))
1589
+ );
1590
+ },
1591
+ removeItem: (name) => {
1592
+ pending.delete(name);
1593
+ if (pending.size === 0) {
1594
+ if (timer) clearTimeout(timer);
1595
+ timer = null;
1596
+ firstQueuedAt = null;
1597
+ }
1598
+ try {
1599
+ backing()?.removeItem(name);
1600
+ } catch (error) {
1601
+ console.warn("[ui-state] Could not remove saved UI state", error);
1602
+ }
1603
+ },
1604
+ flush
1605
+ };
1606
+ }
1607
+
1298
1608
  // src/usage-metered.ts
1299
1609
  function isUsageMetered(usage, subscription) {
1300
1610
  const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0;
1301
1611
  return !(empty && subscription === "dev");
1302
1612
  }
1303
1613
  function useWorkspaces(options) {
1304
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1614
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1305
1615
  return reactQuery.useQuery({
1306
1616
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.workspaces(),
1307
1617
  queryFn: () => arbi.workspaces.list(),
@@ -1309,7 +1619,7 @@ function useWorkspaces(options) {
1309
1619
  });
1310
1620
  }
1311
1621
  function useDocumentVersionList(docId, options) {
1312
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1622
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1313
1623
  return reactQuery.useQuery({
1314
1624
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.documentVersions(docId ?? ""),
1315
1625
  queryFn: () => arbi.documents.versions(docId),
@@ -1317,7 +1627,7 @@ function useDocumentVersionList(docId, options) {
1317
1627
  });
1318
1628
  }
1319
1629
  function useConversations(workspaceId, options) {
1320
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1630
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1321
1631
  const live = options?.live === true;
1322
1632
  return reactQuery.useQuery({
1323
1633
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.conversations(workspaceId ?? ""),
@@ -1330,7 +1640,7 @@ function useConversations(workspaceId, options) {
1330
1640
  });
1331
1641
  }
1332
1642
  function useBuiltinCommands() {
1333
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1643
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1334
1644
  const query = reactQuery.useQuery({
1335
1645
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.assistantCommands(),
1336
1646
  queryFn: () => arbi.assistant.commands(),
@@ -1341,7 +1651,7 @@ function useBuiltinCommands() {
1341
1651
  return { commands, isLoading: query.isLoading };
1342
1652
  }
1343
1653
  function useMessageDetails(messageId, options) {
1344
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1654
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1345
1655
  return reactQuery.useQuery({
1346
1656
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.messageDetails(messageId ?? ""),
1347
1657
  queryFn: () => arbi.conversations.getMessage(messageId),
@@ -1349,7 +1659,7 @@ function useMessageDetails(messageId, options) {
1349
1659
  });
1350
1660
  }
1351
1661
  function useConversationThreads(conversationId, options) {
1352
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1662
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1353
1663
  const session = useArbiSessionStore();
1354
1664
  return reactQuery.useQuery({
1355
1665
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.conversationThreads(conversationId ?? ""),
@@ -1368,7 +1678,7 @@ var tagListKey = (query) => [
1368
1678
  query.linksLimit !== void 0 ? `links:${query.linksLimit}` : ""
1369
1679
  ].filter(Boolean).join("|");
1370
1680
  function useTags(workspaceId, options) {
1371
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1681
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1372
1682
  const { enabled, ...query } = options ?? {};
1373
1683
  const workspace = workspaceId ?? (arbi.hasWorkspace ? arbi.getWorkspaceId() : "");
1374
1684
  const key = tagListKey(query);
@@ -1386,7 +1696,7 @@ function useTags(workspaceId, options) {
1386
1696
  });
1387
1697
  }
1388
1698
  function useThumbnails(docIds, options) {
1389
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1699
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1390
1700
  return reactQuery.useQuery({
1391
1701
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.thumbnails(docIds),
1392
1702
  queryFn: () => arbi.documents.getThumbnails(docIds),
@@ -1395,7 +1705,7 @@ function useThumbnails(docIds, options) {
1395
1705
  });
1396
1706
  }
1397
1707
  function useParsedDocument(docId, stage = "final", options) {
1398
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1708
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1399
1709
  return reactQuery.useQuery({
1400
1710
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.parsedDoc(docId ?? "", stage),
1401
1711
  queryFn: () => {
@@ -1410,13 +1720,13 @@ function useParsedDocument(docId, stage = "final", options) {
1410
1720
  });
1411
1721
  }
1412
1722
  function useAssistantQuery() {
1413
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1723
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1414
1724
  return reactQuery.useMutation({
1415
1725
  mutationFn: ({ request, handlers }) => arbi.assistant.ask(request, handlers)
1416
1726
  });
1417
1727
  }
1418
1728
  function useAgents(options) {
1419
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1729
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1420
1730
  return reactQuery.useQuery({
1421
1731
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.agents(),
1422
1732
  queryFn: () => arbi.agents.list(),
@@ -1424,7 +1734,7 @@ function useAgents(options) {
1424
1734
  });
1425
1735
  }
1426
1736
  function useDeleteAgents() {
1427
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1737
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1428
1738
  const qc = reactQuery.useQueryClient();
1429
1739
  return reactQuery.useMutation({
1430
1740
  mutationFn: ({ agentExtIds }) => arbi.agents.delete(agentExtIds),
@@ -1443,7 +1753,7 @@ function useDeleteAgents() {
1443
1753
  });
1444
1754
  }
1445
1755
  function useHealth(options) {
1446
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1756
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1447
1757
  return reactQuery.useQuery({
1448
1758
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.health(),
1449
1759
  queryFn: () => arbi.health.check(),
@@ -1451,7 +1761,7 @@ function useHealth(options) {
1451
1761
  });
1452
1762
  }
1453
1763
  function useAvailableModels(options) {
1454
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1764
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1455
1765
  return reactQuery.useQuery({
1456
1766
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.availableModels(),
1457
1767
  queryFn: () => arbi.health.models(),
@@ -1460,7 +1770,7 @@ function useAvailableModels(options) {
1460
1770
  });
1461
1771
  }
1462
1772
  function useConfigs(options) {
1463
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1773
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1464
1774
  return reactQuery.useQuery({
1465
1775
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.configVersions(),
1466
1776
  queryFn: () => arbi.agentConfig.list(),
@@ -1468,7 +1778,7 @@ function useConfigs(options) {
1468
1778
  });
1469
1779
  }
1470
1780
  function useConfig(configId, options) {
1471
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1781
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1472
1782
  return reactQuery.useQuery({
1473
1783
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.config(configId ?? ""),
1474
1784
  queryFn: () => arbi.agentConfig.get(configId),
@@ -1477,7 +1787,7 @@ function useConfig(configId, options) {
1477
1787
  });
1478
1788
  }
1479
1789
  function useActivity(options) {
1480
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1790
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1481
1791
  return reactQuery.useQuery({
1482
1792
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.activity(),
1483
1793
  queryFn: () => arbi.dm.listActivity({ limit: options?.limit, offset: options?.offset }),
@@ -1485,7 +1795,7 @@ function useActivity(options) {
1485
1795
  });
1486
1796
  }
1487
1797
  function useWorkspaceActivity(workspaceId, options) {
1488
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1798
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1489
1799
  return reactQuery.useInfiniteQuery({
1490
1800
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.workspaceActivity(workspaceId ?? ""),
1491
1801
  queryFn: async ({ pageParam }) => {
@@ -1501,7 +1811,7 @@ function useWorkspaceActivity(workspaceId, options) {
1501
1811
  });
1502
1812
  }
1503
1813
  function useProjects(options) {
1504
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1814
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1505
1815
  return reactQuery.useQuery({
1506
1816
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.projects(),
1507
1817
  queryFn: () => arbi.projects.list(),
@@ -1509,7 +1819,7 @@ function useProjects(options) {
1509
1819
  });
1510
1820
  }
1511
1821
  function useProjectUsage(projectExtId, monthsBack = 0, options) {
1512
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1822
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1513
1823
  const usage = reactQuery.useQuery({
1514
1824
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.projectUsage(projectExtId ?? "", monthsBack),
1515
1825
  queryFn: () => arbi.projects.usage(projectExtId, monthsBack),
@@ -1521,7 +1831,7 @@ function useProjectUsage(projectExtId, monthsBack = 0, options) {
1521
1831
  return { ...usage, metered };
1522
1832
  }
1523
1833
  function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
1524
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1834
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1525
1835
  const enabled = (options?.enabled ?? true) && arbi.isLoggedIn;
1526
1836
  const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 });
1527
1837
  const results = reactQuery.useQueries({
@@ -1595,7 +1905,7 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
1595
1905
  }, [signature]);
1596
1906
  }
1597
1907
  function useProjectInvoices(projectExtId, options) {
1598
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1908
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1599
1909
  return reactQuery.useQuery({
1600
1910
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.projectInvoices(projectExtId ?? ""),
1601
1911
  queryFn: () => arbi.projects.invoices(projectExtId),
@@ -1603,7 +1913,7 @@ function useProjectInvoices(projectExtId, options) {
1603
1913
  });
1604
1914
  }
1605
1915
  function useCurrentUser(options) {
1606
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1916
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1607
1917
  return reactQuery.useQuery({
1608
1918
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.currentUser(),
1609
1919
  queryFn: () => arbi.user.me(),
@@ -1613,7 +1923,7 @@ function useCurrentUser(options) {
1613
1923
  });
1614
1924
  }
1615
1925
  function useFirmPool(options) {
1616
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1926
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1617
1927
  return reactQuery.useQuery({
1618
1928
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.firmPool(),
1619
1929
  queryFn: () => arbi.firm.pool(),
@@ -1629,7 +1939,7 @@ function useBoxRole(options = {}) {
1629
1939
  return { isBox, isBoxAdmin: isBox && !!data?.can_top_up };
1630
1940
  }
1631
1941
  function useTopUpFirmPool() {
1632
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1942
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1633
1943
  const queryClient = reactQuery.useQueryClient();
1634
1944
  return reactQuery.useMutation({
1635
1945
  mutationFn: (aiAddons) => arbi.firm.topUp(aiAddons),
@@ -1654,7 +1964,7 @@ function useCanCreateProjects() {
1654
1964
  return user.data?.can_create_projects;
1655
1965
  }
1656
1966
  function useUserUsageToday(options) {
1657
- const arbi = chunkY7S2SQH3_cjs.useArbi();
1967
+ const arbi = chunk5YGUBXXH_cjs.useArbi();
1658
1968
  return reactQuery.useQuery({
1659
1969
  queryKey: chunkGQAXAZN7_cjs.arbiQueryKeys.userUsageToday(),
1660
1970
  queryFn: () => arbi.user.usageToday(),
@@ -1666,6 +1976,7 @@ function useUserUsageToday(options) {
1666
1976
  }
1667
1977
 
1668
1978
  exports.DEFAULT_DOCUMENT_VIEWER_STATE = DEFAULT_DOCUMENT_VIEWER_STATE;
1979
+ exports.EMPTY_CHAT_STATE = EMPTY_CHAT_STATE;
1669
1980
  exports.EMPTY_SESSION_STATE = EMPTY_SESSION_STATE;
1670
1981
  exports.MAX_THREAD_TABS = MAX_THREAD_TABS;
1671
1982
  exports.MIN_QUEUED_MESSAGE_VISIBILITY_MS = MIN_QUEUED_MESSAGE_VISIBILITY_MS;
@@ -1676,13 +1987,17 @@ exports.agentControl = agentControl;
1676
1987
  exports.browserWorkspaceStorage = browserWorkspaceStorage;
1677
1988
  exports.clearSealedDrafts = clearSealedDrafts;
1678
1989
  exports.closePanelIn = closePanelIn;
1990
+ exports.composeArbiSessionStore = composeArbiSessionStore;
1679
1991
  exports.conversationKey = conversationKey;
1992
+ exports.createArbiChatStore = createArbiChatStore;
1993
+ exports.createArbiDocumentSessionStore = createArbiDocumentSessionStore;
1680
1994
  exports.createArbiLayoutStore = createArbiLayoutStore;
1681
1995
  exports.createArbiSessionStore = createArbiSessionStore;
1682
1996
  exports.createArbiWorkspaceStore = createArbiWorkspaceStore;
1683
1997
  exports.createDebouncedWriter = createDebouncedWriter;
1684
1998
  exports.createSealedDraftStorage = createSealedDraftStorage;
1685
1999
  exports.createStoragePersist = createStoragePersist;
2000
+ exports.createUiStateStorage = createUiStateStorage;
1686
2001
  exports.defaultLayoutState = defaultLayoutState;
1687
2002
  exports.dmTabId = dmTabId;
1688
2003
  exports.flushOnPageExit = flushOnPageExit;
@@ -1692,10 +2007,12 @@ exports.layoutActionsOf = layoutActionsOf;
1692
2007
  exports.nextViewingDocument = nextViewingDocument;
1693
2008
  exports.openPanelIn = openPanelIn;
1694
2009
  exports.panelPlace = panelPlace;
2010
+ exports.parseSavedChat = parseSavedChat;
1695
2011
  exports.parseSavedLayout = parseSavedLayout;
1696
2012
  exports.queuedMessages = queuedMessages;
1697
2013
  exports.readWorkspaceLastOpened = readWorkspaceLastOpened;
1698
2014
  exports.restoreLayout = restoreLayout;
2015
+ exports.savedChatOf = savedChatOf;
1699
2016
  exports.savedLayoutOf = savedLayoutOf;
1700
2017
  exports.selectDraft = selectDraft;
1701
2018
  exports.selectIsGenerating = selectIsGenerating;
@@ -1736,5 +2053,5 @@ exports.useTransientView = useTransientView;
1736
2053
  exports.useUserUsageToday = useUserUsageToday;
1737
2054
  exports.useWorkspaceActivity = useWorkspaceActivity;
1738
2055
  exports.useWorkspaces = useWorkspaces;
1739
- //# sourceMappingURL=chunk-RS6UUPD2.cjs.map
1740
- //# sourceMappingURL=chunk-RS6UUPD2.cjs.map
2056
+ //# sourceMappingURL=chunk-6RSVGLQY.cjs.map
2057
+ //# sourceMappingURL=chunk-6RSVGLQY.cjs.map