@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
@@ -18,6 +18,44 @@ function createNoPickerOrg(notify, diagnostics) {
18
18
  }
19
19
  };
20
20
  }
21
+ const CHAT_ACTIVE_ORG_STORAGE_KEY = "matrx-chat:active-organization";
22
+ function readStored() {
23
+ try {
24
+ if (typeof window === "undefined" || !window.localStorage) return null;
25
+ const raw = window.localStorage.getItem(CHAT_ACTIVE_ORG_STORAGE_KEY);
26
+ if (!raw) return null;
27
+ const parsed = JSON.parse(raw);
28
+ return typeof parsed.id === "string" ? { id: parsed.id, name: parsed.name ?? null } : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function createStoredOrg(notify, diagnostics) {
34
+ const refuse = createNoPickerOrg(notify, diagnostics);
35
+ let active = readStored();
36
+ const listeners = /* @__PURE__ */ new Set();
37
+ return {
38
+ active: () => active,
39
+ subscribe(listener) {
40
+ listeners.add(listener);
41
+ return () => listeners.delete(listener);
42
+ },
43
+ require(reason, options) {
44
+ if (active) return Promise.resolve(active.id);
45
+ return refuse.require(reason, options);
46
+ },
47
+ choose(org) {
48
+ active = { id: org.id, name: org.name };
49
+ try {
50
+ window.localStorage?.setItem(CHAT_ACTIVE_ORG_STORAGE_KEY, JSON.stringify(active));
51
+ } catch {
52
+ }
53
+ for (const listener of [...listeners]) listener();
54
+ }
55
+ };
56
+ }
21
57
  export {
22
- createNoPickerOrg
58
+ CHAT_ACTIVE_ORG_STORAGE_KEY,
59
+ createNoPickerOrg,
60
+ createStoredOrg
23
61
  };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The bare-host `WorkspaceGate`: when a surface is blocked on "no organization chosen",
3
+ * the same area lists the organizations the person belongs to (read over `host.db`) and
4
+ * picking one makes it active (`host.org.choose`). Nothing is picked for the person.
5
+ * A host with its own picker (matrx-frontend) registers its own gate.
6
+ */
7
+ import { type ReactNode } from "react";
8
+ export interface DefaultWorkspaceGateProps {
9
+ blocked: boolean;
10
+ sentence: string;
11
+ description?: string;
12
+ children?: ReactNode;
13
+ compact?: boolean;
14
+ className?: string;
15
+ }
16
+ export declare function DefaultWorkspaceGate({ blocked, sentence, description, children, className }: DefaultWorkspaceGateProps): import("react").JSX.Element;
@@ -0,0 +1,88 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState, useSyncExternalStore } from "react";
4
+ import { useChatHost } from "../react.js";
5
+ import { invalidateMandateCache } from "../../mandates/service.js";
6
+ const PAGE = 500;
7
+ const CHUNK = 100;
8
+ function DefaultWorkspaceGate({ blocked, sentence, description, children, className }) {
9
+ const host = useChatHost();
10
+ const active = useSyncExternalStore(host.org.subscribe, host.org.active, () => null);
11
+ if (!blocked || active || !host.org.choose) return /* @__PURE__ */ jsx(Fragment, { children });
12
+ return /* @__PURE__ */ jsx(WorkspacePicker, { sentence, description, className });
13
+ }
14
+ function WorkspacePicker({ sentence, description, className }) {
15
+ const host = useChatHost();
16
+ const [orgs, setOrgs] = useState(null);
17
+ const [error, setError] = useState(null);
18
+ const [filter, setFilter] = useState("");
19
+ useEffect(() => {
20
+ let cancelled = false;
21
+ void (async () => {
22
+ const db = host.db;
23
+ const ids = [];
24
+ for (let from = 0; ; from += PAGE) {
25
+ const { data, error: e } = await db.rpc("mbr_for_user", { p_container_type: "organization" }).order("id", { ascending: true }).range(from, from + PAGE - 1);
26
+ if (e) throw new Error(e.message);
27
+ const page = Array.isArray(data) ? data : [];
28
+ ids.push(...page.map((row) => row.container_id));
29
+ if (page.length < PAGE) break;
30
+ }
31
+ const found = [];
32
+ for (let i = 0; i < ids.length; i += CHUNK) {
33
+ const { data, error: e } = await db.schema("iam").from("organizations").select("id,name").in("id", ids.slice(i, i + CHUNK)).is("archived_at", null);
34
+ if (e) throw new Error(e.message);
35
+ found.push(...data ?? []);
36
+ }
37
+ found.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
38
+ if (!cancelled) setOrgs(found);
39
+ })().catch((e) => {
40
+ if (cancelled) return;
41
+ const message = e instanceof Error ? e.message : String(e);
42
+ host.diagnostics.capture(e, { area: "org", code: "workspace-list-failed" });
43
+ setError(message);
44
+ });
45
+ return () => {
46
+ cancelled = true;
47
+ };
48
+ }, [host]);
49
+ const shown = useMemo(() => {
50
+ const q = filter.trim().toLowerCase();
51
+ return (orgs ?? []).filter((o) => !q || (o.name ?? "").toLowerCase().includes(q)).slice(0, 50);
52
+ }, [orgs, filter]);
53
+ const choose = (org) => {
54
+ host.org.choose?.(org);
55
+ invalidateMandateCache();
56
+ };
57
+ return /* @__PURE__ */ jsx("div", { "data-testid": "workspace-gate", className: className ?? "flex h-full min-h-0 w-full flex-col items-center overflow-y-auto p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-2", children: [
58
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: sentence }),
59
+ description ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: description }) : null,
60
+ error ? /* @__PURE__ */ jsxs("p", { className: "text-xs text-destructive", children: [
61
+ "Couldn't list your organizations: ",
62
+ error
63
+ ] }) : orgs === null ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Loading your organizations\u2026" }) : orgs.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "You are not a member of any organization." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
64
+ orgs.length > 8 ? /* @__PURE__ */ jsx(
65
+ "input",
66
+ {
67
+ value: filter,
68
+ onChange: (e) => setFilter(e.target.value),
69
+ placeholder: "Find an organization",
70
+ className: "w-full rounded-md border border-border bg-background px-2 py-1 text-sm"
71
+ }
72
+ ) : null,
73
+ /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border rounded-md border border-border", children: shown.map((org) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
74
+ "button",
75
+ {
76
+ type: "button",
77
+ "data-workspace-choice": org.id,
78
+ onClick: () => choose(org),
79
+ className: "w-full px-3 py-2 text-left text-sm hover:bg-muted",
80
+ children: org.name ?? org.id
81
+ }
82
+ ) }, org.id)) })
83
+ ] })
84
+ ] }) });
85
+ }
86
+ export {
87
+ DefaultWorkspaceGate
88
+ };
@@ -81,8 +81,13 @@ export interface StreamClientErrorInput {
81
81
  export declare function captureStreamClientError(input: StreamClientErrorInput): void;
82
82
  /** Test-only: drop held entries and restart local ids. */
83
83
  export declare function _resetDiagnosticsForTests(): void;
84
+ /** The one degradation that is NOT a stand-in: the registration is missing and the call throws. */
85
+ export declare const SLOT_CANNOT_RUN = "it cannot run";
84
86
  /**
85
- * A host registration (UI slot, usage gate, model-class hooks) was never made, so a stand-in
86
- * is running: say so ONCE, to the console and the host's diagnostics port (Law 4).
87
+ * A host registration (UI slot, usage gate, model-class hooks) was never made.
88
+ *
89
+ * A stand-in is an OPTIONAL enhancement the host may add: it announces itself ONCE as a quiet
90
+ * console info line and nothing else (Law 4: announced, not an error). A registration the package
91
+ * CANNOT run without (`SLOT_CANNOT_RUN`) is an error: console warning + the host's diagnostics.
87
92
  */
88
93
  export declare function reportUnregisteredHostSlot(name: string, degraded: string): void;
@@ -146,8 +146,13 @@ function _resetDiagnosticsForTests() {
146
146
  early = [];
147
147
  localIds = 0;
148
148
  }
149
+ const SLOT_CANNOT_RUN = "it cannot run";
149
150
  function reportUnregisteredHostSlot(name, degraded) {
150
151
  const message = `The host registered no "${name}" for the chat package, so ${degraded}.`;
152
+ if (degraded !== SLOT_CANNOT_RUN) {
153
+ announceOnce(`chat-host-slot:${name}`, message, "info");
154
+ return;
155
+ }
151
156
  if (!announceOnce(`chat-host-slot:${name}`, message)) return;
152
157
  captureError({
153
158
  source: "surface-registration",
@@ -162,6 +167,7 @@ function reportUnregisteredHostSlot(name, degraded) {
162
167
  export {
163
168
  EARLY_DIAGNOSTICS_LIMIT,
164
169
  RecordUnavailableError,
170
+ SLOT_CANNOT_RUN,
165
171
  _resetDiagnosticsForTests,
166
172
  captureError,
167
173
  captureReactRenderError,
@@ -1,5 +1,5 @@
1
1
  import { SIGNED_OUT_IDENTITY } from "./defaults/identity.js";
2
- import { getChatHost } from "./configure.js";
2
+ import { chatHostHasDatabase, getChatHost } from "./configure.js";
3
3
  import { announceOnce } from "./errors.js";
4
4
  import { getStoreSingleton } from "../store/store-singleton.js";
5
5
  function identityOf(state) {
@@ -41,6 +41,7 @@ function requireUserId() {
41
41
  return id;
42
42
  }
43
43
  async function hasBrowserSession() {
44
+ if (!chatHostHasDatabase()) return false;
44
45
  let db;
45
46
  try {
46
47
  db = getChatHost().db;
@@ -2,11 +2,12 @@
2
2
  * @ai-matrx/chat/host — the host contract (no React). React door: `@ai-matrx/chat/host/react`.
3
3
  */
4
4
  export * from "./contract.js";
5
- export { configureChat, getChatHost, isChatHostConfigured, resolveChatHost, _resetChatHostForTests, } from "./configure.js";
5
+ export { configureChat, DEFAULT_CHAT_APP, getChatHost, isChatHostConfigured, resolveChatHost, _resetChatHostForTests, } from "./configure.js";
6
+ export { attributionForSend, currentChatApp, type WireAttribution } from "./app-identity.js";
6
7
  export { ChatHostInvalidError, ChatHostNotConfiguredError, ChatOrganizationRequiredError, } from "./errors.js";
7
8
  export { createLogClientErrorDiagnostics, isChatSourceApp, CHAT_SOURCE_FEATURE, DIAGNOSTICS_FLUSH_DELAY_MS, DIAGNOSTICS_MAX_PER_FLUSH, } from "./defaults/diagnostics.js";
8
9
  export { createDbIdentity, SIGNED_OUT_IDENTITY } from "./defaults/identity.js";
9
- export { createNoPickerOrg } from "./defaults/org.js";
10
+ export { createNoPickerOrg, createStoredOrg, CHAT_ACTIVE_ORG_STORAGE_KEY } from "./defaults/org.js";
10
11
  export { createDefaultServer, DEFAULT_CHAT_SERVER_URL, } from "./defaults/server.js";
11
12
  export { createDomNotifier } from "./defaults/notify.js";
12
13
  export { createWebPrefs, CHAT_PREFS_PREFIX } from "./defaults/prefs.js";
@@ -21,3 +22,5 @@ export { createUnhostedCanvas, UNHOSTED_CANVAS_VIEW } from "./defaults/canvas.js
21
22
  export { DEFAULT_CHAT_ROUTES } from "./configure.js";
22
23
  export { createClient, getClaimsUser, schedulerDb, supabase, type ChatClaimsUser, type ClaimsCapableClient, } from "./db.js";
23
24
  export type { ChatDatabase } from "./db-types.js";
25
+ export { ChatNoDatabaseError, NO_DATABASE_CODE_PREFIX, createNoDatabaseStandIn, isChatNoDatabaseError, isNoDatabase, } from "./no-database.js";
26
+ export * from "./source.js";
@@ -1,11 +1,13 @@
1
1
  export * from "./contract.js";
2
2
  import {
3
3
  configureChat,
4
+ DEFAULT_CHAT_APP,
4
5
  getChatHost,
5
6
  isChatHostConfigured,
6
7
  resolveChatHost,
7
8
  _resetChatHostForTests
8
9
  } from "./configure.js";
10
+ import { attributionForSend, currentChatApp } from "./app-identity.js";
9
11
  import {
10
12
  ChatHostInvalidError,
11
13
  ChatHostNotConfiguredError,
@@ -19,7 +21,7 @@ import {
19
21
  DIAGNOSTICS_MAX_PER_FLUSH
20
22
  } from "./defaults/diagnostics.js";
21
23
  import { createDbIdentity, SIGNED_OUT_IDENTITY } from "./defaults/identity.js";
22
- import { createNoPickerOrg } from "./defaults/org.js";
24
+ import { createNoPickerOrg, createStoredOrg, CHAT_ACTIVE_ORG_STORAGE_KEY } from "./defaults/org.js";
23
25
  import {
24
26
  createDefaultServer,
25
27
  DEFAULT_CHAT_SERVER_URL
@@ -45,23 +47,36 @@ import {
45
47
  schedulerDb,
46
48
  supabase
47
49
  } from "./db.js";
50
+ import {
51
+ ChatNoDatabaseError,
52
+ NO_DATABASE_CODE_PREFIX,
53
+ createNoDatabaseStandIn,
54
+ isChatNoDatabaseError,
55
+ isNoDatabase
56
+ } from "./no-database.js";
57
+ export * from "./source.js";
48
58
  export {
59
+ CHAT_ACTIVE_ORG_STORAGE_KEY,
49
60
  CHAT_PREFS_PREFIX,
50
61
  CHAT_SOURCE_FEATURE,
51
62
  CHAT_WINDOWS,
52
63
  CHAT_WINDOW_IDS,
53
64
  ChatHostInvalidError,
54
65
  ChatHostNotConfiguredError,
66
+ ChatNoDatabaseError,
55
67
  ChatOrganizationRequiredError,
68
+ DEFAULT_CHAT_APP,
56
69
  DEFAULT_CHAT_ROUTES,
57
70
  DEFAULT_CHAT_SERVER_URL,
58
71
  DEFAULT_CHROME_STYLES,
59
72
  DEFAULT_WINDOW_INSTANCE_ID,
60
73
  DIAGNOSTICS_FLUSH_DELAY_MS,
61
74
  DIAGNOSTICS_MAX_PER_FLUSH,
75
+ NO_DATABASE_CODE_PREFIX,
62
76
  SIGNED_OUT_IDENTITY,
63
77
  UNHOSTED_CANVAS_VIEW,
64
78
  _resetChatHostForTests,
79
+ attributionForSend,
65
80
  configureChat,
66
81
  createClient,
67
82
  createDbCatalogGetter,
@@ -71,16 +86,21 @@ export {
71
86
  createDefaultServer,
72
87
  createDomNotifier,
73
88
  createLogClientErrorDiagnostics,
89
+ createNoDatabaseStandIn,
74
90
  createNoPickerOrg,
91
+ createStoredOrg,
75
92
  createUnhostedCanvas,
76
93
  createUnhostedWindows,
77
94
  createWebPrefs,
78
95
  createWindowNavigation,
96
+ currentChatApp,
79
97
  getChatHost,
80
98
  getClaimsUser,
81
99
  isChatHostConfigured,
100
+ isChatNoDatabaseError,
82
101
  isChatSourceApp,
83
102
  isChatWindowId,
103
+ isNoDatabase,
84
104
  resolveChatHost,
85
105
  schedulerDb,
86
106
  supabase
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The no-database stand-in (HOST-OWNED-SOURCE-PLAN §2.3, P28a).
3
+ *
4
+ * A host that passes a message `source` and no `db` still gets a `db` port — this stand-in. Every
5
+ * use of it throws `ChatNoDatabaseError` naming the feature that reached for a database, and is
6
+ * reported to diagnostics ONCE per feature (Law 4: a stand-in announces itself). The engine's
7
+ * doors branch before they reach it (G-DOOR, `scripts/check-host-source-doors.mjs`); the forcing
8
+ * test (`host-source-runs-a-turn.test.tsx`) mounts the real column over it and fails on any report.
9
+ *
10
+ * Pure: no React, no Redux, no `window` at import.
11
+ */
12
+ import type { ChatDb, ChatDiagnosticsPort } from "./contract.js";
13
+ /** Diagnostics `code` prefix every stand-in report carries: `no-database:<feature>`. */
14
+ export declare const NO_DATABASE_CODE_PREFIX = "no-database:";
15
+ export declare class ChatNoDatabaseError extends Error {
16
+ readonly feature: string;
17
+ readonly code = "chat-no-database";
18
+ constructor(feature: string);
19
+ }
20
+ export declare function isChatNoDatabaseError(error: unknown): error is ChatNoDatabaseError;
21
+ /** True when `db` is the stand-in (the host has no database). */
22
+ export declare function isNoDatabase(db: unknown): boolean;
23
+ /**
24
+ * The `db` for a host with none. `report(feature)` is called once per feature, then the access
25
+ * throws. Reading `then` or a symbol answers `undefined`, so the stand-in is never a thenable and
26
+ * survives `await`, logging and React dev tooling.
27
+ */
28
+ export declare function createNoDatabaseStandIn(report: (feature: string) => void): ChatDb;
29
+ /** Diagnostics for a host with no database: the console, each class said once. */
30
+ export declare function createConsoleDiagnostics(): ChatDiagnosticsPort;
31
+ /**
32
+ * The server client for a host with no database and no `server` port: every call refuses, named
33
+ * `server.<call>`, through the same once-per-feature report (the platform server needs a signed-in
34
+ * caller this host does not have).
35
+ */
36
+ /** Members of the server client that never leave the page: the stream parser and state readers. */
37
+ export declare function isLocalServerMember(key: string): boolean;
38
+ export declare function createNoServerApi(report: (feature: string) => void, local?: Record<string, unknown>): unknown;
@@ -0,0 +1,107 @@
1
+ import { announceOnce } from "./errors.js";
2
+ const NO_DATABASE_CODE_PREFIX = "no-database:";
3
+ class ChatNoDatabaseError extends Error {
4
+ constructor(feature) {
5
+ super(
6
+ `"${feature}" needs a database, and this chat host has none (it was given a message source). The control that reached it should be absent here; pass \`db\` to the chat host to enable it.`
7
+ );
8
+ this.feature = feature;
9
+ this.name = "ChatNoDatabaseError";
10
+ }
11
+ feature;
12
+ code = "chat-no-database";
13
+ }
14
+ function isChatNoDatabaseError(error) {
15
+ return error instanceof ChatNoDatabaseError || typeof error === "object" && error !== null && error.code === "chat-no-database";
16
+ }
17
+ const STAND_IN = /* @__PURE__ */ Symbol.for("@ai-matrx/chat/no-database");
18
+ function isNoDatabase(db) {
19
+ return typeof db === "object" && db !== null && db[STAND_IN] === true;
20
+ }
21
+ const NAMED_CALLS = new Set("from rpc schema channel".split(" "));
22
+ function createNoDatabaseStandIn(report) {
23
+ const reported = /* @__PURE__ */ new Set();
24
+ const refuse = (feature) => {
25
+ if (!reported.has(feature)) {
26
+ reported.add(feature);
27
+ try {
28
+ report(feature);
29
+ } catch {
30
+ }
31
+ }
32
+ throw new ChatNoDatabaseError(feature);
33
+ };
34
+ return new Proxy({}, {
35
+ get(_target, key) {
36
+ if (key === STAND_IN) return true;
37
+ if (typeof key === "symbol" || key === "then" || key === "toJSON") return void 0;
38
+ if (NAMED_CALLS.has(key)) {
39
+ return (name) => refuse(`db.${key}(${typeof name === "string" ? name : "?"})`);
40
+ }
41
+ return refuse(`db.${key}`);
42
+ },
43
+ has(_target, key) {
44
+ return key === STAND_IN;
45
+ },
46
+ set(_target, key) {
47
+ return refuse(`db.${String(key)}=`);
48
+ }
49
+ });
50
+ }
51
+ function createConsoleDiagnostics() {
52
+ return {
53
+ capture(error, ctx) {
54
+ announceOnce(
55
+ `console-diagnostics:${ctx.area}:${ctx.code}`,
56
+ `${ctx.area}/${ctx.code}: ${error instanceof Error ? error.message : String(error)}`,
57
+ "error"
58
+ );
59
+ }
60
+ };
61
+ }
62
+ function isLocalServerMember(key) {
63
+ return key === "parseNdjsonStream" || /^select[A-Z]/.test(key);
64
+ }
65
+ function createNoServerApi(report, local = {}) {
66
+ const reported = /* @__PURE__ */ new Set();
67
+ const refuse = (feature) => {
68
+ if (!reported.has(feature)) {
69
+ reported.add(feature);
70
+ try {
71
+ report(feature);
72
+ } catch {
73
+ }
74
+ }
75
+ throw new ChatNoDatabaseError(feature);
76
+ };
77
+ const at = (path) => new Proxy(() => {
78
+ }, {
79
+ get(_target, key) {
80
+ if (typeof key === "symbol" || key === "then" || key === "toJSON") return void 0;
81
+ return at(`${path}.${key}`);
82
+ },
83
+ apply() {
84
+ return refuse(path);
85
+ }
86
+ });
87
+ return new Proxy(
88
+ {},
89
+ {
90
+ get(_target, key) {
91
+ if (typeof key === "symbol" || key === "then" || key === "toJSON") return void 0;
92
+ if (isLocalServerMember(key) && key in local) return local[key];
93
+ return at(`server.${key}`);
94
+ }
95
+ }
96
+ );
97
+ }
98
+ export {
99
+ ChatNoDatabaseError,
100
+ NO_DATABASE_CODE_PREFIX,
101
+ createConsoleDiagnostics,
102
+ createNoDatabaseStandIn,
103
+ createNoServerApi,
104
+ isChatNoDatabaseError,
105
+ isLocalServerMember,
106
+ isNoDatabase
107
+ };
@@ -30,3 +30,4 @@ export declare function ChatProvider({ host, store, children }: ChatProviderProp
30
30
  export declare function useMaybeChatHost(): ResolvedChatHost | null;
31
31
  /** The host from the nearest <ChatProvider>. Throws the named, remedied error outside one. */
32
32
  export declare function useChatHost(): ResolvedChatHost;
33
+ export { Link, usePathname, useRouter, useSearchParams } from "./navigation.js";
@@ -8,12 +8,30 @@ import { ChatStoreContext } from "../store/context.js";
8
8
  import { createChatStore } from "../store/create-chat-store.js";
9
9
  import { useChatHostSync } from "../store/chat-host-sync.js";
10
10
  import { setStoreSingleton } from "../store/store-singleton.js";
11
+ import { BareHostChrome } from "./bare-host-chrome.js";
12
+ import {
13
+ isRemarkDurabilityRegistered,
14
+ registerRemarkDurability
15
+ } from "../agents/redux/execution-system/instance-resources/remarks.js";
16
+ import { createDbRemarkDurability } from "../agents/redux/execution-system/instance-resources/default-remark-durability.js";
11
17
  const ChatHostContext = createContext(null);
12
18
  function ChatProvider({ host, store, children }) {
13
19
  const resolved = typeof window === "undefined" ? resolveChatHost(host) : configureChat(host);
14
20
  const [privateStore] = useState(() => {
15
21
  if (store) return null;
16
22
  const created = createChatStore();
23
+ if (typeof window !== "undefined" && !isRemarkDurabilityRegistered()) {
24
+ registerRemarkDurability(
25
+ createDbRemarkDurability({
26
+ db: resolved.db,
27
+ dispatch: created.dispatch,
28
+ onFailure: (message, error) => {
29
+ resolved.notify.error(message);
30
+ console.error("[remarks] write failed:", error);
31
+ }
32
+ })
33
+ );
34
+ }
17
35
  return { store: created, snapshot: created.getState() };
18
36
  });
19
37
  const chatStore = store ?? privateStore.store;
@@ -21,7 +39,7 @@ function ChatProvider({ host, store, children }) {
21
39
  const serverState = privateStore?.snapshot ?? (parent && parent.store === store ? parent.getServerState?.() : void 0);
22
40
  if (typeof window !== "undefined") setStoreSingleton(chatStore);
23
41
  useChatHostSync(chatStore, resolved);
24
- return /* @__PURE__ */ jsx(ChatHostContext.Provider, { value: resolved, children: /* @__PURE__ */ jsx(Provider, { store: chatStore, context: ChatStoreContext, serverState, children }) });
42
+ return /* @__PURE__ */ jsx(ChatHostContext.Provider, { value: resolved, children: /* @__PURE__ */ jsx(Provider, { store: chatStore, context: ChatStoreContext, serverState, children: privateStore ? /* @__PURE__ */ jsx(BareHostChrome, { host: resolved, children }) : children }) });
25
43
  }
26
44
  function useMaybeChatHost() {
27
45
  return useContext(ChatHostContext);
@@ -31,8 +49,13 @@ function useChatHost() {
31
49
  if (!host) throw new ChatHostNotConfiguredError();
32
50
  return host;
33
51
  }
52
+ import { Link, usePathname, useRouter, useSearchParams } from "./navigation.js";
34
53
  export {
35
54
  ChatProvider,
55
+ Link,
36
56
  useChatHost,
37
- useMaybeChatHost
57
+ useMaybeChatHost,
58
+ usePathname,
59
+ useRouter,
60
+ useSearchParams
38
61
  };
@@ -1,5 +1,5 @@
1
1
  import { createElement } from "react";
2
- import { reportUnregisteredHostSlot } from "./diagnostics.js";
2
+ import { reportUnregisteredHostSlot, SLOT_CANNOT_RUN } from "./diagnostics.js";
3
3
  function createRegisteredSource(sourceName, registerCall, defaults) {
4
4
  let impl = null;
5
5
  const label = (key) => `${sourceName}.${String(key)}`;
@@ -12,7 +12,7 @@ function createRegisteredSource(sourceName, registerCall, defaults) {
12
12
  reportUnregisteredHostSlot(label(key), "its generic default runs");
13
13
  return defaults[key];
14
14
  }
15
- reportUnregisteredHostSlot(label(key), "it cannot run");
15
+ reportUnregisteredHostSlot(label(key), SLOT_CANNOT_RUN);
16
16
  throw new Error(
17
17
  `The host registered no "${label(key)}" for the chat package (${registerCall}).`
18
18
  );
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @ai-matrx/chat/host/source — THE host-owned message source (HOST-OWNED-SOURCE-PLAN §2.2, P28a).
3
+ *
4
+ * A host with no database (coding sessions, desktop) still renders through the ONE real message
5
+ * list + composer: it hands the package history as records and live turns as platform stream
6
+ * events, and receives sends. It mirrors the engine's own two inputs — history arrives as
7
+ * records (`hydrateMessages`), live turns as events (`processStream`) — so nothing downstream
8
+ * learns a second shape. Capability by presence: a handler left out is a control left out.
9
+ *
10
+ * Pure: no React, no Redux, no `window` at import.
11
+ */
12
+ import type { MessagePart, TypedStreamEvent } from "@ai-matrx/agents/generated/stream-events";
13
+ /** One stored message the host hands over. `content` is the platform's own `MessagePart[]`. */
14
+ export interface HostMessageRecord {
15
+ id: string;
16
+ role: "user" | "assistant" | "system" | "tool";
17
+ content: MessagePart[];
18
+ position: number;
19
+ /** ISO timestamp. */
20
+ createdAt: string;
21
+ /** Presence means the turn failed; `message` is the sentence the person reads, `code` its class. */
22
+ error?: {
23
+ message: string;
24
+ code?: string | null;
25
+ } | null;
26
+ }
27
+ export interface HostHistoryPage {
28
+ records: HostMessageRecord[];
29
+ hasMoreOlder: boolean;
30
+ /** The host's sentence when its history could not be read ("This chat's file could not be read"). */
31
+ unavailable?: string | null;
32
+ }
33
+ /** A live turn: the platform NDJSON as-is, or typed events. */
34
+ export interface HostTurn {
35
+ requestId: string;
36
+ /** The person's message, when the HOST started the turn (another device, the CLI). */
37
+ user?: MessagePart[] | null;
38
+ events: Response | AsyncIterable<TypedStreamEvent>;
39
+ }
40
+ /** What the package gives the host for one bound conversation. */
41
+ export interface HostSourceSink {
42
+ /** A turn the host started (or a reconnect to one already running). */
43
+ turn(turn: HostTurn): void;
44
+ /** The host's history changed out of band: re-load it. */
45
+ history(): void;
46
+ /** The composer waits, with the host's sentence; null releases it. */
47
+ held(reason: string | null): void;
48
+ }
49
+ export interface HostSendInput {
50
+ conversationId: string;
51
+ text: string;
52
+ /** "send" when idle; "queue" / "steer" when a turn is running (per `whileBusy`). */
53
+ mode: "send" | "queue" | "steer";
54
+ }
55
+ /** The host's conversation list. Ids are always the host's — the package never mints one. */
56
+ export interface HostConversationSummary {
57
+ id: string;
58
+ title: string | null;
59
+ updatedAt: string | null;
60
+ }
61
+ export interface HostConversationList {
62
+ list(): Promise<HostConversationSummary[]>;
63
+ /** Absent ⇒ no New control. Resolves the host's id for the new conversation. */
64
+ start?(): Promise<string>;
65
+ }
66
+ export type HostPersistence = {
67
+ saved: true;
68
+ where: string;
69
+ } | {
70
+ saved: false;
71
+ reason: string;
72
+ };
73
+ export interface ChatMessageSource {
74
+ /** Stable id of the source ("coding-sessions"). */
75
+ id: string;
76
+ load(conversationId: string, page?: {
77
+ before: number | null;
78
+ }): Promise<HostHistoryPage>;
79
+ subscribe(conversationId: string, sink: HostSourceSink): () => void;
80
+ /** Absent ⇒ read-only. Returns the turn when it holds the stream, `void` when the turn arrives via `sink.turn`. */
81
+ send?(input: HostSendInput, signal: AbortSignal): Promise<HostTurn | void>;
82
+ stop?(conversationId: string, requestId: string | null): Promise<void>;
83
+ retry?(conversationId: string, messageId: string, signal: AbortSignal): Promise<HostTurn | void>;
84
+ answer?(conversationId: string, askId: string, value: unknown): Promise<void>;
85
+ conversations?: HostConversationList;
86
+ whileBusy: "queue" | "steer" | "refuse";
87
+ persistence: HostPersistence;
88
+ }
89
+ /** The host refused a send. `message` is the host's sentence; the words go back in the box. */
90
+ export declare class HostSendRefused extends Error {
91
+ readonly code = "host-send-refused";
92
+ constructor(message: string);
93
+ }
94
+ export declare function isHostSendRefused(error: unknown): error is HostSendRefused;
95
+ /** Typed events as the platform's NDJSON `Response` — the one shape `processStream` reads. */
96
+ export declare function eventsToResponse(events: AsyncIterable<TypedStreamEvent>): Response;
97
+ /** A turn's events as the NDJSON `Response` `processStream` reads. */
98
+ export declare function hostTurnResponse(turn: HostTurn): Response;
99
+ export interface HostTurnWriter {
100
+ turn: HostTurn;
101
+ push(event: TypedStreamEvent): void;
102
+ end(): void;
103
+ fail(error: unknown): void;
104
+ }
105
+ /**
106
+ * A turn the host fills as its own events arrive (a socket, an IPC channel). Events pushed before
107
+ * the package reads are buffered in order; `end()` closes the stream, `fail()` errors it.
108
+ */
109
+ export declare function createHostTurn(requestId: string): HostTurnWriter;