@ai-matrx/chat 0.5.18 → 0.6.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 (99) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/agents/components/identity-refs/AiIdentityRef.d.ts +33 -0
  3. package/dist/agents/components/identity-refs/AiIdentityRef.js +138 -0
  4. package/dist/agents/components/inputs/resources/RenderedArtifactChip.d.ts +8 -0
  5. package/dist/agents/components/inputs/resources/RenderedArtifactChip.js +109 -0
  6. package/dist/agents/components/inputs/resources/SmartAgentResourceChips.js +20 -0
  7. package/dist/agents/components/inputs/resources/useAttachRenderedArtifact.js +31 -6
  8. package/dist/agents/components/inputs/smart-input/QuicksetPanel.js +5 -9
  9. package/dist/agents/components/inputs/smart-input/RunSkillPicker.js +1 -1
  10. package/dist/agents/components/inputs/smart-input/RunToolPicker.js +6 -11
  11. package/dist/agents/components/inputs/smart-input/ShapeChipsRow.js +1 -1
  12. package/dist/agents/components/inputs/smart-input/composer/ComposerEffortPill.js +1 -1
  13. package/dist/agents/components/inputs/smart-input/composer/ComposerOutput.js +1 -1
  14. package/dist/agents/components/inputs/smart-input/composer/ComposerPlusMenu.js +1 -1
  15. package/dist/agents/components/inputs/smart-input/composer/useComposerAgent.js +1 -1
  16. package/dist/agents/components/inputs/smart-input/composer/useRunControlCounts.d.ts +3 -0
  17. package/dist/agents/components/inputs/smart-input/composer/useRunControlCounts.js +54 -0
  18. package/dist/agents/components/model-tiers/ModelTierIdentityList.js +1 -1
  19. package/dist/agents/components/run-controls/RunConfigOverrides.js +1 -1
  20. package/dist/agents/components/run-controls/RunInputCapabilities.js +1 -1
  21. package/dist/agents/components/run-controls/panels/shared.d.ts +0 -2
  22. package/dist/agents/hooks/useDiffEnrichment.js +3 -6
  23. package/dist/agents/identity/agent-catalog-lists.js +2 -1
  24. package/dist/agents/identity/agent-identity.js +2 -1
  25. package/dist/agents/identity/model-catalog.d.ts +9 -0
  26. package/dist/agents/identity/model-catalog.js +25 -0
  27. package/dist/agents/identity/preferred-chat-model.d.ts +9 -0
  28. package/dist/agents/identity/preferred-chat-model.js +33 -0
  29. package/dist/agents/identity/settings-store.d.ts +10 -0
  30. package/dist/agents/identity/settings-store.js +49 -0
  31. package/dist/agents/identity/skill-catalog.d.ts +27 -0
  32. package/dist/agents/identity/skill-catalog.js +100 -0
  33. package/dist/agents/identity/tool-catalog.d.ts +15 -0
  34. package/dist/agents/identity/tool-catalog.js +67 -0
  35. package/dist/agents/redux/agent-definition/cache-bust-middleware.d.ts +0 -1
  36. package/dist/agents/redux/agent-definition/cache-bust-middleware.js +1 -13
  37. package/dist/agents/redux/agent-definition/selectors.d.ts +12 -546
  38. package/dist/agents/redux/agent-settings/internal-utils.d.ts +2 -123
  39. package/dist/agents/redux/agent-settings/internal-utils.js +1 -315
  40. package/dist/agents/redux/agent-settings/settings-catalogue.d.ts +2 -78
  41. package/dist/agents/redux/agent-settings/settings-catalogue.js +1 -176
  42. package/dist/agents/redux/agent-settings/types.d.ts +2 -148
  43. package/dist/agents/redux/agent-settings/types.js +1 -0
  44. package/dist/agents/redux/agent-settings/ui-gates.d.ts +2 -54
  45. package/dist/agents/redux/agent-settings/ui-gates.js +1 -38
  46. package/dist/agents/redux/agent-shortcut-categories/selectors.d.ts +0 -100
  47. package/dist/agents/redux/agent-shortcuts/selectors.d.ts +0 -294
  48. package/dist/agents/redux/conversation-history/selectors.d.ts +0 -32
  49. package/dist/agents/redux/conversation-list/conversation-list.selectors.d.ts +0 -4
  50. package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.d.ts +0 -108
  51. package/dist/agents/redux/execution-system/context-state/context-state.selectors.d.ts +0 -28
  52. package/dist/agents/redux/execution-system/conversations/conversations.selectors.d.ts +0 -10
  53. package/dist/agents/redux/execution-system/instance-context/instance-context.selectors.d.ts +0 -6
  54. package/dist/agents/redux/execution-system/instance-model-overrides/launch-model-overrides.js +1 -1
  55. package/dist/agents/redux/execution-system/instance-resources/instance-resources.selectors.d.ts +0 -16
  56. package/dist/agents/redux/execution-system/instance-ui-state/instance-ui-state.selectors.d.ts +0 -10
  57. package/dist/agents/redux/execution-system/instance-variable-values/instance-variable-values.selectors.d.ts +0 -14
  58. package/dist/agents/redux/execution-system/messages/messages.selectors.d.ts +0 -2
  59. package/dist/agents/redux/execution-system/observability/observability.selectors.d.ts +0 -14
  60. package/dist/agents/redux/execution-system/observational-memory/observational-memory.selectors.d.ts +0 -2
  61. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.d.ts +0 -28
  62. package/dist/agents/redux/execution-system/thunks/process-stream.js +2 -5
  63. package/dist/agents/redux/execution-system/utils/loaded-skill-sources.d.ts +1 -1
  64. package/dist/agents/redux/execution-system/utils/loaded-skill-sources.js +3 -3
  65. package/dist/agents/redux/proposed-directives/proposedDirectivesSlice.d.ts +0 -2
  66. package/dist/agents/ui-first-tools/redux/agent-lists.selectors.d.ts +0 -4
  67. package/dist/agents/utils/renderedArtifactContext.d.ts +55 -17
  68. package/dist/agents/utils/renderedArtifactContext.js +83 -2
  69. package/dist/conversation/utils/frame-print.d.ts +10 -5
  70. package/dist/conversation/utils/frame-print.js +65 -27
  71. package/dist/host/frame-print.d.ts +10 -0
  72. package/dist/host/frame-print.js +9 -0
  73. package/dist/host/ui-slots.d.ts +0 -46
  74. package/dist/host/ui-slots.js +0 -33
  75. package/dist/store/create-chat-store.d.ts +0 -4
  76. package/dist/store/middlewares.d.ts +0 -10
  77. package/dist/store/slices.d.ts +0 -2
  78. package/dist/store/slices.js +0 -4
  79. package/dist/surfaces/redux/selectors.d.ts +0 -4
  80. package/dist/tool-call-visualization/redux/selectors.d.ts +0 -2
  81. package/dist/ui/chat-default-model-knob.d.ts +1 -1
  82. package/dist/ui/chat-default-model-knob.js +1 -1
  83. package/package.json +5 -5
  84. package/dist/agents/components/model/AgentModelPanel.d.ts +0 -4
  85. package/dist/agents/components/model/AgentModelPanel.js +0 -9
  86. package/dist/agents/redux/agent-settings/agentSettingsSlice.d.ts +0 -1015
  87. package/dist/agents/redux/agent-settings/agentSettingsSlice.js +0 -659
  88. package/dist/agents/redux/agent-settings/selectors.d.ts +0 -10057
  89. package/dist/agents/redux/agent-settings/selectors.js +0 -234
  90. package/dist/agents/redux/agent-settings/useNormalizedControls.d.ts +0 -8
  91. package/dist/agents/redux/agent-settings/useNormalizedControls.js +0 -24
  92. package/dist/agents/redux/tools/tools.selectors.d.ts +0 -529
  93. package/dist/agents/redux/tools/tools.selectors.js +0 -24
  94. package/dist/agents/redux/tools/tools.slice.d.ts +0 -12
  95. package/dist/agents/redux/tools/tools.slice.js +0 -37
  96. package/dist/agents/redux/tools/tools.thunks.d.ts +0 -125
  97. package/dist/agents/redux/tools/tools.thunks.js +0 -45
  98. package/dist/host/defaults/setting-control-input.d.ts +0 -11
  99. package/dist/host/defaults/setting-control-input.js +0 -91
@@ -29,7 +29,7 @@ import {
29
29
  import {
30
30
  buildSettingsRows
31
31
  } from "../../redux/agent-settings/settings-catalogue.js";
32
- import { SettingControlInput } from "../../../host/ui-slots.js";
32
+ import { SettingControlInput } from "@ai-matrx/agents/settings/react";
33
33
  import { Label, ErrorBox } from "@ai-matrx/design-system";
34
34
  import { cn } from "@ai-matrx/design-system";
35
35
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/tabs.js";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useAppDispatch, useAppSelector } from "../../../store/hooks.js";
4
- import { InputCapabilitiesEditor } from "../../../host/ui-slots.js";
4
+ import { InputCapabilitiesEditor } from "@ai-matrx/agents/settings/react";
5
5
  import { selectInputCapabilitiesState } from "../../redux/execution-system/instance-input-capabilities/instance-input-capabilities.selectors.js";
6
6
  import {
7
7
  resetInputCapabilityOverride,
@@ -30,7 +30,6 @@ export declare function makeSelectConversationRequests(conversationId: string):
30
30
  agentShortcut: import("../../../redux/agent-shortcuts/types.js").AgentShortcutSliceState;
31
31
  agentShortcutCategory: import("../../../redux/agent-shortcut-categories/types.js").AgentShortcutCategorySliceState;
32
32
  surfaceUserState: import("../../../../surfaces/redux/userStateSlice.js").SurfaceUserStateSlice;
33
- tools: import("../../../redux/tools/tools.slice.js").ToolsSliceState;
34
33
  conversations: import("../../../redux/execution-system/conversations/conversations.slice.js").ConversationsState;
35
34
  chatIncognito: import("../../../redux/chat/chat-incognito.slice.js").ChatIncognitoState;
36
35
  chatRoute: import("../../../redux/chat/chat-route.slice.js").ChatRouteState;
@@ -62,7 +61,6 @@ export declare function makeSelectConversationRequests(conversationId: string):
62
61
  agentAssistantMarkdownDraft: import("../../../redux/agent-assistant-markdown-draft.slice.js").AgentAssistantMarkdownDraftState;
63
62
  mcp: import("../../../redux/mcp/mcp.slice.js").McpSliceState;
64
63
  proposedDirectives: import("../../../redux/proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
65
- agentSettings: import("../../../redux/agent-settings/types.js").AgentSettingsState;
66
64
  conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
67
65
  chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
68
66
  hostConversations: import("../../../redux/execution-system/host-conversations/host-conversations.slice.js").HostConversationsState;
@@ -1,15 +1,12 @@
1
1
  "use client";
2
2
  import { useMemo } from "react";
3
3
  import { useAppSelector } from "../../store/hooks.js";
4
- import {
5
- selectAllTools,
6
- selectToolIdentityMap
7
- } from "../redux/tools/tools.selectors.js";
8
4
  import { selectMcpCatalog } from "../redux/mcp/mcp.slice.js";
9
5
  import { useModelRecords } from "../identity/model-catalog.js";
6
+ import { selectAllTools, selectToolIdentityMap, useToolCatalog } from "../identity/tool-catalog.js";
10
7
  function useDiffEnrichment() {
11
- const allTools = useAppSelector(selectAllTools);
12
- const toolIdentities = useAppSelector(selectToolIdentityMap);
8
+ const allTools = useToolCatalog(selectAllTools);
9
+ const toolIdentities = useToolCatalog(selectToolIdentityMap);
13
10
  const mcpCatalog = useAppSelector(selectMcpCatalog);
14
11
  const modelEntities = useModelRecords((s) => s.entities);
15
12
  const modelIdentities = useModelRecords((s) => s.identityById);
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { useEffect, useMemo, useSyncExternalStore } from "react";
3
- import { getAgentCatalog } from "../../host/ui-slots.js";
3
+ import { getChatHost } from "../../host/configure.js";
4
+ const getAgentCatalog = () => getChatHost().catalog();
4
5
  import { ensureAgentCatalog } from "./agent-identity.js";
5
6
  const EMPTY_ROWS = [];
6
7
  const EMPTY_BY_ID = {};
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { getAgentCatalog } from "../../host/ui-slots.js";
2
+ import { getChatHost } from "../../host/configure.js";
3
+ const getAgentCatalog = () => getChatHost().catalog();
3
4
  import { useAppSelector } from "../../store/hooks.js";
4
5
  import { useEffect, useMemo, useSyncExternalStore } from "react";
5
6
  import { hasField } from "@ai-matrx/agents/field-flags";
@@ -35,3 +35,12 @@ export type ModelClassControls = undefined | {
35
35
  config: ModelClassConfig;
36
36
  };
37
37
  export declare function useModelClassControls(modelId: string | null | undefined, offeringId: string | null | undefined): ModelClassControls;
38
+ /** The active model options; loads them once (idempotent, shared with every picker). */
39
+ export declare function useModelOptions(): {
40
+ options: import("@ai-matrx/agents/models").ModelOption[];
41
+ isLoading: boolean;
42
+ error: string | null;
43
+ isReady: boolean;
44
+ };
45
+ /** One model's FULL record (controls included), or undefined until it has loaded. */
46
+ export declare function useModelFull(modelId: string | null | undefined): ModelRecord | undefined;
@@ -4,8 +4,11 @@ import {
4
4
  classConfigKey,
5
5
  createModelCatalog,
6
6
  EMPTY_MODEL_RECORDS,
7
+ selectActiveModelsReady,
7
8
  selectModelById,
9
+ selectModelFullyLoaded,
8
10
  selectModelLabelById,
11
+ selectModelOptions,
9
12
  selectModelLabelWithClass
10
13
  } from "@ai-matrx/agents/models";
11
14
  import { useModelRecordsSelector } from "@ai-matrx/agents/models/react";
@@ -92,14 +95,36 @@ function useModelClassControls(modelId, offeringId) {
92
95
  if (status === "failed") return { failed: true };
93
96
  return { pending: true };
94
97
  }
98
+ function useModelOptions() {
99
+ const options = useModelRecords(selectModelOptions);
100
+ const isLoading = useModelRecords((s) => s.isLoading);
101
+ const error = useModelRecords((s) => s.error);
102
+ const isReady = useModelRecords(selectActiveModelsReady);
103
+ useEffect(() => {
104
+ if (chatHostHasDatabase()) void getModelRecords().loadOptions();
105
+ }, []);
106
+ return { options, isLoading, error, isReady };
107
+ }
108
+ function useModelFull(modelId) {
109
+ const record = useModelRecords((s) => selectModelById(s, modelId));
110
+ const isFull = useModelRecords((s) => selectModelFullyLoaded(s, modelId));
111
+ useEffect(() => {
112
+ if (!chatHostHasDatabase()) return;
113
+ void getModelRecords().loadOptions();
114
+ if (modelId && !isFull) void getModelRecords().loadModel(modelId);
115
+ }, [modelId, isFull]);
116
+ return isFull ? record : void 0;
117
+ }
95
118
  export {
96
119
  getModelCatalog,
97
120
  getModelRecords,
98
121
  readModelRecords,
99
122
  useModelClassControls,
100
123
  useModelClassLabels,
124
+ useModelFull,
101
125
  useModelLabel,
102
126
  useModelLabelWithClass,
127
+ useModelOptions,
103
128
  useModelRecord,
104
129
  useModelRecords
105
130
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The person's preferred chat model (agent core B6 — chat resolves it itself; the
3
+ * `resolvePreferredChatModel` host slot is retired). `agents.model_prefs.chat_default_model` and
4
+ * its class companion, through the settings ladder (organization → user → device) of the host's
5
+ * knobs port. Null when nobody set one — the Holder's own model answers. A read failure is
6
+ * announced and answers null: a run never blocks on a preference.
7
+ */
8
+ import { type PreferredModelChoice } from "@ai-matrx/agents/models";
9
+ export declare function resolvePreferredChatModel(): Promise<PreferredModelChoice | null>;
@@ -0,0 +1,33 @@
1
+ import {
2
+ CHAT_DEFAULT_MODEL_KNOB,
3
+ modelClassKnobFor,
4
+ modelClassPinOf,
5
+ resolvePreferredModelChoice
6
+ } from "@ai-matrx/agents/models";
7
+ import { supabase } from "../../host/db.js";
8
+ import { ensureEffectiveKnob } from "../../host/prefs.js";
9
+ import { getActiveOrgId } from "../../host/org.js";
10
+ import { getUserId } from "../../host/identity.js";
11
+ async function resolvePreferredChatModel() {
12
+ try {
13
+ return await resolvePreferredModelChoice(
14
+ {
15
+ client: () => supabase,
16
+ resolveKnob: (fullKey) => ensureEffectiveKnob(getActiveOrgId(), getUserId(), fullKey),
17
+ classKnobFor: modelClassKnobFor,
18
+ classPinOf: (value) => modelClassPinOf(value) ?? null
19
+ },
20
+ CHAT_DEFAULT_MODEL_KNOB,
21
+ "preferredChatModel"
22
+ );
23
+ } catch (error) {
24
+ console.error(
25
+ `[preferredChatModel] ${CHAT_DEFAULT_MODEL_KNOB} could not be resolved \u2014 the Holder's own model answers this run:`,
26
+ error
27
+ );
28
+ return null;
29
+ }
30
+ }
31
+ export {
32
+ resolvePreferredChatModel
33
+ };
@@ -0,0 +1,10 @@
1
+ import { type NormalizedControls, type SettingsStore } from "@ai-matrx/agents/settings";
2
+ export declare function getSettingsStore(): SettingsStore;
3
+ /** One agent's settings entry from the page's store. */
4
+ export declare function useAgentSettingsEntry(agentId: string | null | undefined): import("@ai-matrx/agents/settings").AgentSettingsEntry | undefined;
5
+ /**
6
+ * Parsed controls for a settings entry's effective model: the pinned CLASS's controls when a pin
7
+ * is set and loaded (a model's classes run through different APIs), else the model's own. Null
8
+ * until the record (full, with controls) is loaded or when the agent has no entry.
9
+ */
10
+ export declare function useNormalizedControls(agentId: string): NormalizedControls | null;
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { selectModelById, selectModelClassConfig } from "@ai-matrx/agents/models";
4
+ import {
5
+ createSettingsStore,
6
+ effectiveOfferingPinOf,
7
+ parseModelControls,
8
+ readEffectiveModelId
9
+ } from "@ai-matrx/agents/settings";
10
+ import { useSettingsEntry } from "@ai-matrx/agents/settings/react";
11
+ import { readModelRecords, useModelRecords } from "./model-catalog.js";
12
+ const KEY = /* @__PURE__ */ Symbol.for("ai-matrx.chat.settings-store");
13
+ function getSettingsStore() {
14
+ const g = globalThis;
15
+ if (g[KEY]) return g[KEY];
16
+ const store = createSettingsStore({
17
+ lookupModel: (modelId) => {
18
+ const model = selectModelById(readModelRecords(), modelId);
19
+ if (!model) return void 0;
20
+ return {
21
+ id: model.id,
22
+ name: model.common_name || model.name || model.id,
23
+ controls: model.controls ?? null
24
+ };
25
+ }
26
+ });
27
+ g[KEY] = store;
28
+ return store;
29
+ }
30
+ function useAgentSettingsEntry(agentId) {
31
+ return useSettingsEntry(getSettingsStore(), agentId);
32
+ }
33
+ function useNormalizedControls(agentId) {
34
+ const entry = useAgentSettingsEntry(agentId);
35
+ const modelId = readEffectiveModelId(entry);
36
+ const pin = effectiveOfferingPinOf(entry) ?? null;
37
+ const model = useModelRecords((s) => selectModelById(s, modelId));
38
+ const classConfig = useModelRecords((s) => selectModelClassConfig(s, modelId, pin));
39
+ return useMemo(() => {
40
+ if (!model) return null;
41
+ const controls = classConfig ? classConfig.controls : model.controls;
42
+ return parseModelControls(controls);
43
+ }, [model, classConfig]);
44
+ }
45
+ export {
46
+ getSettingsStore,
47
+ useAgentSettingsEntry,
48
+ useNormalizedControls
49
+ };
@@ -0,0 +1,27 @@
1
+ import { type SkillCatalog, type SkillRow } from "@ai-matrx/agents/skills";
2
+ import { type UseSkillsArgs } from "@ai-matrx/agents/skills/react";
3
+ export declare function getSkillCatalog(): SkillCatalog;
4
+ export interface ChatSkillsResult {
5
+ skills: SkillRow[];
6
+ grouped: Record<string, SkillRow[]>;
7
+ count: number;
8
+ loading: boolean;
9
+ error: string | null;
10
+ reload: () => Promise<void>;
11
+ }
12
+ /** The skills list, grouped by type; reloads and announces when a skill stream event lands. */
13
+ export declare function useSkills(args?: UseSkillsArgs): ChatSkillsResult;
14
+ /** The skills already loaded, without a read: `ready` + rows, or the status while not ready. */
15
+ export declare function readLoadedSkills(): {
16
+ status: string;
17
+ skills: SkillRow[];
18
+ };
19
+ /** True when a `resource_changed` kind is skill-related. */
20
+ export declare function isSkillStreamEvent(kind: string | undefined): boolean;
21
+ /** Hand a skill `resource_changed` event to the catalog (it bumps `lastIngestAt`; lists reload). */
22
+ export declare function applySkillStreamEvent(payload: {
23
+ kind?: string;
24
+ action?: string;
25
+ resource_id?: string;
26
+ metadata?: Record<string, unknown>;
27
+ }): void;
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import { useEffect, useMemo, useRef } from "react";
3
+ import { createSkillCatalog } from "@ai-matrx/agents/skills";
4
+ import { useSkillCatalogSelector, useSkills as useCoreSkills } from "@ai-matrx/agents/skills/react";
5
+ import { supabase } from "../../host/db.js";
6
+ import { captureError } from "../../host/diagnostics.js";
7
+ import { toast } from "../../host/notify.js";
8
+ import { associationsService, isScopesRpcErr } from "../../context/sources/scopes.js";
9
+ import { chatHostHasDatabase } from "../../host/configure.js";
10
+ const KEY = /* @__PURE__ */ Symbol.for("ai-matrx.chat.skill-catalog");
11
+ function getSkillCatalog() {
12
+ const g = globalThis;
13
+ if (g[KEY]) return g[KEY];
14
+ const catalog = createSkillCatalog({
15
+ client: supabase,
16
+ associations: {
17
+ async skillIdsForProject(projectId) {
18
+ const res = await associationsService.listForTargets("project", [projectId]);
19
+ if (isScopesRpcErr(res)) return { ok: false, message: res.error.message };
20
+ return {
21
+ ok: true,
22
+ ids: res.data.edges.filter((e) => e.sourceType === "skill" && e.role === "member").map((e) => e.sourceId)
23
+ };
24
+ },
25
+ async projectIdsBySkill(skillIds) {
26
+ const out = {};
27
+ if (skillIds.length === 0) return out;
28
+ const res = await associationsService.listForSources("skill", [...skillIds], "project");
29
+ if (isScopesRpcErr(res)) return out;
30
+ for (const edge of res.data.edges) {
31
+ if (edge.role !== "member") continue;
32
+ (out[edge.sourceId] ??= []).push(edge.targetId);
33
+ }
34
+ return out;
35
+ }
36
+ },
37
+ errorSink: (event) => {
38
+ captureError({ source: "supabase-postgrest", schema: "skill", message: event.message, code: event.code });
39
+ }
40
+ });
41
+ g[KEY] = catalog;
42
+ return catalog;
43
+ }
44
+ function useSkills(args = {}) {
45
+ const catalog = getSkillCatalog();
46
+ const result = useCoreSkills(catalog, { ...args, skipAutoFetch: Boolean(args.skipAutoFetch) || !chatHostHasDatabase() });
47
+ const lastIngestAt = useSkillCatalogSelector(catalog, (s) => s.lastIngestAt);
48
+ const lastReport = useSkillCatalogSelector(catalog, (s) => s.lastStreamReport);
49
+ const seen = useRef(lastIngestAt);
50
+ useEffect(() => {
51
+ if (!lastIngestAt || lastIngestAt === seen.current) return;
52
+ seen.current = lastIngestAt;
53
+ const created = lastReport?.created ?? 0;
54
+ const updated = lastReport?.updated ?? 0;
55
+ const total = created + updated;
56
+ if (total > 0) {
57
+ const parts = [];
58
+ if (created) parts.push(`${created} new`);
59
+ if (updated) parts.push(`${updated} updated`);
60
+ toast.success(`Discovered ${parts.join(", ")} skill${total === 1 ? "" : "s"}`);
61
+ }
62
+ }, [lastIngestAt, lastReport]);
63
+ const all = useSkillCatalogSelector(catalog, (s) => s.skills);
64
+ const grouped = useMemo(() => {
65
+ const groups = {};
66
+ for (const id of all.allIds) {
67
+ const row = all.byId[id];
68
+ if (!row) continue;
69
+ (groups[row.skillType || "reference"] ??= []).push(row);
70
+ }
71
+ return groups;
72
+ }, [all]);
73
+ return { ...result, grouped };
74
+ }
75
+ function readLoadedSkills() {
76
+ const { skills } = getSkillCatalog().getState();
77
+ return {
78
+ status: skills.status,
79
+ skills: skills.allIds.map((id) => skills.byId[id]).filter((r) => Boolean(r))
80
+ };
81
+ }
82
+ function isSkillStreamEvent(kind) {
83
+ return Boolean(kind && kind.startsWith("skill"));
84
+ }
85
+ function applySkillStreamEvent(payload) {
86
+ if (!isSkillStreamEvent(payload.kind)) return;
87
+ getSkillCatalog().applyStreamEvent({
88
+ kind: payload.kind,
89
+ action: payload.action ?? "modified",
90
+ resourceId: payload.resource_id ?? "",
91
+ metadata: payload.metadata ?? {}
92
+ });
93
+ }
94
+ export {
95
+ applySkillStreamEvent,
96
+ getSkillCatalog,
97
+ isSkillStreamEvent,
98
+ readLoadedSkills,
99
+ useSkills
100
+ };
@@ -0,0 +1,15 @@
1
+ import { type ToolCatalog, type ToolCatalogState } from "@ai-matrx/agents/tools";
2
+ import type { DatabaseTool } from "../../ui/database-tool.js";
3
+ export { selectAllTools, selectToolsStatus, selectToolsError, selectToolsReady, selectToolIdentityMap, selectToolById, selectToolLookupStatus, } from "@ai-matrx/agents/tools";
4
+ export type ChatToolCatalogState = ToolCatalogState<DatabaseTool>;
5
+ export declare function getToolCatalog(): ToolCatalog<DatabaseTool>;
6
+ /** Subscribe to a slice of the tool catalogue. `select` must return a stable value for unchanged state. */
7
+ export declare function useToolCatalog<T>(select: (state: ChatToolCatalogState) => T): T;
8
+ /** Read the active catalogue (once per session). A failure lands in the state's `error`. */
9
+ export declare function loadAvailableTools(options?: {
10
+ force?: boolean;
11
+ }): Promise<void>;
12
+ /** Resolve one tool reference (inactive included). */
13
+ export declare function loadToolById(toolId: string): Promise<DatabaseTool | undefined>;
14
+ /** One tool by id (active list, else a resolved historical reference); resolves it when unknown. */
15
+ export declare function useToolById(toolId: string | null | undefined): DatabaseTool | undefined;
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { useEffect, useSyncExternalStore } from "react";
3
+ import {
4
+ createToolCatalog,
5
+ selectToolById
6
+ } from "@ai-matrx/agents/tools";
7
+ import { supabase } from "../../host/db.js";
8
+ import { captureError } from "../../host/diagnostics.js";
9
+ import { chatHostHasDatabase } from "../../host/configure.js";
10
+ import {
11
+ selectAllTools,
12
+ selectToolsStatus,
13
+ selectToolsError,
14
+ selectToolsReady,
15
+ selectToolIdentityMap,
16
+ selectToolById as selectToolById2,
17
+ selectToolLookupStatus
18
+ } from "@ai-matrx/agents/tools";
19
+ const KEY = /* @__PURE__ */ Symbol.for("ai-matrx.chat.tool-catalog");
20
+ function getToolCatalog() {
21
+ const g = globalThis;
22
+ if (g[KEY]) return g[KEY];
23
+ const catalog = createToolCatalog({
24
+ client: () => supabase,
25
+ isAvailable: () => chatHostHasDatabase(),
26
+ errorSink: (event) => {
27
+ captureError({ source: "supabase-postgrest", schema: "tool", code: event.code, message: event.message });
28
+ }
29
+ });
30
+ g[KEY] = catalog;
31
+ return catalog;
32
+ }
33
+ function useToolCatalog(select) {
34
+ const catalog = getToolCatalog();
35
+ return useSyncExternalStore(
36
+ catalog.subscribe,
37
+ () => select(catalog.getState()),
38
+ () => select(catalog.getState())
39
+ );
40
+ }
41
+ function loadAvailableTools(options) {
42
+ return getToolCatalog().load(options).then(() => void 0, () => void 0);
43
+ }
44
+ function loadToolById(toolId) {
45
+ return getToolCatalog().loadById(toolId);
46
+ }
47
+ function useToolById(toolId) {
48
+ const tool = useToolCatalog((s) => selectToolById(s, toolId));
49
+ useEffect(() => {
50
+ if (toolId && !tool) void loadToolById(toolId);
51
+ }, [toolId, tool]);
52
+ return tool;
53
+ }
54
+ export {
55
+ getToolCatalog,
56
+ loadAvailableTools,
57
+ loadToolById,
58
+ selectAllTools,
59
+ selectToolById2 as selectToolById,
60
+ selectToolIdentityMap,
61
+ selectToolLookupStatus,
62
+ selectToolsError,
63
+ selectToolsReady,
64
+ selectToolsStatus,
65
+ useToolById,
66
+ useToolCatalog
67
+ };
@@ -16,7 +16,6 @@
16
16
  * - `agentDefinition/promoteVersion/fulfilled` (past version → live)
17
17
  * - `agentDefinition/updateFromSource/fulfilled` (derived reset)
18
18
  * - `agentDefinition/purgeVersions/fulfilled` (version history trim)
19
- * - `agentSettings/saveAgentSettings/fulfilled` (settings/variables writer)
20
19
  *
21
20
  * NOT the only layer, and deliberately not the load-bearing one. This call can
22
21
  * only evict the ONE python process that answers it, and we run several
@@ -8,19 +8,7 @@ const WATCHED_ACTION_TYPES = /* @__PURE__ */ new Set([
8
8
  "agentDefinition/saveField/fulfilled",
9
9
  "agentDefinition/promoteVersion/fulfilled",
10
10
  "agentDefinition/updateFromSource/fulfilled",
11
- "agentDefinition/purgeVersions/fulfilled",
12
- // Second agent-save path, living in a DIFFERENT slice: `saveAgentSettings`
13
- // (`packages/chat/src/agents/redux/agent-settings/agentSettingsSlice.ts`) writes `settings`
14
- // + `variable_definitions` straight to `agent.definition` and never dispatches
15
- // an `agentDefinition/*` action. `settings` is where model choice, reasoning
16
- // effort and GROUNDING live — so this was the client write that made D159's
17
- // "grounding stayed on in production" reproducible while the Builder's own
18
- // saves busted correctly. `meta.arg` is `{ agentId }`, already handled below.
19
- //
20
- // ⚠️ This entry makes the miss harmless; it does not make the path right. Two
21
- // parallel writers of one row is the real defect — see FOUND_DEFECTS D159/D160
22
- // for the recommendation to fold this onto `agentDefinition/saveField`.
23
- "agentSettings/saveAgentSettings/fulfilled"
11
+ "agentDefinition/purgeVersions/fulfilled"
24
12
  ]);
25
13
  function extractAgentId(action) {
26
14
  if (!action || typeof action !== "object") return null;