@ai-matrx/chat 0.3.33 → 0.4.2

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 (129) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/agents/addressing/useAgentHref.js +4 -1
  3. package/dist/agents/api/submit-tool-results.js +11 -1
  4. package/dist/agents/components/ambient-assistant/intelligence-places.js +2 -2
  5. package/dist/agents/components/chat/intelligence-places.js +7 -7
  6. package/dist/agents/components/chat/useCanvasScopedToConversation.js +1 -1
  7. package/dist/agents/components/inputs/smart-input/RunToolPicker.js +7 -13
  8. package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPill.js +3 -2
  9. package/dist/agents/components/inputs/smart-input/composer/useComposerAgent.js +5 -5
  10. package/dist/agents/components/inputs/smart-input/composer/useComposerAgentFilter.js +3 -2
  11. package/dist/agents/components/messages-display/AgentConversationDisplay.js +4 -1
  12. package/dist/agents/components/run-controls/RunConfigOverrides.js +10 -16
  13. package/dist/agents/components/run-controls/panels/shared.d.ts +1 -1
  14. package/dist/agents/components/shared/AgentConversationColumn.js +3 -2
  15. package/dist/agents/components/working-document/workingDocumentSurface.d.ts +1 -1
  16. package/dist/agents/hooks/useAgentModelLabel.js +4 -3
  17. package/dist/agents/hooks/useDiffEnrichment.js +3 -5
  18. package/dist/agents/hooks/useModelControls.d.ts +5 -161
  19. package/dist/agents/identity/model-catalog.d.ts +37 -0
  20. package/dist/agents/identity/model-catalog.js +105 -0
  21. package/dist/agents/redux/agent-definition/selectors.d.ts +237 -237
  22. package/dist/agents/redux/agent-definition/thunks.d.ts +1 -1
  23. package/dist/agents/redux/agent-settings/agentSettingsSlice.d.ts +1 -1
  24. package/dist/agents/redux/agent-settings/agentSettingsSlice.js +4 -6
  25. package/dist/agents/redux/agent-settings/selectors.d.ts +13 -152
  26. package/dist/agents/redux/agent-settings/selectors.js +0 -39
  27. package/dist/agents/redux/agent-settings/useNormalizedControls.d.ts +8 -0
  28. package/dist/agents/redux/agent-settings/useNormalizedControls.js +24 -0
  29. package/dist/agents/redux/agent-shortcut-categories/selectors.d.ts +50 -50
  30. package/dist/agents/redux/agent-shortcuts/selectors.d.ts +147 -147
  31. package/dist/agents/redux/conversation-history/selectors.d.ts +16 -16
  32. package/dist/agents/redux/conversation-list/conversation-list.selectors.d.ts +2 -2
  33. package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.d.ts +54 -54
  34. package/dist/agents/redux/execution-system/context-state/context-state.selectors.d.ts +14 -14
  35. package/dist/agents/redux/execution-system/conversations/conversations.selectors.d.ts +5 -5
  36. package/dist/agents/redux/execution-system/host-conversations/conversation-abilities.d.ts +12 -0
  37. package/dist/agents/redux/execution-system/host-conversations/conversation-abilities.js +25 -0
  38. package/dist/agents/redux/execution-system/host-conversations/host-conversation.thunks.d.ts +50 -0
  39. package/dist/agents/redux/execution-system/host-conversations/host-conversation.thunks.js +367 -0
  40. package/dist/agents/redux/execution-system/host-conversations/host-conversations.selectors.d.ts +28 -0
  41. package/dist/agents/redux/execution-system/host-conversations/host-conversations.selectors.js +41 -0
  42. package/dist/agents/redux/execution-system/host-conversations/host-conversations.slice.d.ts +43 -0
  43. package/dist/agents/redux/execution-system/host-conversations/host-conversations.slice.js +38 -0
  44. package/dist/agents/redux/execution-system/host-conversations/source-registry.d.ts +9 -0
  45. package/dist/agents/redux/execution-system/host-conversations/source-registry.js +15 -0
  46. package/dist/agents/redux/execution-system/host-conversations/useHostConversation.d.ts +4 -0
  47. package/dist/agents/redux/execution-system/host-conversations/useHostConversation.js +24 -0
  48. package/dist/agents/redux/execution-system/instance-context/instance-context.selectors.d.ts +3 -3
  49. package/dist/agents/redux/execution-system/instance-resources/default-remark-durability.d.ts +22 -0
  50. package/dist/agents/redux/execution-system/instance-resources/default-remark-durability.js +164 -0
  51. package/dist/agents/redux/execution-system/instance-resources/instance-resources.selectors.d.ts +8 -8
  52. package/dist/agents/redux/execution-system/instance-ui-state/instance-ui-state.selectors.d.ts +5 -5
  53. package/dist/agents/redux/execution-system/instance-user-input/composer-draft-store.js +20 -0
  54. package/dist/agents/redux/execution-system/instance-user-input/useComposerDraftRestore.js +2 -1
  55. package/dist/agents/redux/execution-system/instance-variable-values/instance-variable-values.selectors.d.ts +7 -7
  56. package/dist/agents/redux/execution-system/messages/messages.selectors.d.ts +1 -1
  57. package/dist/agents/redux/execution-system/observability/observability.selectors.d.ts +7 -7
  58. package/dist/agents/redux/execution-system/observational-memory/observational-memory.selectors.d.ts +1 -1
  59. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.d.ts +14 -14
  60. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.js +2 -1
  61. package/dist/agents/redux/execution-system/thunks/execute-manual-instance.thunk.js +4 -3
  62. package/dist/agents/redux/execution-system/thunks/load-conversation.thunk.js +6 -0
  63. package/dist/agents/redux/execution-system/thunks/load-older-messages.thunk.js +12 -0
  64. package/dist/agents/redux/execution-system/thunks/process-stream.js +5 -3
  65. package/dist/agents/redux/execution-system/thunks/resolve-base-url.js +1 -1
  66. package/dist/agents/redux/execution-system/thunks/smart-execute.thunk.js +43 -0
  67. package/dist/agents/redux/execution-system/utils/continuation-body.d.ts +1 -0
  68. package/dist/agents/redux/execution-system/utils/continuation-body.js +2 -1
  69. package/dist/agents/redux/model-registry.d.ts +6 -4
  70. package/dist/agents/redux/model-registry.js +23 -5
  71. package/dist/agents/redux/proposed-directives/proposedDirectivesSlice.d.ts +1 -1
  72. package/dist/agents/redux/tools/tools.selectors.d.ts +1 -1
  73. package/dist/agents/resources/default-picker-items.d.ts +17 -0
  74. package/dist/agents/resources/default-picker-items.js +48 -0
  75. package/dist/agents/runtime/generation-job.js +4 -7
  76. package/dist/agents/runtime/get-model-capabilities.js +3 -3
  77. package/dist/agents/types/instance.types.d.ts +2 -1
  78. package/dist/agents/ui-first-tools/redux/agent-lists.selectors.d.ts +2 -2
  79. package/dist/cx-chat/components/SsrSidebarChats.js +1 -1
  80. package/dist/cx-chat/components/sidebar/SidebarUserFooter.js +1 -1
  81. package/dist/host/app-identity.d.ts +20 -0
  82. package/dist/host/app-identity.js +21 -0
  83. package/dist/host/bare-host-chrome.d.ts +14 -0
  84. package/dist/host/bare-host-chrome.js +44 -0
  85. package/dist/host/configure.d.ts +9 -1
  86. package/dist/host/configure.js +44 -8
  87. package/dist/host/content-ir-slots.d.ts +5 -1
  88. package/dist/host/content-ir-slots.js +5 -1
  89. package/dist/host/contract.d.ts +39 -2
  90. package/dist/host/db-types.d.ts +375 -10
  91. package/dist/host/defaults/navigation-hooks.d.ts +2 -0
  92. package/dist/host/defaults/navigation-hooks.js +7 -1
  93. package/dist/host/defaults/navigation.d.ts +4 -3
  94. package/dist/host/defaults/navigation.js +38 -7
  95. package/dist/host/defaults/org.d.ts +12 -4
  96. package/dist/host/defaults/org.js +39 -1
  97. package/dist/host/defaults/workspace-gate.d.ts +16 -0
  98. package/dist/host/defaults/workspace-gate.js +88 -0
  99. package/dist/host/diagnostics.d.ts +7 -2
  100. package/dist/host/diagnostics.js +6 -0
  101. package/dist/host/identity.js +2 -1
  102. package/dist/host/index.d.ts +5 -2
  103. package/dist/host/index.js +21 -1
  104. package/dist/host/no-database.d.ts +38 -0
  105. package/dist/host/no-database.js +107 -0
  106. package/dist/host/react.d.ts +1 -0
  107. package/dist/host/react.js +25 -2
  108. package/dist/host/registered-source.js +2 -2
  109. package/dist/host/source.d.ts +109 -0
  110. package/dist/host/source.js +86 -0
  111. package/dist/host/ui-slots.d.ts +8 -8
  112. package/dist/host/ui-slots.js +5 -3
  113. package/dist/mandates/useMandate.js +13 -0
  114. package/dist/public-chat/components/PublicMessageOptionsMenu.js +1 -1
  115. package/dist/store/create-chat-store.d.ts +4 -4
  116. package/dist/store/middlewares.d.ts +5 -5
  117. package/dist/store/slices.d.ts +1 -1
  118. package/dist/store/slices.js +4 -3
  119. package/dist/surfaces/redux/selectors.d.ts +2 -2
  120. package/dist/testing/turn-harness.d.ts +35 -0
  121. package/dist/testing/turn-harness.js +85 -0
  122. package/dist/tool-call-visualization/intelligence-places.js +1 -1
  123. package/dist/tool-call-visualization/redux/selectors.d.ts +1 -1
  124. package/dist/voice-agent/intelligence-places.js +6 -6
  125. package/package.json +9 -6
  126. package/dist/agents/model-registry/modelRegistrySlice.d.ts +0 -691
  127. package/dist/agents/model-registry/modelRegistrySlice.js +0 -574
  128. package/dist/host/model-class.d.ts +0 -33
  129. package/dist/host/model-class.js +0 -21
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The two reads every door and control makes (HOST-OWNED-SOURCE-PLAN §2.3):
3
+ *
4
+ * - `selectHostConversation(id)` — is this conversation carried by a host-owned
5
+ * source? Every db-touching thunk reachable from the conversation column
6
+ * branches on it FIRST (guard: scripts/check-host-source-doors.mjs).
7
+ * - `selectConversationAbilities(id)` — (host has a db) × (source handlers
8
+ * present). Every db-backed control reads it and is ABSENT, never dead.
9
+ */
10
+ import type { ChatRootState } from "../../../../store/root-state.js";
11
+ import type { HostConversationEntry } from "./host-conversations.slice.js";
12
+ export declare function selectHostConversation(conversationId: string | null | undefined): (state: ChatRootState) => HostConversationEntry | null;
13
+ /** Non-curried form for thunks. */
14
+ export declare function isHostConversation(state: ChatRootState, conversationId: string): boolean;
15
+ export interface ConversationAbilities {
16
+ /** Carried by a host-owned source. */
17
+ hosted: boolean;
18
+ /** Edit, fork, delete, pins, flags, annotations, share, pickers, attachments, history rows. */
19
+ database: boolean;
20
+ send: boolean;
21
+ stop: boolean;
22
+ retry: boolean;
23
+ answer: boolean;
24
+ whileBusy: "queue" | "steer" | "refuse";
25
+ }
26
+ /** A database-backed conversation: everything present. */
27
+ export declare const FULL_CONVERSATION_ABILITIES: ConversationAbilities;
28
+ export declare function selectConversationAbilities(conversationId: string | null | undefined): (state: ChatRootState) => ConversationAbilities;
@@ -0,0 +1,41 @@
1
+ function selectHostConversation(conversationId) {
2
+ return (state) => (conversationId ? state.hostConversations?.byConversationId[conversationId] : void 0) ?? null;
3
+ }
4
+ function isHostConversation(state, conversationId) {
5
+ return selectHostConversation(conversationId)(state) !== null;
6
+ }
7
+ const FULL_CONVERSATION_ABILITIES = Object.freeze({
8
+ hosted: false,
9
+ database: true,
10
+ send: true,
11
+ stop: true,
12
+ retry: true,
13
+ answer: true,
14
+ whileBusy: "queue"
15
+ });
16
+ const cache = /* @__PURE__ */ new WeakMap();
17
+ function selectConversationAbilities(conversationId) {
18
+ return (state) => {
19
+ const entry = selectHostConversation(conversationId)(state);
20
+ if (!entry) return FULL_CONVERSATION_ABILITIES;
21
+ const hit = cache.get(entry);
22
+ if (hit) return hit;
23
+ const abilities = Object.freeze({
24
+ hosted: true,
25
+ database: entry.database,
26
+ send: entry.canSend,
27
+ stop: entry.canStop,
28
+ retry: entry.canRetry,
29
+ answer: entry.canAnswer,
30
+ whileBusy: entry.whileBusy
31
+ });
32
+ cache.set(entry, abilities);
33
+ return abilities;
34
+ };
35
+ }
36
+ export {
37
+ FULL_CONVERSATION_ABILITIES,
38
+ isHostConversation,
39
+ selectConversationAbilities,
40
+ selectHostConversation
41
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * hostConversations — which conversations a host-owned message source carries
3
+ * (HOST-OWNED-SOURCE-PLAN §2.3, P28a).
4
+ *
5
+ * Plain data only: the source itself (functions) lives in the non-Redux
6
+ * registry beside this file (`source-registry.ts`), like `abort-registry.ts`.
7
+ * What is here is what selectors need: which source, what it can do (capability
8
+ * by presence), whether its conversations are saved and where, and the
9
+ * composer's held sentence.
10
+ */
11
+ import type { HostPersistence } from "../../../../host/source.js";
12
+ export interface HostConversationEntry {
13
+ sourceId: string;
14
+ whileBusy: "queue" | "steer" | "refuse";
15
+ persistence: HostPersistence;
16
+ /** The host's sentence while the composer waits; null when it does not. */
17
+ held: string | null;
18
+ /** The host's sentence when its history could not be read. */
19
+ unavailable: string | null;
20
+ /** Does the host ALSO have a database (both given)? */
21
+ database: boolean;
22
+ canSend: boolean;
23
+ canStop: boolean;
24
+ canRetry: boolean;
25
+ canAnswer: boolean;
26
+ hasConversationList: boolean;
27
+ }
28
+ export interface HostConversationsState {
29
+ byConversationId: Record<string, HostConversationEntry>;
30
+ }
31
+ export declare const hostConversationBound: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
32
+ conversationId: string;
33
+ entry: HostConversationEntry;
34
+ }, "hostConversations/hostConversationBound">, hostConversationUnbound: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "hostConversations/hostConversationUnbound">, hostConversationHeld: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
35
+ conversationId: string;
36
+ reason: string | null;
37
+ }, "hostConversations/hostConversationHeld">, hostConversationUnavailable: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
38
+ conversationId: string;
39
+ reason: string | null;
40
+ }, "hostConversations/hostConversationUnavailable">;
41
+ export declare const hostConversationsReducer: import("redux").Reducer<HostConversationsState>;
42
+ declare const _default: import("redux").Reducer<HostConversationsState>;
43
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+ const initialState = { byConversationId: {} };
3
+ const hostConversationsSlice = createSlice({
4
+ name: "hostConversations",
5
+ initialState,
6
+ reducers: {
7
+ hostConversationBound(state, action) {
8
+ state.byConversationId[action.payload.conversationId] = action.payload.entry;
9
+ },
10
+ hostConversationUnbound(state, action) {
11
+ delete state.byConversationId[action.payload];
12
+ },
13
+ hostConversationHeld(state, action) {
14
+ const entry = state.byConversationId[action.payload.conversationId];
15
+ if (entry) entry.held = action.payload.reason;
16
+ },
17
+ hostConversationUnavailable(state, action) {
18
+ const entry = state.byConversationId[action.payload.conversationId];
19
+ if (entry) entry.unavailable = action.payload.reason;
20
+ }
21
+ }
22
+ });
23
+ const {
24
+ hostConversationBound,
25
+ hostConversationUnbound,
26
+ hostConversationHeld,
27
+ hostConversationUnavailable
28
+ } = hostConversationsSlice.actions;
29
+ const hostConversationsReducer = hostConversationsSlice.reducer;
30
+ var host_conversations_slice_default = hostConversationsSlice.reducer;
31
+ export {
32
+ host_conversations_slice_default as default,
33
+ hostConversationBound,
34
+ hostConversationHeld,
35
+ hostConversationUnavailable,
36
+ hostConversationUnbound,
37
+ hostConversationsReducer
38
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * conversationId → the host-owned message source carrying it. Functions stay
3
+ * out of Redux state (the same reason `abort-registry.ts` exists); the
4
+ * `hostConversations` slice holds the plain-data half.
5
+ */
6
+ import type { ChatMessageSource } from "../../../../host/source.js";
7
+ export declare function registerHostSource(conversationId: string, source: ChatMessageSource): void;
8
+ export declare function unregisterHostSource(conversationId: string, source?: ChatMessageSource): void;
9
+ export declare function getHostSource(conversationId: string): ChatMessageSource | null;
@@ -0,0 +1,15 @@
1
+ const sources = /* @__PURE__ */ new Map();
2
+ function registerHostSource(conversationId, source) {
3
+ sources.set(conversationId, source);
4
+ }
5
+ function unregisterHostSource(conversationId, source) {
6
+ if (!source || sources.get(conversationId) === source) sources.delete(conversationId);
7
+ }
8
+ function getHostSource(conversationId) {
9
+ return sources.get(conversationId) ?? null;
10
+ }
11
+ export {
12
+ getHostSource,
13
+ registerHostSource,
14
+ unregisterHostSource
15
+ };
@@ -0,0 +1,4 @@
1
+ import type { ChatMessageSource } from "../../../../host/source.js";
2
+ export declare function useHostConversation(source: ChatMessageSource | null | undefined, conversationId: string | null | undefined, options?: {
3
+ surfaceKey?: string;
4
+ }): void;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { useAppDispatch, useAppStore } from "../../../../store/hooks.js";
4
+ import { useChatHost } from "../../../../host/react.js";
5
+ import { bindHostConversation } from "./host-conversation.thunks.js";
6
+ function useHostConversation(source, conversationId, options = {}) {
7
+ const dispatch = useAppDispatch();
8
+ const store = useAppStore();
9
+ const host = useChatHost();
10
+ const bound = source ?? host.source;
11
+ const { surfaceKey } = options;
12
+ useEffect(() => {
13
+ if (!bound || !conversationId) return;
14
+ return bindHostConversation(dispatch, () => store.getState(), {
15
+ conversationId,
16
+ source: bound,
17
+ database: host.hasDatabase,
18
+ surfaceKey
19
+ });
20
+ }, [bound, conversationId, dispatch, store, host.hasDatabase, surfaceKey]);
21
+ }
22
+ export {
23
+ useHostConversation
24
+ };
@@ -42,8 +42,8 @@ export declare const selectInstanceContextEntries: (conversationId: string) => (
42
42
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
43
43
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
44
44
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
45
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
46
45
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
46
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
47
47
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => InstanceContextEntry[]) & {
48
48
  clearCache: () => void;
49
49
  resultsCount: () => number;
@@ -111,8 +111,8 @@ export declare const selectSlotMatchedContext: (conversationId: string) => ((sta
111
111
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
112
112
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
113
113
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
114
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
115
114
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
115
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
116
116
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => InstanceContextEntry[]) & {
117
117
  clearCache: () => void;
118
118
  resultsCount: () => number;
@@ -179,8 +179,8 @@ export declare const selectAdHocContext: (conversationId: string) => ((state: {
179
179
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
180
180
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
181
181
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
182
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
183
182
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
183
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
184
184
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => InstanceContextEntry[]) & {
185
185
  clearCache: () => void;
186
186
  resultsCount: () => number;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * default-remark-durability — how a bare host keeps UNSENT chips (a comment, an edit, a choice)
3
+ * server-side, so they survive a reload and ride the next send.
4
+ *
5
+ * The same table and doors the main frontend's richer port uses: `platform.block_states`, kind
6
+ * `remark`, block key `remark:<chip key>`, through `block_state_set` / `block_state_list_staged` /
7
+ * `block_state_dismiss_chip` over `host.db`. A chip is due by the server's rule
8
+ * (state_version > sent_version, not dismissed at that version) and carries `blockStateRef` so the
9
+ * server marks it sent with the message. A chip belongs to the conversation it was staged into.
10
+ * Registered by `<ChatProvider>` for a private store when the host registered no port of its own.
11
+ * Not in this default: the live feed from another tab (the next mount lists again).
12
+ */
13
+ import type { ChatDb } from "../../../../host/contract.js";
14
+ import type { ChatDispatch } from "../../../../store/root-state.js";
15
+ import { type RemarkDurability } from "./remarks.js";
16
+ export interface DefaultRemarkDurabilityOptions {
17
+ db: ChatDb;
18
+ dispatch: ChatDispatch;
19
+ /** A write that failed: say so (the host's notify + console). */
20
+ onFailure: (message: string, error: unknown) => void;
21
+ }
22
+ export declare function createDbRemarkDurability({ db, dispatch, onFailure }: DefaultRemarkDurabilityOptions): RemarkDurability;
@@ -0,0 +1,164 @@
1
+ import { durableRecordId } from "@ai-matrx/kit/ids";
2
+ import {
3
+ attachRemarkRef,
4
+ readStoredRemarks,
5
+ restageRemarks,
6
+ unstageRemark
7
+ } from "./remarks.js";
8
+ const DEBOUNCE_MS = 800;
9
+ function rowOf(value) {
10
+ if (!value || typeof value !== "object") return null;
11
+ const r = value;
12
+ if (typeof r.id !== "string" || typeof r.state_version !== "number") return null;
13
+ return {
14
+ id: r.id,
15
+ kind: String(r.kind ?? ""),
16
+ state_version: r.state_version,
17
+ sent_version: typeof r.sent_version === "number" ? r.sent_version : 0,
18
+ state: r.state && typeof r.state === "object" ? r.state : {},
19
+ metadata: r.metadata && typeof r.metadata === "object" ? r.metadata : null
20
+ };
21
+ }
22
+ function isDue(row) {
23
+ if (row.state_version <= row.sent_version) return false;
24
+ const dismissed = row.metadata?.chip_dismissed_version;
25
+ return !(typeof dismissed === "number" && dismissed >= row.state_version);
26
+ }
27
+ function entityOf(item) {
28
+ const messageId = durableRecordId(item.target.messageId);
29
+ if (messageId) return { entityType: "message", entityId: messageId };
30
+ const record = item.target.record;
31
+ if (record?.token && record.id) return { entityType: record.token, entityId: record.id };
32
+ return null;
33
+ }
34
+ function stripRef(item) {
35
+ const { blockStateRef: _ref, ...rest } = item;
36
+ return rest;
37
+ }
38
+ function createDbRemarkDurability({ db, dispatch, onFailure }) {
39
+ const rpc = (name, args) => db.rpc(name, args);
40
+ const slots = /* @__PURE__ */ new Map();
41
+ const restored = /* @__PURE__ */ new Set();
42
+ const restoring = /* @__PURE__ */ new Set();
43
+ const idOf = (conversationId, key) => `${conversationId}\0${key}`;
44
+ const slotFor = (conversationId, key) => {
45
+ const id = idOf(conversationId, key);
46
+ let slot = slots.get(id);
47
+ if (!slot) {
48
+ slot = { timer: null, chain: Promise.resolve(), inFlight: 0, rowId: null, latest: null };
49
+ slots.set(id, slot);
50
+ }
51
+ return slot;
52
+ };
53
+ const slotsOf = (conversationId) => [...slots.entries()].filter(([id]) => id.startsWith(`${conversationId}\0`));
54
+ const write = (conversationId, key, slot) => {
55
+ const latest = slot.latest;
56
+ if (!latest) return;
57
+ const entity = entityOf(latest.item);
58
+ if (!entity) {
59
+ console.warn("[remarks] a chip with no answer or record to belong to is not kept:", key);
60
+ return;
61
+ }
62
+ slot.inFlight += 1;
63
+ slot.chain = slot.chain.then(async () => {
64
+ try {
65
+ const { data, error } = await rpc("block_state_set", {
66
+ p_entity_type: entity.entityType,
67
+ p_entity_id: entity.entityId,
68
+ p_block_key: `remark:${key}`,
69
+ p_kind: "remark",
70
+ p_scope: "viewer",
71
+ p_patch: {
72
+ remark: stripRef(latest.item),
73
+ coalesceKey: latest.coalesceKey,
74
+ stagedIn: latest.conversationId,
75
+ resourceId: latest.resourceId
76
+ },
77
+ p_client_request_id: crypto.randomUUID()
78
+ });
79
+ const row = error ? null : rowOf(data);
80
+ if (!row) throw new Error(error?.message ?? "The server returned no saved state.");
81
+ slot.rowId = row.id;
82
+ dispatch(attachRemarkRef(latest.conversationId, latest.resourceId, { id: row.id, stateVersion: row.state_version }));
83
+ } catch (error) {
84
+ onFailure("Your note on this answer is not saved. Try again.", error);
85
+ } finally {
86
+ slot.inFlight -= 1;
87
+ }
88
+ });
89
+ };
90
+ return {
91
+ save(conversationId, resourceId, coalesceKey, item) {
92
+ const key = coalesceKey ?? resourceId;
93
+ const slot = slotFor(conversationId, key);
94
+ slot.latest = { conversationId, resourceId, coalesceKey, item };
95
+ if (slot.timer) clearTimeout(slot.timer);
96
+ slot.timer = setTimeout(() => {
97
+ slot.timer = null;
98
+ write(conversationId, key, slot);
99
+ }, DEBOUNCE_MS);
100
+ },
101
+ retire(conversationId, resourceId, coalesceKey, item) {
102
+ const slot = slotFor(conversationId, coalesceKey ?? resourceId);
103
+ if (slot.timer) {
104
+ clearTimeout(slot.timer);
105
+ slot.timer = null;
106
+ }
107
+ slot.latest = null;
108
+ slot.chain = slot.chain.then(async () => {
109
+ const rowId = slot.rowId ?? item.blockStateRef?.id ?? null;
110
+ if (!rowId) return;
111
+ const { error } = await rpc("block_state_dismiss_chip", { p_id: rowId });
112
+ if (error) onFailure("Your note on this answer is not saved. Try again.", error);
113
+ });
114
+ },
115
+ hasPending(conversationId) {
116
+ return slotsOf(conversationId).some(([, slot]) => slot.timer !== null || slot.inFlight > 0);
117
+ },
118
+ async flush(conversationId) {
119
+ for (const [id, slot] of slotsOf(conversationId)) {
120
+ if (!slot.timer) continue;
121
+ clearTimeout(slot.timer);
122
+ slot.timer = null;
123
+ write(conversationId, id.slice(conversationId.length + 1), slot);
124
+ }
125
+ await Promise.all(slotsOf(conversationId).map(([, slot]) => slot.chain));
126
+ },
127
+ restore(conversationId) {
128
+ if (restored.has(conversationId) || restoring.has(conversationId)) return;
129
+ restoring.add(conversationId);
130
+ void (async () => {
131
+ try {
132
+ const { data, error } = await rpc("block_state_list_staged", { p_conversation_id: conversationId });
133
+ if (error) throw new Error(error.message);
134
+ restored.add(conversationId);
135
+ const rows = (Array.isArray(data) ? data : []).flatMap((entry) => {
136
+ const row = rowOf(entry);
137
+ return row ? [row] : [];
138
+ });
139
+ const mine = rows.filter((r) => r.kind === "remark" && r.state.stagedIn === conversationId && r.state.remark && typeof r.state.remark === "object");
140
+ for (const r of mine) {
141
+ if (!isDue(r) && typeof r.state.coalesceKey === "string") {
142
+ dispatch(unstageRemark(conversationId, r.state.coalesceKey, { retire: false }));
143
+ }
144
+ }
145
+ const stored = readStoredRemarks(
146
+ mine.filter(isDue).map((r) => ({
147
+ resourceId: typeof r.state.resourceId === "string" ? r.state.resourceId : r.id,
148
+ coalesceKey: typeof r.state.coalesceKey === "string" ? r.state.coalesceKey : null,
149
+ item: { ...r.state.remark, blockStateRef: { id: r.id, stateVersion: r.state_version } }
150
+ }))
151
+ );
152
+ if (stored.length > 0) dispatch(restageRemarks(conversationId, stored));
153
+ } catch (error) {
154
+ console.error("[remarks] restoring unsent chips failed:", error);
155
+ } finally {
156
+ restoring.delete(conversationId);
157
+ }
158
+ })();
159
+ }
160
+ };
161
+ }
162
+ export {
163
+ createDbRemarkDurability
164
+ };
@@ -67,8 +67,8 @@ export declare const selectInstanceResources: (conversationId: string) => ((stat
67
67
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
68
68
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
69
69
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
70
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
71
70
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
71
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
72
72
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ManagedResource[]) & {
73
73
  clearCache: () => void;
74
74
  resultsCount: () => number;
@@ -148,8 +148,8 @@ export declare const selectReadyResources: (conversationId: string) => ((state:
148
148
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
149
149
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
150
150
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
151
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
152
151
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
152
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
153
153
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ManagedResource[]) & {
154
154
  clearCache: () => void;
155
155
  resultsCount: () => number;
@@ -216,8 +216,8 @@ export declare const selectPendingResources: (conversationId: string) => ((state
216
216
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
217
217
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
218
218
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
219
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
220
219
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
220
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
221
221
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ManagedResource[]) & {
222
222
  clearCache: () => void;
223
223
  resultsCount: () => number;
@@ -291,8 +291,8 @@ export declare const selectResourcePayloads: (conversationId: string) => ((state
291
291
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
292
292
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
293
293
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
294
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
295
294
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
295
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
296
296
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ({
297
297
  metadata?: {
298
298
  [key: string]: unknown;
@@ -1807,8 +1807,8 @@ export declare const selectResourceContextPayload: (conversationId: string) => (
1807
1807
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
1808
1808
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
1809
1809
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
1810
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
1811
1810
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
1811
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
1812
1812
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => Record<string, unknown> | undefined) & {
1813
1813
  clearCache: () => void;
1814
1814
  resultsCount: () => number;
@@ -1877,8 +1877,8 @@ export declare const selectEditorResources: (conversationId: string) => ((state:
1877
1877
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
1878
1878
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
1879
1879
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
1880
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
1881
1880
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
1881
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
1882
1882
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ManagedResource[]) & {
1883
1883
  clearCache: () => void;
1884
1884
  resultsCount: () => number;
@@ -1946,8 +1946,8 @@ export declare const selectEditorResourceXml: (conversationId: string) => ((stat
1946
1946
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
1947
1947
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
1948
1948
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
1949
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
1950
1949
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
1950
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
1951
1951
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => string) & {
1952
1952
  clearCache: () => void;
1953
1953
  resultsCount: () => number;
@@ -2002,8 +2002,8 @@ export declare const selectEditorResourceXml: (conversationId: string) => ((stat
2002
2002
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
2003
2003
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
2004
2004
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
2005
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
2006
2005
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
2006
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
2007
2007
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => ManagedResource[]) & {
2008
2008
  clearCache: () => void;
2009
2009
  resultsCount: () => number;
@@ -191,8 +191,8 @@ export declare const selectInstanceIdsByDisplayMode: (displayMode: ResultDisplay
191
191
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
192
192
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
193
193
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
194
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
195
194
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
195
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
196
196
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => string[] | undefined) & {
197
197
  clearCache: () => void;
198
198
  resultsCount: () => number;
@@ -256,8 +256,8 @@ export declare const selectModalInstanceIds: ((state: {
256
256
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
257
257
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
258
258
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
259
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
260
259
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
260
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
261
261
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => string[] | undefined) & {
262
262
  clearCache: () => void;
263
263
  resultsCount: () => number;
@@ -321,8 +321,8 @@ export declare const selectPersistentInstanceIds: ((state: {
321
321
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
322
322
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
323
323
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
324
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
325
324
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
325
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
326
326
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => string[] | undefined) & {
327
327
  clearCache: () => void;
328
328
  resultsCount: () => number;
@@ -386,8 +386,8 @@ export declare const selectAllUIStateConversationIds: ((state: {
386
386
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
387
387
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
388
388
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
389
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
390
389
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
390
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
391
391
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => string[]) & {
392
392
  clearCache: () => void;
393
393
  resultsCount: () => number;
@@ -456,8 +456,8 @@ export declare const selectUIStateInstancesByAgent: ((state: {
456
456
  proposedDirectives: import("../../proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
457
457
  agentSettings: import("../../agent-settings/types.js").AgentSettingsState;
458
458
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
459
- modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
460
459
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
460
+ hostConversations: import("../host-conversations/host-conversations.slice.js").HostConversationsState;
461
461
  } & import("../../../../store/root-state.js").ChatHostReadSlices) => InstanceAgentGroup[]) & {
462
462
  clearCache: () => void;
463
463
  resultsCount: () => number;
@@ -1,9 +1,29 @@
1
+ import { chatHostHasDatabase, getChatHost, isChatHostConfigured } from "../../../../host/configure.js";
1
2
  import { DRAFT_TTL_MS } from "@ai-matrx/kit/drafts";
2
3
  const PREFIX = "matrx.composer-draft.";
3
4
  const ALIAS_PREFIX = "matrx.composer-draft.surface.";
4
5
  const COMPOSER_DRAFT_MIN_CHARS = 2;
5
6
  let swept = false;
7
+ function hostPrefsStorage() {
8
+ if (chatHostHasDatabase() || !isChatHostConfigured()) return null;
9
+ const prefs = getChatHost().prefs;
10
+ const keys = () => Object.keys(prefs.snapshot?.() ?? {});
11
+ return {
12
+ get length() {
13
+ return keys().length;
14
+ },
15
+ key: (index) => keys()[index] ?? null,
16
+ getItem: (key) => prefs.get(key),
17
+ setItem: (key, value) => prefs.set(key, value),
18
+ removeItem: (key) => prefs.remove(key),
19
+ clear: () => {
20
+ for (const key of keys()) if (key.startsWith(PREFIX)) prefs.remove(key);
21
+ }
22
+ };
23
+ }
6
24
  function storage() {
25
+ const hosted = hostPrefsStorage();
26
+ if (hosted) return hosted;
7
27
  try {
8
28
  if (typeof window === "undefined") return null;
9
29
  const s = window.localStorage;
@@ -14,6 +14,7 @@ import {
14
14
  isDraftRestoreEnabled
15
15
  } from "./composer-draft.middleware.js";
16
16
  import { selectUserId } from "../../../../host/identity.js";
17
+ import { chatHostHasDatabase } from "../../../../host/configure.js";
17
18
  import {
18
19
  selectUserInputEntryExists,
19
20
  selectUserInputText
@@ -48,7 +49,7 @@ function useComposerDraftRestore(conversationId, alias) {
48
49
  setRestoredValue(null);
49
50
  setStorageAvailable(isComposerDraftStorageAvailable());
50
51
  if (!enabled) return;
51
- restoreComposerRemarks(conversationId);
52
+ if (chatHostHasDatabase()) restoreComposerRemarks(conversationId);
52
53
  const token = peekComposerDraft(conversationId, liveAlias, ownerId);
53
54
  if (!token) return;
54
55
  if (dispatch(applyComposerDraft(token)) === "restored") {