@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,72 @@
1
+ /**
2
+ * What a failed server-history call means, and what to do about it (BOFF-7335).
3
+ *
4
+ * ★★ The rule that matters: a queued save is DROPPED only when the server
5
+ * itself said this item is invalid — `BAD_USER_INPUT` carrying one of the two
6
+ * history i18n keys its validator raises. Everything else keeps the item:
7
+ *
8
+ * - `schema-unavailable` — the fields are not there (yet). Hive publishes the
9
+ * new schema right after the image is pushed, before Flux has rolled the
10
+ * pods, and a rolled-back server rejects the v2 fields the same way. A
11
+ * subgraph pod without the fields fails validation in graphql-yoga, which
12
+ * codes it `GRAPHQL_VALIDATION_FAILED` (the gateway forwards any coded
13
+ * error); a supergraph without them fails at the gateway, whose
14
+ * request-phase remap answers `BAD_USER_INPUT` with no i18n key and the
15
+ * graphql-js message. Both pause; neither drops. (A gateway older than that
16
+ * remap masks the latter as `INTERNAL_SERVER_ERROR` "Unexpected error." —
17
+ * transient below, so the item is still kept.)
18
+ * - `quota` — park; the next panel open or ten minutes retries it.
19
+ * - `auth` — wait for the account or token to change.
20
+ * - `not-found` — only `myAssistantConversationEntries` raises it, and it
21
+ * means "this scope never had that id". It is NEVER read as a delete.
22
+ * - `scope-inactive` — the request's workspace or account is not the active
23
+ * one, so it was not sent at all. Hold until the scope is active again.
24
+ * - `transient` — anything else, including the server's own retryable
25
+ * `RATE_LIMIT_EXCEEDED` (a busy scope, or the bound on tombstones for
26
+ * never-seen ids), which carries `retryAfter` seconds. Backed off,
27
+ * retried indefinitely: every write is idempotent.
28
+ */
29
+ export type AssistantHistoryErrorClass = "schema-unavailable" | "rejected" | "quota" | "auth" | "not-found" | "scope-inactive" | "transient";
30
+ export interface AssistantHistoryErrorVerdict {
31
+ class: AssistantHistoryErrorClass;
32
+ /** The first `extensions.code` found, for logs. */
33
+ code?: string;
34
+ /** The first `extensions.i18nKey` found, for logs. */
35
+ i18nKey?: string;
36
+ /** The server asked for at least this long before a retry (`RATE_LIMIT_EXCEEDED`'s `retryAfter`). */
37
+ retryAfterMs?: number;
38
+ }
39
+ /** The validator's two keys — the ONLY errors that drop a queued item. */
40
+ export declare const ASSISTANT_HISTORY_REJECTION_KEYS: readonly string[];
41
+ export declare function classifyAssistantHistoryError(error: unknown): AssistantHistoryErrorVerdict;
42
+ /** How long a schema mismatch pauses the whole engine. */
43
+ export declare const ASSISTANT_HISTORY_SCHEMA_PAUSE_MS: number;
44
+ /** When a quota-parked save is retried if the panel is not opened first. */
45
+ export declare const ASSISTANT_HISTORY_QUOTA_RETRY_MS: number;
46
+ export declare const ASSISTANT_HISTORY_BACKOFF_BASE_MS = 1000;
47
+ export declare const ASSISTANT_HISTORY_BACKOFF_MAX_MS: number;
48
+ /**
49
+ * `drop` — this item only (and only a save); `pause` — the whole engine, for
50
+ * `delayMs`; `park` — this item, until the panel opens or `delayMs`; `hold` —
51
+ * until the scope, account or token changes; `retry` — this item after `delayMs`.
52
+ */
53
+ export type AssistantHistoryRetryAction = "drop" | "pause" | "park" | "hold" | "retry";
54
+ export interface AssistantHistoryRetryPlan {
55
+ action: AssistantHistoryRetryAction;
56
+ delayMs: number;
57
+ }
58
+ /** 1 s · 2^attempts, full jitter on the upper half, capped at five minutes. */
59
+ export declare function assistantHistoryBackoffMs(attempts: number, random?: () => number): number;
60
+ /**
61
+ * What to do with an outbox item after a failure.
62
+ *
63
+ * ★★ A DELETE is never dropped, whatever the server said: dropping it would
64
+ * let the conversation come back from the server on the next pull. A delete
65
+ * the validator refuses (which only a client bug can cause) is retried on the
66
+ * slow schedule instead, so the defect is visible rather than silent.
67
+ */
68
+ export declare function planAssistantHistoryRetry(verdict: AssistantHistoryErrorVerdict, item: {
69
+ type: "save" | "delete";
70
+ attempts: number;
71
+ }, random?: () => number): AssistantHistoryRetryPlan;
72
+ //# sourceMappingURL=historyErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyErrors.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/historyErrors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAQH,MAAM,MAAM,0BAA0B,GAClC,oBAAoB,GACpB,UAAU,GACV,OAAO,GACP,MAAM,GACN,WAAW,GACX,gBAAgB,GAChB,WAAW,CAAC;AAEhB,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,0BAA0B,CAAC;IAClC,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qGAAqG;IACrG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,EAAE,SAAS,MAAM,EAG7D,CAAC;AAwCF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,4BAA4B,CA8C1F;AAID,0DAA0D;AAC1D,eAAO,MAAM,iCAAiC,QAAa,CAAC;AAC5D,4EAA4E;AAC5E,eAAO,MAAM,gCAAgC,QAAc,CAAC;AAC5D,eAAO,MAAM,iCAAiC,OAAQ,CAAC;AACvD,eAAO,MAAM,gCAAgC,QAAa,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvF,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,2BAA2B,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,MAAoB,GAAG,MAAM,CAQtG;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,4BAA4B,EACrC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EACnD,MAAM,GAAE,MAAM,MAAoB,GACjC,yBAAyB,CAuB3B"}
@@ -0,0 +1,74 @@
1
+ import { classifyQuotaError as e, extensionObjectsIn as t, isQuotaExhaustedError as n } from "../quota.js";
2
+ import { AssistantHistoryResponseError as r, AssistantHistoryScopeInactiveError as i } from "./historyApi.js";
3
+ //#region src/shared/assistant/history/historyErrors.ts
4
+ var a = ["assistant.errors.invalidHistoryInput", "assistant.errors.historyPayloadTooLarge"], o = /Cannot query field|Unknown argument|Unknown type|is not defined by type|Variable "\$[^"]+" got invalid/i, s = new Set(["GRAPHQL_VALIDATION_FAILED", "GRAPHQL_PARSE_FAILED"]), c = new Set(["UNAUTHENTICATED", "FORBIDDEN"]);
5
+ function l(e) {
6
+ return e instanceof Error ? e.message : typeof e == "string" ? e : "";
7
+ }
8
+ function u(e, t) {
9
+ for (let n of e) {
10
+ let e = n[t];
11
+ if (typeof e == "string" && e.length > 0) return e;
12
+ }
13
+ }
14
+ function d(e) {
15
+ for (let t of e) {
16
+ let e = t.retryAfter;
17
+ if (typeof e == "number" && Number.isFinite(e) && e > 0) return Math.min(e, 3600) * 1e3;
18
+ }
19
+ }
20
+ function f(f) {
21
+ if (f instanceof i) return { class: "scope-inactive" };
22
+ if (f instanceof r) return { class: "schema-unavailable" };
23
+ let p = t(f), m = new Set(p.map((e) => e.code).filter((e) => typeof e == "string")), h = new Set(p.map((e) => e.i18nKey).filter((e) => typeof e == "string")), g = u(p, "code"), _ = u(p, "i18nKey"), v = (e) => ({
24
+ class: e,
25
+ ...g ? { code: g } : {},
26
+ ..._ ? { i18nKey: _ } : {}
27
+ });
28
+ if (m.has("BAD_USER_INPUT") && a.some((e) => h.has(e))) return v("rejected");
29
+ if (o.test(l(f)) || [...m].some((e) => s.has(e))) return v("schema-unavailable");
30
+ if (m.has("RATE_LIMIT_EXCEEDED")) {
31
+ let e = d(p);
32
+ return {
33
+ ...v("transient"),
34
+ ...e ? { retryAfterMs: e } : {}
35
+ };
36
+ }
37
+ return e(f) !== null || n(f) ? v("quota") : [...m].some((e) => c.has(e)) ? v("auth") : m.has("NOT_FOUND") ? v("not-found") : m.has("BAD_USER_INPUT") ? v("schema-unavailable") : v("transient");
38
+ }
39
+ var p = 5 * 6e4, m = 10 * 6e4, h = 1e3, g = 5 * 6e4;
40
+ function _(e, t = Math.random) {
41
+ let n = Math.min(g, h * 2 ** Math.max(0, Math.min(e, 20))), r = n / 2 + n / 2 * Math.min(Math.max(t(), 0), 1);
42
+ return Math.round(r);
43
+ }
44
+ function v(e, t, n = Math.random) {
45
+ switch (e.class) {
46
+ case "rejected": return t.type === "save" ? {
47
+ action: "drop",
48
+ delayMs: 0
49
+ } : {
50
+ action: "retry",
51
+ delayMs: g
52
+ };
53
+ case "schema-unavailable": return {
54
+ action: "pause",
55
+ delayMs: p
56
+ };
57
+ case "quota": return {
58
+ action: "park",
59
+ delayMs: m
60
+ };
61
+ case "auth":
62
+ case "scope-inactive": return {
63
+ action: "hold",
64
+ delayMs: 0
65
+ };
66
+ case "not-found":
67
+ case "transient": return {
68
+ action: "retry",
69
+ delayMs: Math.max(_(t.attempts, n), e.retryAfterMs ?? 0)
70
+ };
71
+ }
72
+ }
73
+ //#endregion
74
+ export { h as ASSISTANT_HISTORY_BACKOFF_BASE_MS, g as ASSISTANT_HISTORY_BACKOFF_MAX_MS, m as ASSISTANT_HISTORY_QUOTA_RETRY_MS, a as ASSISTANT_HISTORY_REJECTION_KEYS, p as ASSISTANT_HISTORY_SCHEMA_PAUSE_MS, _ as assistantHistoryBackoffMs, f as classifyAssistantHistoryError, v as planAssistantHistoryRetry };
@@ -0,0 +1,115 @@
1
+ import { AssistantModeConfig, Conversation, ConversationSyncStamp } from '../conversation';
2
+ import { AssistantMode } from '../types';
3
+ import { AssistantHistoryConvKey, AssistantHistoryHeader, AssistantHistoryScope, AssistantHistoryScopeKey, AssistantHistoryServerConversation, AssistantHistoryTombstone } from './historyTypes';
4
+ /** The scope a stamped conversation belongs to. */
5
+ export declare function historyScopeKeyOfStamp(sync: ConversationSyncStamp): AssistantHistoryScopeKey;
6
+ /** A server conversation's key here: its client id, or `legacy:<id>` for a pre-v2 row. */
7
+ export declare function historyConvKeyOf(conversation: Pick<AssistantHistoryServerConversation, "id" | "clientConversationId">): AssistantHistoryConvKey;
8
+ /** The header the list keeps for a live server conversation. */
9
+ export declare function historyHeaderOf(conversation: AssistantHistoryServerConversation): AssistantHistoryHeader;
10
+ /**
11
+ * Has this conversation got anything to lose — so it must never be reused as
12
+ * a fresh draft? Messages, a live session, or a place in server history (a
13
+ * conversation opened from the server is empty while it loads).
14
+ */
15
+ export declare function conversationHasHistory(conversation: Conversation): boolean;
16
+ /**
17
+ * Saved before server history (v2): shown, deletable, never continued and
18
+ * never used as context — the composer is disabled while it is open, and a
19
+ * send that arrives anyway starts a new conversation.
20
+ */
21
+ export declare function isReadOnlyHistoryConversation(conversation: Pick<Conversation, "sync"> | undefined): boolean;
22
+ /**
23
+ * Stamped for another owner than a conversation created now would get
24
+ * (`stamp`): another account, workspace or product. Such a conversation is
25
+ * never continued — the list hides it and the engine closes it once nothing
26
+ * runs in it, and a send that reaches it anyway starts a new conversation, so
27
+ * its content is never carried into this workspace's turns. With no stamp
28
+ * (history off, or the owner unknown) there is nothing to compare with, and
29
+ * nothing is "other".
30
+ */
31
+ export declare function isOtherScopeHistoryConversation(conversation: Pick<Conversation, "sync"> | undefined, stamp: AssistantHistoryScope | null): boolean;
32
+ /**
33
+ * May `conversation` be reused as a fresh draft by a mode switch? Only an
34
+ * empty one with nothing to lose (`conversationHasHistory`) — and only one
35
+ * that belongs where the next turn will be saved: stamped for exactly the
36
+ * owner a new conversation would get now (`stamp`), or, with no stamp
37
+ * (history off, or its account, workspace or product unknown), device-only.
38
+ * Otherwise a draft made in another workspace would take this workspace's
39
+ * turns, or a device-only one would keep them off the server for good.
40
+ */
41
+ export declare function isReusableHistoryDraft(conversation: Conversation, stamp: AssistantHistoryScope | null): boolean;
42
+ /**
43
+ * The mode a conversation opened from the server starts in: the first mode
44
+ * known NOT to write — `assistant` when offered — so a reopened conversation
45
+ * can only read until the person chooses a write mode (through its consent).
46
+ */
47
+ export declare function resolveHistoryReopenMode(modes: readonly AssistantModeConfig[]): AssistantMode;
48
+ export interface MaterializeHistoryOptions {
49
+ /** The product's modes, in display order (the reopen mode is chosen from these). */
50
+ modes: readonly AssistantModeConfig[];
51
+ /** Auto is selected (the store's `autoRouting`). */
52
+ autoRouting: boolean;
53
+ /** Now, as ISO (the stamp's `openedAt`). */
54
+ openedAt: string;
55
+ }
56
+ /**
57
+ * A server header as a conversation of this device: no messages yet (the load
58
+ * fills them), no backend session (the model's memory of it is gone; a new
59
+ * one starts with the next message), in a mode that does not write.
60
+ */
61
+ export declare function materializeHistoryHeader(convKey: AssistantHistoryConvKey, header: AssistantHistoryHeader, scope: AssistantHistoryScope, options: MaterializeHistoryOptions): Conversation;
62
+ export interface AssistantHistoryListRow {
63
+ key: AssistantHistoryConvKey;
64
+ /** The conversation's title, or the server's; empty when neither has one (the UI names it). */
65
+ title: string;
66
+ updatedAt: string;
67
+ /** Held on this device (opened here, or created here). Null: a server header only. */
68
+ conversation: Conversation | null;
69
+ header: AssistantHistoryHeader | null;
70
+ /** Saved before v2: opens read-only. */
71
+ legacy: boolean;
72
+ /** Why its latest turns are not being saved. */
73
+ blocked?: ConversationSyncStamp["blocked"];
74
+ loading: boolean;
75
+ }
76
+ export interface AssistantHistoryListInput {
77
+ conversations: readonly Conversation[];
78
+ /** The active scope, or null (then nothing is "this workspace"). */
79
+ scopeKey: AssistantHistoryScopeKey | null;
80
+ /** The persisted headers of the active scope. */
81
+ headers: Readonly<Record<AssistantHistoryConvKey, AssistantHistoryHeader>>;
82
+ /** Headers paged in this page load ("Show older conversations"). */
83
+ olderHeaders?: Readonly<Record<AssistantHistoryConvKey, AssistantHistoryHeader>>;
84
+ tombstones: Readonly<Record<AssistantHistoryConvKey, AssistantHistoryTombstone>>;
85
+ loadingIds?: Readonly<Record<string, true>>;
86
+ }
87
+ export interface AssistantHistoryList {
88
+ workspace: AssistantHistoryListRow[];
89
+ device: Conversation[];
90
+ }
91
+ /** The two groups the list renders (see the module docblock). */
92
+ export declare function selectAssistantHistoryList(input: AssistantHistoryListInput): AssistantHistoryList;
93
+ /** Server-backed conversations kept on this device at most (the least recently opened go first). */
94
+ export declare const ASSISTANT_HISTORY_MAX_CACHED_CONVERSATIONS = 25;
95
+ export interface HistoryEvictionInput {
96
+ conversations: readonly Conversation[];
97
+ activeConversationId: string | null;
98
+ /** Keep at most this many server-backed conversations. */
99
+ max: number;
100
+ /**
101
+ * Must stay regardless: queued work, something live in it, or no header to
102
+ * show it by once it is gone from here.
103
+ */
104
+ isProtected: (conversation: Conversation) => boolean;
105
+ }
106
+ /**
107
+ * The server-backed conversations to evict, least recently opened first.
108
+ *
109
+ * Never evicted: device-only conversations (they exist nowhere else), the open
110
+ * one, one with queued saves or deletes, one with a turn or a voice session in
111
+ * it, one renamed here (the new name exists only here) or one whose turns are
112
+ * not being saved (`blocked`: its history is only here too).
113
+ */
114
+ export declare function selectHistoryEvictions(input: HistoryEvictionInput): string[];
115
+ //# sourceMappingURL=historyList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyList.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/historyList.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import { modeRequiresConfirmWrites as e } from "../api.js";
2
+ import "../autoRouting.js";
3
+ import { assistantHistoryScopeKey as t, legacyHistoryConvKey as n } from "./historyTypes.js";
4
+ //#region src/shared/assistant/history/historyList.ts
5
+ function r(e) {
6
+ return t({
7
+ actorId: e.actorId,
8
+ workspaceId: e.workspaceId,
9
+ product: e.product
10
+ });
11
+ }
12
+ function i(e) {
13
+ return e.clientConversationId ?? n(e.id);
14
+ }
15
+ function a(e) {
16
+ return {
17
+ serverId: e.id,
18
+ clientConversationId: e.clientConversationId,
19
+ title: e.title,
20
+ legacy: e.legacy,
21
+ revision: e.revision,
22
+ lastMessageSeq: e.lastMessageSeq,
23
+ createdAt: e.createdAt,
24
+ updatedAt: e.updatedAt
25
+ };
26
+ }
27
+ function o(e) {
28
+ return e.messages.length > 0 || !!e.backendSessionId || !!e.sync?.serverId || e.sync?.origin === "remote" || e.sync?.origin === "legacy";
29
+ }
30
+ function s(e) {
31
+ return e?.sync?.origin === "legacy";
32
+ }
33
+ function c(e, t) {
34
+ let n = e?.sync;
35
+ return !n || !t ? !1 : n.product !== t.product || n.workspaceId !== t.workspaceId || n.actorId !== t.actorId;
36
+ }
37
+ function l(e, t) {
38
+ if (o(e)) return !1;
39
+ let n = e.sync;
40
+ return !t || !n ? !t && !n : n.product === t.product && n.workspaceId === t.workspaceId && n.actorId === t.actorId;
41
+ }
42
+ function u(t) {
43
+ return t.find((t) => t.id === "assistant" || !t.writeCapable && !t.requiresAdmin && !e(t.id))?.id ?? "assistant";
44
+ }
45
+ function d(e, t, n, r) {
46
+ let i = u(r.modes), a = i === "assistant" && r.autoRouting ? "auto" : void 0;
47
+ return {
48
+ id: e,
49
+ title: t.title ?? "",
50
+ mode: i,
51
+ ...a ? { routedBy: a } : {},
52
+ messages: [],
53
+ backendSessionId: null,
54
+ createdAt: t.createdAt,
55
+ updatedAt: t.updatedAt,
56
+ sync: {
57
+ v: 1,
58
+ product: n.product,
59
+ workspaceId: n.workspaceId,
60
+ actorId: n.actorId,
61
+ origin: t.legacy || t.clientConversationId === null ? "legacy" : "remote",
62
+ serverId: t.serverId,
63
+ revision: t.revision,
64
+ lastSeq: 0,
65
+ openedAt: r.openedAt
66
+ }
67
+ };
68
+ }
69
+ var f = (e, t) => e > t ? e : t;
70
+ function p(e) {
71
+ let t = [], n = /* @__PURE__ */ new Map(), i = e.loadingIds ?? {};
72
+ for (let a of e.conversations) {
73
+ let o = a.sync;
74
+ if (!o) {
75
+ t.push(a);
76
+ continue;
77
+ }
78
+ if (e.scopeKey === null || r(o) !== e.scopeKey || a.id in e.tombstones) continue;
79
+ let s = e.headers[a.id] ?? e.olderHeaders?.[a.id] ?? null;
80
+ n.set(a.id, {
81
+ key: a.id,
82
+ title: a.title,
83
+ updatedAt: s ? f(a.updatedAt, s.updatedAt) : a.updatedAt,
84
+ conversation: a,
85
+ header: s,
86
+ legacy: o.origin === "legacy",
87
+ ...o.blocked ? { blocked: o.blocked } : {},
88
+ loading: a.id in i
89
+ });
90
+ }
91
+ if (e.scopeKey !== null) {
92
+ let t = [e.headers, e.olderHeaders ?? {}];
93
+ for (let r of t) for (let [t, a] of Object.entries(r)) n.has(t) || a.gone || t in e.tombstones || n.set(t, {
94
+ key: t,
95
+ title: a.title ?? "",
96
+ updatedAt: a.updatedAt,
97
+ conversation: null,
98
+ header: a,
99
+ legacy: a.legacy,
100
+ loading: t in i
101
+ });
102
+ }
103
+ return {
104
+ workspace: [...n.values()].sort((e, t) => e.updatedAt === t.updatedAt ? e.key < t.key ? -1 : 1 : e.updatedAt < t.updatedAt ? 1 : -1),
105
+ device: t
106
+ };
107
+ }
108
+ var m = 25;
109
+ function h(e) {
110
+ let t = e.conversations.filter((e) => !!e.sync?.serverId), n = t.length - e.max;
111
+ if (n <= 0) return [];
112
+ let r = (e) => e.sync?.openedAt ?? e.updatedAt;
113
+ return t.filter((t) => t.id !== e.activeConversationId && !t.sync?.titleLocked && !t.sync?.blocked && !e.isProtected(t)).sort((e, t) => r(e) === r(t) ? e.id < t.id ? -1 : 1 : r(e) < r(t) ? -1 : 1).slice(0, n).map((e) => e.id);
114
+ }
115
+ //#endregion
116
+ export { m as ASSISTANT_HISTORY_MAX_CACHED_CONVERSATIONS, o as conversationHasHistory, i as historyConvKeyOf, a as historyHeaderOf, r as historyScopeKeyOfStamp, c as isOtherScopeHistoryConversation, s as isReadOnlyHistoryConversation, l as isReusableHistoryDraft, d as materializeHistoryHeader, u as resolveHistoryReopenMode, p as selectAssistantHistoryList, h as selectHistoryEvictions };
@@ -0,0 +1,65 @@
1
+ import { Message } from '../conversation';
2
+ import { AssistantHistoryEntryInput, AssistantHistoryEntryKind, AssistantHistoryServerEntry } from './historyTypes';
3
+ /** The server's id rule for `clientConversationId` / `clientMessageId`. A local `${Date.now()}-${rand}` id always matches. */
4
+ export declare const HISTORY_CLIENT_ID_PATTERN: RegExp;
5
+ /** The server refuses content over this many UTF-8 bytes. */
6
+ export declare const HISTORY_MAX_CONTENT_BYTES = 131072;
7
+ /** What the client cuts one saved entry's content to before anything else (the server's limit, with room). */
8
+ export declare const HISTORY_ENTRY_CONTENT_CAP_BYTES = 98304;
9
+ /** A save request must fit under the gateway body limit with this much to spare. */
10
+ export declare const HISTORY_REQUEST_HEADROOM_BYTES = 16384;
11
+ /** The stored metadata envelope's limits. */
12
+ export declare const HISTORY_METADATA_ENVELOPE_MAX_BYTES = 16384;
13
+ /** Appended to a saved copy that had to be cut. The local message is untouched. */
14
+ export declare const HISTORY_TRUNCATION_MARKER = "\n\n[\u2026truncated in saved history]";
15
+ export declare function isHistoryClientId(value: unknown): value is string;
16
+ export declare function utf8ByteLength(value: string): number;
17
+ /** What the server stores for text it cannot keep as-is: U+0000 and unpaired surrogates become U+FFFD. */
18
+ export declare function toStorableHistoryText(value: string): string;
19
+ /** The metadata keys server history stores. Everything else stays on the device. */
20
+ export declare const HISTORY_METADATA_KEYS: readonly string[];
21
+ export interface FilteredHistoryMetadata {
22
+ kept: Record<string, unknown>;
23
+ /** Keys not kept, for logs. */
24
+ dropped: string[];
25
+ }
26
+ /**
27
+ * The server's allow-list, applied on this side: unknown, ill-typed,
28
+ * unstorable or too-deep keys are dropped (never an error), and approval data
29
+ * is removed from inside every kept value.
30
+ */
31
+ export declare function filterHistoryMetadata(metadata: unknown): FilteredHistoryMetadata;
32
+ /**
33
+ * Drop whole keys, largest first, until the stored envelope fits — the same
34
+ * order the server uses, so a request never depends on the server making room.
35
+ */
36
+ export declare function fitHistoryMetadataEnvelope(kind: AssistantHistoryEntryKind, clientCreatedAt: string | null, metadata: Record<string, unknown>): Record<string, unknown>;
37
+ /** The longest prefix (whole code points) that is at most `maxBytes` of UTF-8. */
38
+ export declare function truncateUtf8(value: string, maxBytes: number): string;
39
+ export interface HistorySaveTarget {
40
+ productId: string;
41
+ clientConversationId: string;
42
+ kind: AssistantHistoryEntryKind;
43
+ }
44
+ /** The size, in bytes, of the save request as the gateway receives it. */
45
+ export declare function measureHistorySaveRequest(target: HistorySaveTarget, entries: AssistantHistoryEntryInput[]): number;
46
+ /** The request budget: the gateway limit less headroom for headers the fetch layer adds. */
47
+ export declare const HISTORY_SAVE_REQUEST_BUDGET_BYTES: number;
48
+ /**
49
+ * The entries to save for `messages`, sized to fit one request.
50
+ *
51
+ * Each entry's content is first capped at {@link HISTORY_ENTRY_CONTENT_CAP_BYTES};
52
+ * then, while the whole request is over budget (at most three passes), the
53
+ * largest content is cut at a code-point boundary. A cut copy ends with
54
+ * {@link HISTORY_TRUNCATION_MARKER} and carries `truncated: true`.
55
+ */
56
+ export declare function toHistoryEntries(messages: readonly Message[], target: HistorySaveTarget): AssistantHistoryEntryInput[];
57
+ /** TURN / LOCAL_COMMAND are exactly [USER, ASSISTANT]; NOTE is exactly [NOTE] — the server's rule. */
58
+ export declare function historyEntriesMatchKind(kind: AssistantHistoryEntryKind, entries: readonly AssistantHistoryEntryInput[]): boolean;
59
+ /**
60
+ * A complete panel message for a server entry. The id is the client's own
61
+ * (`clientMessageId`), so a message saved from this device is recognised as
62
+ * the same message; a pre-v2 entry is `legacy:<serverId>`.
63
+ */
64
+ export declare function fromHistoryEntry(entry: AssistantHistoryServerEntry): Message;
65
+ //# sourceMappingURL=historyMapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyMapping.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/history/historyMapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAMV,OAAO,EACR,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EAEzB,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC;AAKxB,8HAA8H;AAC9H,eAAO,MAAM,yBAAyB,QAAwC,CAAC;AAC/E,6DAA6D;AAC7D,eAAO,MAAM,yBAAyB,SAAU,CAAC;AACjD,8GAA8G;AAC9G,eAAO,MAAM,+BAA+B,QAAS,CAAC;AACtD,oFAAoF;AACpF,eAAO,MAAM,8BAA8B,QAAS,CAAC;AACrD,6CAA6C;AAC7C,eAAO,MAAM,mCAAmC,QAAS,CAAC;AAwB1D,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,2CAAsC,CAAC;AAE7E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEjE;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAsCD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3D;AAmGD,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAmC,CAAC;AAEvF,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,+BAA+B;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,uBAAuB,CAkBhF;AAQD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,yBAAyB,EAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBzB;AAyGD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWpE;AAgBD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,yBAAyB,CAAC;CACjC;AAED,0EAA0E;AAC1E,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,0BAA0B,EAAE,GACpC,MAAM,CAkBR;AAED,4FAA4F;AAC5F,eAAO,MAAM,iCAAiC,QACW,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,MAAM,EAAE,iBAAiB,GACxB,0BAA0B,EAAE,CA+C9B;AAED,sGAAsG;AACtG,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,yBAAyB,EAC/B,OAAO,EAAE,SAAS,0BAA0B,EAAE,GAC7C,OAAO,CAWT;AAqJD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAc5E"}