@burdenoff/fe-libs 2026.926.5 → 2026.927.1

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 (95) hide show
  1. package/dist/shared/assistant/conversation.d.ts +91 -3
  2. package/dist/shared/assistant/conversation.d.ts.map +1 -1
  3. package/dist/shared/assistant/gatewayClient.d.ts +15 -0
  4. package/dist/shared/assistant/gatewayClient.d.ts.map +1 -1
  5. package/dist/shared/assistant/gatewayClient.js +1 -1
  6. package/dist/shared/assistant/guardedStorage.d.ts +4 -2
  7. package/dist/shared/assistant/guardedStorage.d.ts.map +1 -1
  8. package/dist/shared/assistant/guardedStorage.js +1 -1
  9. package/dist/shared/assistant/history/historyApi.d.ts +38 -0
  10. package/dist/shared/assistant/history/historyApi.d.ts.map +1 -0
  11. package/dist/shared/assistant/history/historyApi.js +153 -0
  12. package/dist/shared/assistant/history/historyEngine.d.ts +96 -0
  13. package/dist/shared/assistant/history/historyEngine.d.ts.map +1 -0
  14. package/dist/shared/assistant/history/historyEngine.js +774 -0
  15. package/dist/shared/assistant/history/historyErrors.d.ts +72 -0
  16. package/dist/shared/assistant/history/historyErrors.d.ts.map +1 -0
  17. package/dist/shared/assistant/history/historyErrors.js +74 -0
  18. package/dist/shared/assistant/history/historyList.d.ts +115 -0
  19. package/dist/shared/assistant/history/historyList.d.ts.map +1 -0
  20. package/dist/shared/assistant/history/historyList.js +116 -0
  21. package/dist/shared/assistant/history/historyMapping.d.ts +65 -0
  22. package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -0
  23. package/dist/shared/assistant/history/historyMapping.js +383 -0
  24. package/dist/shared/assistant/history/historyMerge.d.ts +65 -0
  25. package/dist/shared/assistant/history/historyMerge.d.ts.map +1 -0
  26. package/dist/shared/assistant/history/historyMerge.js +97 -0
  27. package/dist/shared/assistant/history/historyOperations.d.ts +24 -0
  28. package/dist/shared/assistant/history/historyOperations.d.ts.map +1 -0
  29. package/dist/shared/assistant/history/historyOperations.js +125 -0
  30. package/dist/shared/assistant/history/historyResume.d.ts +56 -0
  31. package/dist/shared/assistant/history/historyResume.d.ts.map +1 -0
  32. package/dist/shared/assistant/history/historyResume.js +55 -0
  33. package/dist/shared/assistant/history/historyStatus.d.ts +76 -0
  34. package/dist/shared/assistant/history/historyStatus.d.ts.map +1 -0
  35. package/dist/shared/assistant/history/historyStatus.js +47 -0
  36. package/dist/shared/assistant/history/historyStore.d.ts +192 -0
  37. package/dist/shared/assistant/history/historyStore.d.ts.map +1 -0
  38. package/dist/shared/assistant/history/historyStore.js +503 -0
  39. package/dist/shared/assistant/history/historyTimestamps.d.ts +11 -0
  40. package/dist/shared/assistant/history/historyTimestamps.d.ts.map +1 -0
  41. package/dist/shared/assistant/history/historyTimestamps.js +9 -0
  42. package/dist/shared/assistant/history/historyTypes.d.ts +256 -0
  43. package/dist/shared/assistant/history/historyTypes.d.ts.map +1 -0
  44. package/dist/shared/assistant/history/historyTypes.js +20 -0
  45. package/dist/shared/assistant/history/profileBoundStorage.d.ts +36 -0
  46. package/dist/shared/assistant/history/profileBoundStorage.d.ts.map +1 -0
  47. package/dist/shared/assistant/history/profileBoundStorage.js +74 -0
  48. package/dist/shared/assistant/history/stampRegistry.d.ts +84 -0
  49. package/dist/shared/assistant/history/stampRegistry.d.ts.map +1 -0
  50. package/dist/shared/assistant/history/stampRegistry.js +58 -0
  51. package/dist/shared/assistant/history/useAssistantServerHistory.d.ts +18 -0
  52. package/dist/shared/assistant/history/useAssistantServerHistory.d.ts.map +1 -0
  53. package/dist/shared/assistant/history/useAssistantServerHistory.js +12 -0
  54. package/dist/shared/assistant/i18nManifest.d.ts +18 -0
  55. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  56. package/dist/shared/assistant/i18nManifest.js +18 -0
  57. package/dist/shared/assistant/index.d.ts +16 -0
  58. package/dist/shared/assistant/index.d.ts.map +1 -1
  59. package/dist/shared/assistant/liveTurns.d.ts +7 -0
  60. package/dist/shared/assistant/liveTurns.d.ts.map +1 -1
  61. package/dist/shared/assistant/liveTurns.js +35 -32
  62. package/dist/shared/assistant/spokenTurns.d.ts +20 -0
  63. package/dist/shared/assistant/spokenTurns.d.ts.map +1 -1
  64. package/dist/shared/assistant/spokenTurns.js +13 -8
  65. package/dist/shared/assistant/store.d.ts +35 -1
  66. package/dist/shared/assistant/store.d.ts.map +1 -1
  67. package/dist/shared/assistant/store.js +93 -24
  68. package/dist/shared/assistant/ui/AIAssistantPanel.d.ts +16 -0
  69. package/dist/shared/assistant/ui/AIAssistantPanel.d.ts.map +1 -1
  70. package/dist/shared/assistant/ui/AIAssistantPanel.js +63 -60
  71. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  72. package/dist/shared/assistant/ui/AssistantChatArea.js +730 -672
  73. package/dist/shared/assistant/ui/AssistantConversationList.d.ts +17 -0
  74. package/dist/shared/assistant/ui/AssistantConversationList.d.ts.map +1 -1
  75. package/dist/shared/assistant/ui/AssistantConversationList.js +252 -145
  76. package/dist/shared/assistant/ui/AssistantHistoryNotices.d.ts +36 -0
  77. package/dist/shared/assistant/ui/AssistantHistoryNotices.d.ts.map +1 -0
  78. package/dist/shared/assistant/ui/AssistantHistoryNotices.js +103 -0
  79. package/dist/shared/assistant/ui/AssistantOverlay.d.ts +4 -0
  80. package/dist/shared/assistant/ui/AssistantOverlay.d.ts.map +1 -1
  81. package/dist/shared/assistant/ui/AssistantOverlay.js +97 -94
  82. package/dist/shared/assistant/ui/AssistantSpokenTurnsNotice.d.ts +5 -3
  83. package/dist/shared/assistant/ui/AssistantSpokenTurnsNotice.d.ts.map +1 -1
  84. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +6 -0
  85. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts.map +1 -1
  86. package/dist/shared/assistant/ui/composer/AssistantComposer.js +54 -54
  87. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.d.ts +9 -0
  88. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.d.ts.map +1 -1
  89. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.js +37 -32
  90. package/dist/shared/assistant/voice/turnVisibility.d.ts +7 -5
  91. package/dist/shared/assistant/voice/turnVisibility.d.ts.map +1 -1
  92. package/dist/shared/assistant/voice/voiceTranscript.d.ts +3 -2
  93. package/dist/shared/assistant/voice/voiceTranscript.d.ts.map +1 -1
  94. package/dist/shared-assistant.js +153 -137
  95. package/package.json +1 -1
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Server-backed assistant history (BOFF-7335): the shapes shared by the
3
+ * transport, the mapper, the persisted history store and the engine.
4
+ *
5
+ * ★★ The WIRE types mirror the wspace-conversations `my*` assistant-history
6
+ * fields as BUILT — `history/__fixtures__/assistantHistory.sdl.graphql` is a
7
+ * vendored copy of that SDL, and `historySdlContract.test.ts` validates every
8
+ * operation the client sends against it. When the two disagree, the server is
9
+ * right and this file changes.
10
+ *
11
+ * Product-neutral by construction: a product is only ever the string the
12
+ * product itself declared (`AssistantProductConfig.product`), passed through.
13
+ */
14
+ /** Whose history a request reads or writes: one account, in one workspace, in one product. */
15
+ export interface AssistantHistoryScope {
16
+ actorId: string;
17
+ workspaceId: string;
18
+ /** Sent to the server untouched as `productId`. */
19
+ product: string;
20
+ }
21
+ /** `${actorId}|${workspaceId}|${product}` — see {@link assistantHistoryScopeKey}. */
22
+ export type AssistantHistoryScopeKey = string;
23
+ /**
24
+ * A conversation's key in the history store: its `clientConversationId` (the
25
+ * local conversation id), or `legacy:<serverId>` for a conversation saved
26
+ * before v2, which has no client id.
27
+ */
28
+ export type AssistantHistoryConvKey = string;
29
+ export declare const LEGACY_HISTORY_KEY_PREFIX = "legacy:";
30
+ export declare function assistantHistoryScopeKey(scope: AssistantHistoryScope): AssistantHistoryScopeKey;
31
+ /** A complete scope, or null when any part is missing (history is then off, never "partly on"). */
32
+ export declare function completeAssistantHistoryScope(actorId: string | null | undefined, workspaceId: string | null | undefined, product: string | null | undefined): AssistantHistoryScope | null;
33
+ export declare function legacyHistoryConvKey(serverId: string): AssistantHistoryConvKey;
34
+ export declare function isLegacyHistoryConvKey(key: AssistantHistoryConvKey): boolean;
35
+ /** Exactly one of the two: a client-minted id, or a legacy row's server id. */
36
+ export type AssistantHistoryConvRef = {
37
+ clientConversationId: string;
38
+ } | {
39
+ conversationId: string;
40
+ };
41
+ export type AssistantHistoryEntryKind = "TURN" | "LOCAL_COMMAND" | "NOTE";
42
+ export type AssistantHistoryRole = "USER" | "ASSISTANT" | "NOTE";
43
+ export type AssistantHistorySaveOutcome = "APPLIED" | "ALREADY_APPLIED" | "CONVERSATION_DELETED";
44
+ export type AssistantHistoryDeleteOutcome = "DELETED" | "ALREADY_DELETED" | "TOMBSTONED_UNSEEN" | "NOT_PRESENT";
45
+ /** `AssistantHistoryConversation`, with its DateTimes normalised to ISO strings. */
46
+ export interface AssistantHistoryServerConversation {
47
+ id: string;
48
+ /** Null for a conversation saved before v2 (read-only). */
49
+ clientConversationId: string | null;
50
+ /** The product as the request named it (a renamed product's alias is echoed back as sent). */
51
+ productId: string;
52
+ /** Null once the conversation is deleted: a deleted chat's title is never served. */
53
+ title: string | null;
54
+ legacy: boolean;
55
+ revision: number;
56
+ lastMessageSeq: number;
57
+ deleted: boolean;
58
+ deletedAt: string | null;
59
+ createdAt: string;
60
+ updatedAt: string;
61
+ }
62
+ /** `AssistantHistoryEntry`, with `createdAt` normalised to an ISO string. */
63
+ export interface AssistantHistoryServerEntry {
64
+ id: string;
65
+ /** Null for a message saved before v2. */
66
+ clientMessageId: string | null;
67
+ kind: AssistantHistoryEntryKind | null;
68
+ role: AssistantHistoryRole;
69
+ content: string;
70
+ seq: number | null;
71
+ createdAt: string;
72
+ /** The client's own timestamp, exactly as it was sent (or null when the server clamped it away). */
73
+ clientCreatedAt: string | null;
74
+ /** The allow-listed metadata, verbatim. Untrusted input to `fromHistoryEntry`, never executed. */
75
+ metadata: Record<string, unknown> | null;
76
+ }
77
+ export interface AssistantHistoryPageInfo {
78
+ hasNextPage: boolean;
79
+ hasPreviousPage: boolean;
80
+ startCursor: string | null;
81
+ endCursor: string | null;
82
+ }
83
+ /** `myAssistantHistoryChanges`: every change in commit order, tombstones included. */
84
+ export interface AssistantHistoryChangePage {
85
+ nodes: AssistantHistoryServerConversation[];
86
+ pageInfo: AssistantHistoryPageInfo;
87
+ /** The cursor predates retained tombstones: drop synced state and pull from the start. */
88
+ resetRequired: boolean;
89
+ }
90
+ /** `myAssistantConversations`: live conversations, most recently changed first. */
91
+ export interface AssistantHistoryHeaderPage {
92
+ nodes: AssistantHistoryServerConversation[];
93
+ pageInfo: AssistantHistoryPageInfo;
94
+ }
95
+ /** `myAssistantConversationEntries`: nodes are always ascending by `seq`. */
96
+ export interface AssistantHistoryEntryPage {
97
+ conversation: AssistantHistoryServerConversation;
98
+ nodes: AssistantHistoryServerEntry[];
99
+ pageInfo: AssistantHistoryPageInfo;
100
+ }
101
+ /** `AssistantHistoryEntryInput`. `metadata` is already allow-listed by `toHistoryEntries`. */
102
+ export interface AssistantHistoryEntryInput {
103
+ clientMessageId: string;
104
+ role: AssistantHistoryRole;
105
+ content: string;
106
+ clientCreatedAt?: string;
107
+ metadata?: Record<string, unknown>;
108
+ }
109
+ /** A save, minus `productId` — the transport takes that from the scope, never from the caller. */
110
+ export interface AssistantHistorySaveInput {
111
+ clientConversationId: string;
112
+ kind: AssistantHistoryEntryKind;
113
+ entries: AssistantHistoryEntryInput[];
114
+ }
115
+ export interface AssistantHistorySavePayload {
116
+ outcome: AssistantHistorySaveOutcome;
117
+ conversation: AssistantHistoryServerConversation;
118
+ entries: AssistantHistoryServerEntry[];
119
+ /** `<entryIndex>.<key>` (or `<entryIndex>.<key>.<path>.pendingWrite`) for what the server did not store. */
120
+ droppedMetadataKeys: string[];
121
+ }
122
+ export interface AssistantHistoryDeletePayload {
123
+ outcome: AssistantHistoryDeleteOutcome;
124
+ conversation: AssistantHistoryServerConversation | null;
125
+ }
126
+ /** Paging for `myAssistantConversationEntries`: backward (`last`/`before`) OR forward (`first`/`after`/`sinceSeq`), never both. */
127
+ export type AssistantHistoryEntryPaging = {
128
+ last?: number;
129
+ before?: string;
130
+ } | {
131
+ first?: number;
132
+ after?: string;
133
+ sinceSeq?: number;
134
+ };
135
+ /** What the list shows for a server conversation that is not (yet) materialised locally. */
136
+ export interface AssistantHistoryHeader {
137
+ serverId: string;
138
+ clientConversationId: string | null;
139
+ title: string | null;
140
+ legacy: boolean;
141
+ revision: number;
142
+ lastMessageSeq: number;
143
+ createdAt: string;
144
+ updatedAt: string;
145
+ /**
146
+ * The server answered NOT_FOUND for this conversation (it never had it in
147
+ * this scope), so the list hides it. NOT a delete: nothing is tombstoned,
148
+ * and a feed node with a HIGHER revision makes it visible again. At the same
149
+ * revision `gone` wins a merge, so another tab cannot quietly bring it back.
150
+ */
151
+ gone?: true;
152
+ }
153
+ export interface AssistantHistoryScopeState {
154
+ /**
155
+ * How many times this scope was reset (`resetRequired`). A merge keeps the
156
+ * cursor and headers of the HIGHER generation wholesale — a union would put
157
+ * back exactly what the reset threw away. Absent means 0.
158
+ */
159
+ gen?: number;
160
+ /** The feed's opaque `endCursor`, and the revision it reached (merges keep the higher). */
161
+ cursor: string | null;
162
+ cursorRev: number;
163
+ headers: Record<AssistantHistoryConvKey, AssistantHistoryHeader>;
164
+ /** Headers were dropped to the cache bound; "Show older conversations" pages the live list. */
165
+ hasOlderHeaders?: true;
166
+ pulledAt?: number;
167
+ /**
168
+ * Epoch ms of this generation's reset (`resetRequired`), kept after its
169
+ * re-pull finishes: everything held since was read after it, so for a
170
+ * while a further `resetRequired` cannot mean a missed delete (the engine's
171
+ * feed says how long). Absent for a scope never reset.
172
+ */
173
+ resetAt?: number;
174
+ /** That re-pull has pages still to read: after a reload it resumes, and still removes what it did not return. */
175
+ rescanning?: true;
176
+ }
177
+ export interface AssistantHistoryTombstone {
178
+ scopeKey: AssistantHistoryScopeKey;
179
+ /** Epoch ms it was recorded here. */
180
+ at: number;
181
+ /** The server has confirmed the delete (any outcome), or reported it deleted. */
182
+ confirmed: boolean;
183
+ serverId?: string;
184
+ }
185
+ /**
186
+ * A save carries a SNAPSHOT of the entries, built from the store at commit
187
+ * time — never message ids to look up later — so it survives the main store
188
+ * losing the conversation (another tab's last write wins there).
189
+ */
190
+ export interface AssistantHistorySaveItem {
191
+ id: string;
192
+ type: "save";
193
+ scopeKey: AssistantHistoryScopeKey;
194
+ convKey: AssistantHistoryConvKey;
195
+ kind: AssistantHistoryEntryKind;
196
+ entries: AssistantHistoryEntryInput[];
197
+ attempts: number;
198
+ nextAttemptAt?: number;
199
+ parked?: "quota";
200
+ }
201
+ export interface AssistantHistoryDeleteItem {
202
+ id: string;
203
+ type: "delete";
204
+ scopeKey: AssistantHistoryScopeKey;
205
+ convKey: AssistantHistoryConvKey;
206
+ serverId?: string;
207
+ legacy: boolean;
208
+ attempts: number;
209
+ nextAttemptAt?: number;
210
+ }
211
+ export type AssistantHistoryOutboxItem = AssistantHistorySaveItem | AssistantHistoryDeleteItem;
212
+ /**
213
+ * ★★ `v` is this build's FORMAT. A later build keeps it at 1 only for ADDITIVE
214
+ * changes; anything else takes a higher `v`, and this build then never writes
215
+ * the key (nor reads it). At `v: 1`, what this build does with what it does
216
+ * not read (see historyStore):
217
+ *
218
+ * PRESERVED, exactly as the key holds it at each write:
219
+ * - a new top-level key;
220
+ * - an outbox item of a new type or save kind, in its place in the queue,
221
+ * until that build finishes it (`doneItemIds`);
222
+ * - a new field on a scope, a tombstone, a header or a known outbox item.
223
+ * Wherever the key holds that record, the field is the key's — at every
224
+ * write and every read of another tab's write — so a value the later
225
+ * build changes stays changed and a field it deletes stays deleted, even
226
+ * in a tab of this build that read the old ones. This build never writes
227
+ * such a field the key does not hold, except on a record the key no
228
+ * longer holds at all, which it writes back as it last read it.
229
+ *
230
+ * NOT preserved:
231
+ * - a new field on a header this build replaces with a higher revision (a
232
+ * newer copy of the server's record replaces the old one whole, and this
233
+ * build's own pulls carry none) — so a header's new fields must describe
234
+ * that revision only;
235
+ * - a new field on a scope this build resets (`resetRequired` starts it
236
+ * again from nothing), or on a scope a copy of a higher `gen` replaces;
237
+ * - a record merely left out of the key: this build keeps what it holds
238
+ * (a union), so a later build removes one only by the facts this build
239
+ * reads — `doneItemIds`, a tombstone, a higher `gen`, `gone`;
240
+ * - a new field NESTED inside a field this build reads (inside a save's
241
+ * `entries`, say): it goes with that field's value, which this build's
242
+ * rules choose (the more-tried copy; at equal attempts, this tab's);
243
+ * - a field this build reads, given another type or meaning: it is read
244
+ * as it always was — a scope's or tombstone's field of another type is
245
+ * dropped, a tombstone or header lacking a required one is dropped whole,
246
+ * and an outbox item lacking one is carried as an item of unknown type.
247
+ */
248
+ export interface AssistantHistoryPersisted {
249
+ v: 1;
250
+ scopes: Record<AssistantHistoryScopeKey, AssistantHistoryScopeState>;
251
+ outbox: AssistantHistoryOutboxItem[];
252
+ /** Outbox item id -> epoch ms it was acknowledged. Kept so a merge from a stale tab cannot revive it. */
253
+ doneItemIds: Record<string, number>;
254
+ tombstones: Record<AssistantHistoryConvKey, AssistantHistoryTombstone>;
255
+ }
256
+ //# sourceMappingURL=historyTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyTypes.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/historyTypes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ //#region src/shared/assistant/history/historyTypes.ts
2
+ var e = "legacy:";
3
+ function t(e) {
4
+ return `${e.actorId}|${e.workspaceId}|${e.product}`;
5
+ }
6
+ function n(e, t, n) {
7
+ return !e || !t || !n ? null : {
8
+ actorId: e,
9
+ workspaceId: t,
10
+ product: n
11
+ };
12
+ }
13
+ function r(t) {
14
+ return `${e}${t}`;
15
+ }
16
+ function i(t) {
17
+ return t.startsWith(e);
18
+ }
19
+ //#endregion
20
+ export { e as LEGACY_HISTORY_KEY_PREFIX, t as assistantHistoryScopeKey, n as completeAssistantHistoryScope, i as isLegacyHistoryConvKey, r as legacyHistoryConvKey };
@@ -0,0 +1,36 @@
1
+ import { StateStorage } from 'zustand/middleware';
2
+ export interface ProfileBoundStorage extends StateStorage {
3
+ /** Synchronous: binds to the active profile's key (see the module docblock). */
4
+ getItem(name: string): string | null;
5
+ /** Forget the bound key: writes are refused until the next read binds one (the only way to change profile). */
6
+ unbind(): void;
7
+ /** The storage key the state was read from, or null while unbound. */
8
+ boundKey(): string | null;
9
+ /**
10
+ * What the bound key holds right now, WITHOUT binding: null while unbound or
11
+ * once the profile has changed. A write merges with this first, so another
12
+ * tab's write that this one has not folded in yet is never overwritten.
13
+ */
14
+ peekItem(name: string): string | null;
15
+ /** Bound, and `name` still resolves to the bound key (the active profile has not changed). */
16
+ isCurrent(name: string): boolean;
17
+ /** The key `name` would bind to right now, or null with no active profile. Reads nothing. */
18
+ activeKey(name: string): string | null;
19
+ /**
20
+ * The browser refused the latest write (a full or blocked storage): what is
21
+ * in memory is not saved on this device. False again once a write succeeds.
22
+ * A write refused for the profile (unbound, or changed) is not counted — it
23
+ * was never meant to land.
24
+ */
25
+ lastWriteFailed(): boolean;
26
+ }
27
+ export interface ProfileBoundStorageOptions {
28
+ /** Resolve the profile-scoped key for a base name (default: the app's active profile). */
29
+ resolveKey?: (name: string) => string;
30
+ /** The storage to use (default: `window.localStorage`, when there is one). */
31
+ storage?: () => Pick<Storage, "getItem" | "setItem" | "removeItem"> | null;
32
+ /** Told once per refusal streak, and about every failed write. */
33
+ onRefused?: (reason: "unbound" | "profile-changed" | "write-failed", error?: unknown) => void;
34
+ }
35
+ export declare function createProfileBoundStorage(options?: ProfileBoundStorageOptions): ProfileBoundStorage;
36
+ //# sourceMappingURL=profileBoundStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profileBoundStorage.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/profileBoundStorage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,gFAAgF;IAChF,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,+GAA+G;IAC/G,MAAM,IAAI,IAAI,CAAC;IACf,sEAAsE;IACtE,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACtC,8FAA8F;IAC9F,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,6FAA6F;IAC7F,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvC;;;;;OAKG;IACH,eAAe,IAAI,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC;IAC3E,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,iBAAiB,GAAG,cAAc,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/F;AAUD,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,mBAAmB,CAyGrB"}
@@ -0,0 +1,74 @@
1
+ import { getProfileScopedKey as e } from "../../utils/profileScopedStorage.js";
2
+ //#region src/shared/assistant/history/profileBoundStorage.ts
3
+ function t() {
4
+ try {
5
+ return typeof localStorage > "u" ? null : localStorage;
6
+ } catch {
7
+ return null;
8
+ }
9
+ }
10
+ function n(n = {}) {
11
+ let r = n.resolveKey ?? e, i = n.storage ?? t, a = null, o = !1, s = !1, c = (e, t) => {
12
+ (e === "write-failed" || !o) && (o = !0, n.onRefused?.(e, t));
13
+ }, l = (e) => {
14
+ try {
15
+ let t = r(e);
16
+ return t === e ? null : t;
17
+ } catch {
18
+ return null;
19
+ }
20
+ }, u = (e) => a === null ? (c("unbound"), null) : l(e) === a ? a : (c("profile-changed"), null);
21
+ return {
22
+ getItem(e) {
23
+ let t = l(e);
24
+ if (a !== null && t !== a) return c("profile-changed"), null;
25
+ if (a = t, o = !1, t === null) return null;
26
+ try {
27
+ return i()?.getItem(t) ?? null;
28
+ } catch {
29
+ return null;
30
+ }
31
+ },
32
+ setItem(e, t) {
33
+ let n = u(e);
34
+ if (n !== null) try {
35
+ i()?.setItem(n, t), s = !1;
36
+ } catch (e) {
37
+ s = !0, c("write-failed", e);
38
+ }
39
+ },
40
+ removeItem(e) {
41
+ let t = u(e);
42
+ if (t !== null) try {
43
+ i()?.removeItem(t), s = !1;
44
+ } catch (e) {
45
+ s = !0, c("write-failed", e);
46
+ }
47
+ },
48
+ peekItem(e) {
49
+ if (a === null || l(e) !== a) return null;
50
+ try {
51
+ return i()?.getItem(a) ?? null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ },
56
+ isCurrent(e) {
57
+ return a !== null && l(e) === a;
58
+ },
59
+ activeKey(e) {
60
+ return l(e);
61
+ },
62
+ unbind() {
63
+ a = null, s = !1;
64
+ },
65
+ lastWriteFailed() {
66
+ return s;
67
+ },
68
+ boundKey() {
69
+ return a;
70
+ }
71
+ };
72
+ }
73
+ //#endregion
74
+ export { n as createProfileBoundStorage };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The seams between the main assistant store and server history (BOFF-7335).
3
+ *
4
+ * ★★ A LEAF: this module imports nothing. The main store (`../store`) reads
5
+ * it and the history engine writes it, so neither has to import the other —
6
+ * the store stays loadable in every product, and in every test, without the
7
+ * engine, its transport or its persisted store.
8
+ *
9
+ * Four seams, each empty until the engine is enabled — so with server history
10
+ * off (every product that has not opted in) the store behaves exactly as it
11
+ * did before this module existed:
12
+ *
13
+ * - the STAMP: who a conversation created right now belongs to. The store
14
+ * stamps a new conversation with it (`Conversation.sync`), and only then is
15
+ * that conversation ever saved. No source, or a source that cannot name the
16
+ * product, the account AND the workspace, means device-only.
17
+ * - STORAGE FULL: the main store's persisted write was refused for space. The
18
+ * engine frees space by evicting server-backed conversations it can load
19
+ * again; the eviction's own write is the retry.
20
+ * - BUSY: a conversation that must not be rewritten under the person right now
21
+ * (a live voice session in it). The panel registers this; the engine checks
22
+ * it, together with the turn-in-flight state it reads from the store, before
23
+ * it merges loaded messages or evicts.
24
+ * - OPEN IN PLACE: which conversation may open when the open one leaves the
25
+ * store (deleted here or elsewhere). The store used to open the first one
26
+ * left, whoever it belonged to — another workspace's, which the list hides
27
+ * and whose turns would then be sent from this workspace.
28
+ */
29
+ /** The owner a conversation created now is stamped with. */
30
+ export interface AssistantHistoryStamp {
31
+ product: string;
32
+ workspaceId: string;
33
+ actorId: string;
34
+ }
35
+ /** Install (or, with null, remove) where new conversations' stamps come from. */
36
+ export declare function setHistoryStampSource(source: (() => AssistantHistoryStamp | null) | null): void;
37
+ /**
38
+ * The stamp for a conversation created now, or null: history off, or any part
39
+ * of the owner unknown. Never throws — a source that fails means device-only.
40
+ */
41
+ export declare function getHistoryStamp(): AssistantHistoryStamp | null;
42
+ /**
43
+ * Told when the main store's write was refused. `stillFailing` reports whether
44
+ * the most recent write attempt (including one the handler itself caused) was
45
+ * refused too.
46
+ */
47
+ export type AssistantStorageFullHandler = (stillFailing: () => boolean) => void;
48
+ export declare function setAssistantStorageFullHandler(handler: AssistantStorageFullHandler | null): void;
49
+ /** Called by the main store's guarded storage; a no-op while history is off. */
50
+ export declare function notifyAssistantStorageFull(stillFailing: () => boolean): void;
51
+ /**
52
+ * The panel's answer to "is something live in this conversation right now" (a
53
+ * voice session). Returns its release, which clears the probe only while it is
54
+ * still this one — a panel unmounting after another mounted leaves the newer
55
+ * panel's probe in place.
56
+ */
57
+ export declare function setHistoryBusyProbe(probe: ((conversationId: string) => boolean) | null): () => void;
58
+ /** True when the registered probe says so. A probe that throws answers "busy" — the safe side. */
59
+ export declare function isHistoryConversationBusy(conversationId: string): boolean;
60
+ /** What the store knows of a conversation when it asks whether that one may open. */
61
+ export interface AssistantHistoryOpenCandidate {
62
+ readonly id: string;
63
+ readonly sync?: {
64
+ readonly product: string;
65
+ readonly workspaceId: string;
66
+ readonly actorId: string;
67
+ };
68
+ }
69
+ /** Decides, for one removal, which conversations may open in place of the one that went. */
70
+ export type AssistantHistoryOpenFilter = (candidate: AssistantHistoryOpenCandidate) => boolean;
71
+ /**
72
+ * Install (or, with null, remove) the rule for what may open in place of a
73
+ * removed conversation. A source, not a filter: it is asked once per removal,
74
+ * so it can read the active scope once rather than once per conversation.
75
+ */
76
+ export declare function setHistoryOpenFilterSource(source: (() => AssistantHistoryOpenFilter) | null): void;
77
+ /**
78
+ * The rule for this removal: any conversation with history off (as before),
79
+ * otherwise the source's. A source or filter that throws leaves only the
80
+ * device's own conversations — never another workspace's, at worst an empty
81
+ * panel.
82
+ */
83
+ export declare function historyOpenFilter(): AssistantHistoryOpenFilter;
84
+ //# sourceMappingURL=stampRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stampRegistry.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/stampRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAE/F;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,qBAAqB,GAAG,IAAI,CAQ9D;AAED;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,YAAY,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAIhF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,2BAA2B,GAAG,IAAI,GAAG,IAAI,CAEhG;AAED,gFAAgF;AAChF,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,OAAO,GAAG,IAAI,CAE5E;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,CAAC,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI,GAClD,MAAM,IAAI,CAKZ;AAED,kGAAkG;AAClG,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAOzE;AAED,qFAAqF;AACrF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,4FAA4F;AAC5F,MAAM,MAAM,0BAA0B,GAAG,CAAC,SAAS,EAAE,6BAA6B,KAAK,OAAO,CAAC;AAI/F;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,CAAC,MAAM,0BAA0B,CAAC,GAAG,IAAI,GAAG,IAAI,CAElG;AAKD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,0BAA0B,CAe9D"}
@@ -0,0 +1,58 @@
1
+ //#region src/shared/assistant/history/stampRegistry.ts
2
+ var e = null;
3
+ function t(t) {
4
+ e = t;
5
+ }
6
+ function n() {
7
+ if (!e) return null;
8
+ try {
9
+ let t = e();
10
+ return t && t.product && t.workspaceId && t.actorId ? t : null;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ var r = null;
16
+ function i(e) {
17
+ r = e;
18
+ }
19
+ function a(e) {
20
+ r?.(e);
21
+ }
22
+ var o = null;
23
+ function s(e) {
24
+ return o = e, () => {
25
+ o === e && (o = null);
26
+ };
27
+ }
28
+ function c(e) {
29
+ if (!o) return !1;
30
+ try {
31
+ return o(e);
32
+ } catch {
33
+ return !0;
34
+ }
35
+ }
36
+ var l = null;
37
+ function u(e) {
38
+ l = e;
39
+ }
40
+ var d = () => !0, f = (e) => !e.sync;
41
+ function p() {
42
+ if (!l) return d;
43
+ let e;
44
+ try {
45
+ e = l();
46
+ } catch {
47
+ return f;
48
+ }
49
+ return (t) => {
50
+ try {
51
+ return e(t);
52
+ } catch {
53
+ return f(t);
54
+ }
55
+ };
56
+ }
57
+ //#endregion
58
+ export { n as getHistoryStamp, p as historyOpenFilter, c as isHistoryConversationBusy, a as notifyAssistantStorageFull, i as setAssistantStorageFullHandler, s as setHistoryBusyProbe, u as setHistoryOpenFilterSource, t as setHistoryStampSource };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Opt this product's panel into server-backed history (BOFF-7335, contract §6).
3
+ *
4
+ * ★★ OFF unless asked. A product turns it on with the panel's `serverHistory`
5
+ * prop; with it off (the default) nothing is stamped, queued, pulled or read,
6
+ * and the panel behaves exactly as it did before server history existed.
7
+ *
8
+ * The engine is a module-level singleton, and this only holds it on: enabling
9
+ * is ref-counted, so the overlay (which keeps it on while the panel is closed)
10
+ * and the panel itself can both ask, and it switches off when the last one
11
+ * lets go. The engine watches the account, workspace and profile itself.
12
+ *
13
+ * ★ The product id is the one the product provider already gives — the same
14
+ * string the server stores as `productId` — so no product names itself twice.
15
+ * With no product there is nothing to scope the history to, and it stays off.
16
+ */
17
+ export declare function useAssistantServerHistory(enabled: boolean): void;
18
+ //# sourceMappingURL=useAssistantServerHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssistantServerHistory.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/useAssistantServerHistory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMhE"}
@@ -0,0 +1,12 @@
1
+ import { useAssistantProductOrNull as e } from "../product.js";
2
+ import { assistantHistory as t } from "./historyEngine.js";
3
+ import { useEffect as n } from "react";
4
+ //#region src/shared/assistant/history/useAssistantServerHistory.ts
5
+ function r(r) {
6
+ let i = e()?.product ?? "";
7
+ n(() => {
8
+ if (!(!r || !i)) return t.enable(i);
9
+ }, [r, i]);
10
+ }
11
+ //#endregion
12
+ export { r as useAssistantServerHistory };
@@ -180,6 +180,24 @@ export declare const ASSISTANT_I18N_LITERAL_COPY: {
180
180
  readonly "header.preview": "Preview";
181
181
  readonly "header.ready": "Ready";
182
182
  readonly "header.title": "AI Assistant";
183
+ readonly "history.badgeLoading": "Loading…";
184
+ readonly "history.badgeNotSaved": "Not saved";
185
+ readonly "history.badgeReadOnly": "Read-only";
186
+ readonly "history.deleteNotSaved": "This device's storage is full, so that delete isn't saved here yet. Keep this page open until it reaches the server.";
187
+ readonly "history.deletedElsewhere": "The conversation you had open was deleted on another device.";
188
+ readonly "history.dismiss": "Dismiss";
189
+ readonly "history.groupDevice": "On this device";
190
+ readonly "history.groupWorkspace": "This workspace";
191
+ readonly "history.legacyReadOnly": "This conversation was saved by an earlier version of the assistant. You can read it, but it can't be continued.";
192
+ readonly "history.loadFailed": "Couldn't load this conversation.";
193
+ readonly "history.loading": "Loading conversation…";
194
+ readonly "history.notSavedInvalid": "Part of this conversation couldn't be saved. It stays on this device.";
195
+ readonly "history.notSavedQuota": "Not saved yet: this workspace has reached its conversation limit. It will be saved when there is room.";
196
+ readonly "history.notSavedScope": "Some turns were sent from another workspace. They stay on this device.";
197
+ readonly "history.showEarlier": "Show earlier messages";
198
+ readonly "history.showOlder": "Show older conversations";
199
+ readonly "history.tryAgain": "Try again";
200
+ readonly "history.untitled": "Untitled conversation";
183
201
  readonly "language.inputLabel": "Language";
184
202
  readonly "language.replyLabel": "Assistant replies in";
185
203
  readonly "language.replyMatch": "Match my language";
@@ -1 +1 @@
1
- {"version":3,"file":"i18nManifest.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/i18nManifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAU1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0GG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4OG,CAAC;AAE5C,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAW/E;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBtE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIjE,CAAC;AAEL,kEAAkE;AAClE,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,mBAAmB,EACnB,IAAI,GAAG,OAAO,GAAG,mBAAmB,CACrC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,uBAAuB,EAAE,GACxC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC9C,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiCzB"}
1
+ {"version":3,"file":"i18nManifest.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/i18nManifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAU1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0GG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoQG,CAAC;AAE5C,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAW/E;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBtE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIjE,CAAC;AAEL,kEAAkE;AAClE,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,mBAAmB,EACnB,IAAI,GAAG,OAAO,GAAG,mBAAmB,CACrC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,uBAAuB,EAAE,GACxC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC9C,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiCzB"}
@@ -75,6 +75,24 @@ var u = {
75
75
  "header.preview": "Preview",
76
76
  "header.ready": "Ready",
77
77
  "header.title": "AI Assistant",
78
+ "history.badgeLoading": "Loading…",
79
+ "history.badgeNotSaved": "Not saved",
80
+ "history.badgeReadOnly": "Read-only",
81
+ "history.deleteNotSaved": "This device's storage is full, so that delete isn't saved here yet. Keep this page open until it reaches the server.",
82
+ "history.deletedElsewhere": "The conversation you had open was deleted on another device.",
83
+ "history.dismiss": "Dismiss",
84
+ "history.groupDevice": "On this device",
85
+ "history.groupWorkspace": "This workspace",
86
+ "history.legacyReadOnly": "This conversation was saved by an earlier version of the assistant. You can read it, but it can't be continued.",
87
+ "history.loadFailed": "Couldn't load this conversation.",
88
+ "history.loading": "Loading conversation…",
89
+ "history.notSavedInvalid": "Part of this conversation couldn't be saved. It stays on this device.",
90
+ "history.notSavedQuota": "Not saved yet: this workspace has reached its conversation limit. It will be saved when there is room.",
91
+ "history.notSavedScope": "Some turns were sent from another workspace. They stay on this device.",
92
+ "history.showEarlier": "Show earlier messages",
93
+ "history.showOlder": "Show older conversations",
94
+ "history.tryAgain": "Try again",
95
+ "history.untitled": "Untitled conversation",
78
96
  "language.inputLabel": "Language",
79
97
  "language.replyLabel": "Assistant replies in",
80
98
  "language.replyMatch": "Match my language",