@ai-matrx/chat 0.3.33 → 0.4.0
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.
- package/CHANGELOG.md +20 -0
- package/dist/agents/components/ambient-assistant/intelligence-places.js +2 -2
- package/dist/agents/components/chat/intelligence-places.js +7 -7
- package/dist/agents/components/inputs/smart-input/RunToolPicker.js +7 -13
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPill.js +3 -2
- package/dist/agents/components/inputs/smart-input/composer/useComposerAgent.js +5 -5
- package/dist/agents/components/inputs/smart-input/composer/useComposerAgentFilter.js +3 -2
- package/dist/agents/components/run-controls/RunConfigOverrides.js +10 -16
- package/dist/agents/components/run-controls/panels/shared.d.ts +0 -1
- package/dist/agents/hooks/useAgentModelLabel.js +4 -3
- package/dist/agents/hooks/useDiffEnrichment.js +3 -5
- package/dist/agents/hooks/useModelControls.d.ts +5 -161
- package/dist/agents/identity/model-catalog.d.ts +37 -0
- package/dist/agents/identity/model-catalog.js +103 -0
- package/dist/agents/redux/agent-definition/selectors.d.ts +0 -237
- package/dist/agents/redux/agent-definition/thunks.d.ts +1 -1
- package/dist/agents/redux/agent-settings/agentSettingsSlice.d.ts +1 -1
- package/dist/agents/redux/agent-settings/agentSettingsSlice.js +4 -6
- package/dist/agents/redux/agent-settings/selectors.d.ts +1 -152
- package/dist/agents/redux/agent-settings/selectors.js +0 -39
- package/dist/agents/redux/agent-settings/useNormalizedControls.d.ts +8 -0
- package/dist/agents/redux/agent-settings/useNormalizedControls.js +24 -0
- package/dist/agents/redux/agent-shortcut-categories/selectors.d.ts +0 -50
- package/dist/agents/redux/agent-shortcuts/selectors.d.ts +0 -147
- package/dist/agents/redux/conversation-history/selectors.d.ts +0 -16
- package/dist/agents/redux/conversation-list/conversation-list.selectors.d.ts +0 -2
- package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.d.ts +0 -54
- package/dist/agents/redux/execution-system/context-state/context-state.selectors.d.ts +0 -14
- package/dist/agents/redux/execution-system/conversations/conversations.selectors.d.ts +0 -5
- package/dist/agents/redux/execution-system/instance-context/instance-context.selectors.d.ts +0 -3
- package/dist/agents/redux/execution-system/instance-resources/instance-resources.selectors.d.ts +0 -8
- package/dist/agents/redux/execution-system/instance-ui-state/instance-ui-state.selectors.d.ts +0 -5
- package/dist/agents/redux/execution-system/instance-variable-values/instance-variable-values.selectors.d.ts +0 -7
- package/dist/agents/redux/execution-system/messages/messages.selectors.d.ts +0 -1
- package/dist/agents/redux/execution-system/observability/observability.selectors.d.ts +0 -7
- package/dist/agents/redux/execution-system/observational-memory/observational-memory.selectors.d.ts +0 -1
- package/dist/agents/redux/execution-system/selectors/aggregate.selectors.d.ts +0 -14
- package/dist/agents/redux/execution-system/thunks/execute-manual-instance.thunk.js +2 -2
- package/dist/agents/redux/model-registry.d.ts +6 -4
- package/dist/agents/redux/model-registry.js +23 -5
- package/dist/agents/redux/proposed-directives/proposedDirectivesSlice.d.ts +0 -1
- package/dist/agents/redux/tools/tools.selectors.d.ts +0 -1
- package/dist/agents/runtime/generation-job.js +4 -7
- package/dist/agents/runtime/get-model-capabilities.js +3 -3
- package/dist/agents/ui-first-tools/redux/agent-lists.selectors.d.ts +0 -2
- package/dist/host/db-types.d.ts +276 -9
- package/dist/store/create-chat-store.d.ts +0 -2
- package/dist/store/middlewares.d.ts +0 -5
- package/dist/store/slices.d.ts +0 -1
- package/dist/store/slices.js +0 -2
- package/dist/surfaces/redux/selectors.d.ts +0 -2
- package/dist/tool-call-visualization/intelligence-places.js +1 -1
- package/dist/tool-call-visualization/redux/selectors.d.ts +0 -1
- package/dist/voice-agent/intelligence-places.js +6 -6
- package/package.json +5 -5
- package/dist/agents/model-registry/modelRegistrySlice.d.ts +0 -691
- package/dist/agents/model-registry/modelRegistrySlice.js +0 -574
- package/dist/host/model-class.d.ts +0 -33
- package/dist/host/model-class.js +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
Agent core B3 + the B2 tail — every piece of agent and model state has one holder:
|
|
6
|
+
|
|
7
|
+
- **The model registry slice is retired.** `modelRegistry` is gone from `chatReducers`; model records
|
|
8
|
+
(options, full records with controls, pinned-class configs, class labels, identities) live in the core
|
|
9
|
+
model catalog (`@ai-matrx/agents/models` 0.52+, `catalog.records`), bound once per page by
|
|
10
|
+
`agents/identity/model-catalog` (`getModelCatalog`, `getModelRecords`, `readModelRecords`,
|
|
11
|
+
`useModelRecords`, `useModelRecord`, `useModelLabel`, `useModelLabelWithClass`, `useModelClassLabels`,
|
|
12
|
+
`useModelClassControls`). `agents/redux/model-registry` re-exports the core selectors, which take the
|
|
13
|
+
records state. `agents/model-registry/modelRegistrySlice` and the `host/model-class` port are deleted;
|
|
14
|
+
`selectNormalizedControls` / `selectEffectiveModelName` became `useNormalizedControls(agentId)`
|
|
15
|
+
(`agents/redux/agent-settings/useNormalizedControls`).
|
|
16
|
+
- **The run tier is never copied onto the agent record**: selectors complete the record from the core run
|
|
17
|
+
tier store at read time (`agents/redux/agent-definition/run-tier-record`); a field the record read itself wins.
|
|
18
|
+
- G3 `check:one-holder`: the model part and the run-tier projection are hard bans (self-tested).
|
|
19
|
+
- Intelligence places name the package's real paths (`apps/shared/chat/src/...`).
|
|
20
|
+
- **Consumer action:** host — make `getModelCatalog()` return chat's instance, hydrate shell model rows with
|
|
21
|
+
`getModelRecords().hydrate(...)`, drop `registerChatModelClassHooks`, repoint `modelRegistrySlice` imports.
|
|
22
|
+
|
|
3
23
|
## 0.3.33
|
|
4
24
|
|
|
5
25
|
- **Opening a chat never asks for an organization.** `launchAgentExecution` asks before opening only
|
|
@@ -3,14 +3,14 @@ const K = MANDATE_KEYS;
|
|
|
3
3
|
const AMBIENT_PLACES = {
|
|
4
4
|
feature: "ambient",
|
|
5
5
|
label: "Ambient assistant",
|
|
6
|
-
roots: ["
|
|
6
|
+
roots: ["apps/shared/chat/src/agents/components/ambient-assistant"],
|
|
7
7
|
places: [
|
|
8
8
|
{
|
|
9
9
|
id: "page-guidance",
|
|
10
10
|
label: "Any page",
|
|
11
11
|
trigger: "The page assistant (where a module has none of its own)",
|
|
12
12
|
mandateKeys: [K.ambient__page_guidance],
|
|
13
|
-
sources: ["
|
|
13
|
+
sources: ["apps/shared/chat/src/agents/components/ambient-assistant/ambientAssistantMandates.ts"]
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
id: "listen",
|
|
@@ -15,7 +15,7 @@ const CHAT_PLACES = {
|
|
|
15
15
|
feature: "chat",
|
|
16
16
|
label: "Chat",
|
|
17
17
|
aliases: { DEFAULT_NEW_CHAT_MANDATE_KEY },
|
|
18
|
-
roots: ["
|
|
18
|
+
roots: ["apps/shared/chat/src/agents/components/chat", "app/(core)/chat"],
|
|
19
19
|
places: [
|
|
20
20
|
{
|
|
21
21
|
id: "new",
|
|
@@ -25,9 +25,9 @@ const CHAT_PLACES = {
|
|
|
25
25
|
mandateKeys: [K.chat__default_new_chat],
|
|
26
26
|
sources: [
|
|
27
27
|
"app/(core)/chat/new/page.tsx",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
28
|
+
"apps/shared/chat/src/agents/components/chat/ChatNewClient.tsx",
|
|
29
|
+
"apps/shared/chat/src/agents/components/chat/ChatNewHeader.tsx",
|
|
30
|
+
"apps/shared/chat/src/agents/components/chat/NewChatGreeting.tsx"
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
{
|
|
@@ -46,8 +46,8 @@ const CHAT_PLACES = {
|
|
|
46
46
|
mandateKeys: [K.chat__default_new_chat],
|
|
47
47
|
sources: [
|
|
48
48
|
"app/(core)/chat/[conversationId]/page.tsx",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
49
|
+
"apps/shared/chat/src/agents/components/chat/ChatConversationRoom.tsx",
|
|
50
|
+
"apps/shared/chat/src/agents/components/chat/ChatRoomClient.tsx"
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
{
|
|
@@ -69,7 +69,7 @@ const CHAT_PLACES = {
|
|
|
69
69
|
K.chat__response_mode_data,
|
|
70
70
|
K.chat__response_mode_brainstorm
|
|
71
71
|
],
|
|
72
|
-
sources: ["
|
|
72
|
+
sources: ["apps/shared/chat/src/cx-chat/components/agent/local-agents.ts"]
|
|
73
73
|
}
|
|
74
74
|
]
|
|
75
75
|
};
|
|
@@ -30,18 +30,14 @@ import {
|
|
|
30
30
|
} from "../../../redux/agent-definition/selectors.js";
|
|
31
31
|
import { fetchAgentRunControls } from "../../../redux/agent-definition/thunks.js";
|
|
32
32
|
import { selectAgentIdFromInstance } from "../../../redux/execution-system/conversations/conversations.selectors.js";
|
|
33
|
-
import {
|
|
34
|
-
selectAllModels,
|
|
35
|
-
selectModelFullyLoaded,
|
|
36
|
-
fetchModelById
|
|
37
|
-
} from "../../../model-registry/modelRegistrySlice.js";
|
|
33
|
+
import { selectAllModels, selectModelFullyLoaded } from "@ai-matrx/agents/models";
|
|
38
34
|
import {
|
|
39
35
|
useModelControls,
|
|
40
36
|
supportsTools
|
|
41
37
|
} from "../../../hooks/useModelControls.js";
|
|
42
38
|
import { selectInstanceOverrideState } from "../../../redux/execution-system/instance-model-overrides/instance-model-overrides.selectors.js";
|
|
43
39
|
import { effectiveOfferingPin } from "../../../redux/execution-system/instance-model-overrides/offering-pin.js";
|
|
44
|
-
import { useModelClassControls } from "
|
|
40
|
+
import { getModelRecords, useModelClassControls, useModelRecords } from "../../../identity/model-catalog.js";
|
|
45
41
|
import { selectBuilderAdvancedSettings } from "../../../redux/execution-system/instance-ui-state/instance-ui-state.selectors.js";
|
|
46
42
|
import { setBuilderAdvancedSettings } from "../../../redux/execution-system/instance-ui-state/instance-ui-state.slice.js";
|
|
47
43
|
import { DEFAULT_BUILDER_ADVANCED_SETTINGS } from "../../../types/instance.types.js";
|
|
@@ -73,16 +69,14 @@ function RunToolPicker({ conversationId }) {
|
|
|
73
69
|
selectInstanceOverrideState(conversationId)
|
|
74
70
|
);
|
|
75
71
|
const effectiveModelId = overrideState?.overrides?.model ?? overrideState?.baseSettings?.model ?? "";
|
|
76
|
-
const models =
|
|
77
|
-
const modelIsFull =
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
const modelRegistryLoading = useAppSelector((s) => s.modelRegistry.isLoading);
|
|
72
|
+
const models = useModelRecords(selectAllModels);
|
|
73
|
+
const modelIsFull = useModelRecords((s) => selectModelFullyLoaded(s, effectiveModelId));
|
|
74
|
+
const modelRegistryLoading = useModelRecords((s) => s.isLoading);
|
|
81
75
|
useEffect(() => {
|
|
82
76
|
if (effectiveModelId && !modelIsFull && !modelRegistryLoading) {
|
|
83
|
-
void
|
|
77
|
+
void getModelRecords().loadModel(effectiveModelId);
|
|
84
78
|
}
|
|
85
|
-
}, [effectiveModelId, modelIsFull, modelRegistryLoading
|
|
79
|
+
}, [effectiveModelId, modelIsFull, modelRegistryLoading]);
|
|
86
80
|
const classControls = useModelClassControls(
|
|
87
81
|
effectiveModelId,
|
|
88
82
|
effectiveOfferingPin(overrideState)
|
|
@@ -21,7 +21,8 @@ import {
|
|
|
21
21
|
import { useSessionKnob } from "../../../../../host/prefs-react.js";
|
|
22
22
|
import { knobRefusalSentence, setKnobOverride } from "../../../../../host/prefs.js";
|
|
23
23
|
import { CHAT_DEFAULT_MODEL_KNOB } from "../../../../../ui/chat-default-model-knob.js";
|
|
24
|
-
import { selectModelLabelWithClass } from "
|
|
24
|
+
import { selectModelLabelWithClass } from "@ai-matrx/agents/models";
|
|
25
|
+
import { useModelRecords } from "../../../../identity/model-catalog.js";
|
|
25
26
|
import {
|
|
26
27
|
ComposerMenuDivider,
|
|
27
28
|
ComposerMenuHelp,
|
|
@@ -173,7 +174,7 @@ function ChatPresetsPanel({
|
|
|
173
174
|
const personalModelId = typeof personalModel === "string" && personalModel.trim() ? personalModel : null;
|
|
174
175
|
const overrideState = useAppSelector(selectInstanceOverrideState(conversationId));
|
|
175
176
|
const pinnedOfferingId = effectiveOfferingPin(overrideState);
|
|
176
|
-
const personalModelLabel =
|
|
177
|
+
const personalModelLabel = useModelRecords((s) => selectModelLabelWithClass(s, personalModelId, pinnedOfferingId)) ?? null;
|
|
177
178
|
const onSelectAgent = agentControl?.onSelectAgent;
|
|
178
179
|
const agentFilter = useComposerAgentFilter(conversationId);
|
|
179
180
|
if (!onSelectAgent) {
|
|
@@ -12,9 +12,9 @@ import { selectInstanceOverrideState } from "../../../../redux/execution-system/
|
|
|
12
12
|
import {
|
|
13
13
|
selectModelLabelById,
|
|
14
14
|
selectModelLabelWithClass
|
|
15
|
-
} from "
|
|
15
|
+
} from "@ai-matrx/agents/models";
|
|
16
16
|
import { useModelOptions } from "../../../../../host/ui-slots.js";
|
|
17
|
-
import { useModelClassLabels } from "
|
|
17
|
+
import { useModelClassLabels, useModelRecords } from "../../../../identity/model-catalog.js";
|
|
18
18
|
import { useEffectiveClassPin } from "../../../../redux/execution-system/instance-model-overrides/useEffectiveClassPin.js";
|
|
19
19
|
import { ensureAgentCatalog, useAgentName } from "../../../../identity/agent-identity.js";
|
|
20
20
|
const CHAT_AGENT_TAG = "chat-agent";
|
|
@@ -49,14 +49,14 @@ function useComposerAgent(conversationId) {
|
|
|
49
49
|
const classPins = useEffectiveClassPin(conversationId);
|
|
50
50
|
const effectivePin = classPins.effectivePin ?? null;
|
|
51
51
|
const agentOwnPin = classPins.basePin ?? null;
|
|
52
|
-
const effectiveModelLabel =
|
|
52
|
+
const effectiveModelLabel = useModelRecords((state) => selectModelLabelWithClass(state, effectiveModelId, effectivePin)) ?? null;
|
|
53
53
|
const agentOwnModelId = useAgentOwnModelId(conversationId);
|
|
54
|
-
const agentModelLabel =
|
|
54
|
+
const agentModelLabel = useModelRecords((state) => selectModelLabelWithClass(state, agentOwnModelId, agentOwnPin)) ?? null;
|
|
55
55
|
const { mandate: customMandate } = useMandate(MANDATE_KEYS.chat__default_new_chat, { optional: true });
|
|
56
56
|
const customAgentId = customMandate?.agentId ?? null;
|
|
57
57
|
const rows = useAgentCatalogRows();
|
|
58
58
|
const presetRows = rows.filter(isPresetRow);
|
|
59
|
-
const modelLabels =
|
|
59
|
+
const modelLabels = useModelRecords(
|
|
60
60
|
(state) => presetRows.map((row) => selectModelLabelById(state, row.modelId) ?? null).join("\0")
|
|
61
61
|
).split("\0");
|
|
62
62
|
const presets = presetRows.map((row, index) => ({
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useAppSelector } from "../../../../../store/hooks.js";
|
|
3
3
|
import { selectBuilderAdvancedSettings } from "../../../../redux/execution-system/instance-ui-state/instance-ui-state.selectors.js";
|
|
4
|
-
import { selectAllModels } from "
|
|
4
|
+
import { selectAllModels } from "@ai-matrx/agents/models";
|
|
5
|
+
import { useModelRecords } from "../../../../identity/model-catalog.js";
|
|
5
6
|
import { readOutputTypes } from "./output-selection.js";
|
|
6
7
|
import { agentOutputFilterSpec, modelMakesAny, modelOutputModalities } from "./agent-output-filter.js";
|
|
7
8
|
function useComposerAgentFilter(conversationId) {
|
|
8
9
|
const settings = useAppSelector(selectBuilderAdvancedSettings(conversationId));
|
|
9
|
-
const models =
|
|
10
|
+
const models = useModelRecords(selectAllModels);
|
|
10
11
|
const spec = agentOutputFilterSpec(readOutputTypes(settings?.outputTypes));
|
|
11
12
|
if (!spec) return void 0;
|
|
12
13
|
const outputsById = new Map(models.map((model) => [model.id, modelOutputModalities(model.capabilities)]));
|
|
@@ -8,12 +8,10 @@ import { useAppDispatch, useAppSelector, useAppStore } from "../../../store/hook
|
|
|
8
8
|
import {
|
|
9
9
|
selectAllModels,
|
|
10
10
|
selectModelFullyLoaded,
|
|
11
|
-
fetchModelById,
|
|
12
|
-
retryModelDetail,
|
|
13
11
|
selectModelDetailError
|
|
14
|
-
} from "
|
|
12
|
+
} from "@ai-matrx/agents/models";
|
|
15
13
|
import { useModelControls } from "../../hooks/useModelControls.js";
|
|
16
|
-
import { useModelClassControls } from "
|
|
14
|
+
import { getModelRecords, useModelClassControls, useModelRecords } from "../../identity/model-catalog.js";
|
|
17
15
|
import {
|
|
18
16
|
selectInstanceOverrideState,
|
|
19
17
|
selectSettingsOverridesForApi
|
|
@@ -88,7 +86,7 @@ function RunConfigOverrides({
|
|
|
88
86
|
const overrideState = useAppSelector(
|
|
89
87
|
selectInstanceOverrideState(conversationId)
|
|
90
88
|
);
|
|
91
|
-
const models =
|
|
89
|
+
const models = useModelRecords(selectAllModels);
|
|
92
90
|
const overrideJson = useAppSelector(
|
|
93
91
|
(state) => JSON.stringify(
|
|
94
92
|
selectSettingsOverridesForApi(conversationId)(state) ?? {},
|
|
@@ -133,18 +131,14 @@ function RunConfigOverrides({
|
|
|
133
131
|
const effectiveOffering = removals.includes("offering_id") ? nullDefaults?.offering_id : overrides.offering_id ?? base.offering_id;
|
|
134
132
|
const pinnedOfferingId = typeof effectiveOffering === "string" && effectiveOffering ? effectiveOffering : void 0;
|
|
135
133
|
const modelChoiceOverridden = "model" in overrides || "offering_id" in overrides || removals.includes("offering_id");
|
|
136
|
-
const isFull =
|
|
137
|
-
|
|
138
|
-
);
|
|
139
|
-
const modelDetailError = useAppSelector(
|
|
140
|
-
(s) => selectModelDetailError(s, effectiveModelId)
|
|
141
|
-
);
|
|
142
|
-
const registryLoading = useAppSelector((s) => s.modelRegistry.isLoading);
|
|
134
|
+
const isFull = useModelRecords((s) => selectModelFullyLoaded(s, effectiveModelId));
|
|
135
|
+
const modelDetailError = useModelRecords((s) => selectModelDetailError(s, effectiveModelId));
|
|
136
|
+
const registryLoading = useModelRecords((s) => s.isLoading);
|
|
143
137
|
useEffect(() => {
|
|
144
138
|
if (effectiveModelId && !isFull && !registryLoading) {
|
|
145
|
-
|
|
139
|
+
void getModelRecords().loadModel(effectiveModelId);
|
|
146
140
|
}
|
|
147
|
-
}, [
|
|
141
|
+
}, [effectiveModelId, isFull, registryLoading]);
|
|
148
142
|
const classControls = useModelClassControls(effectiveModelId, pinnedOfferingId);
|
|
149
143
|
const { normalizedControls } = useModelControls(
|
|
150
144
|
models,
|
|
@@ -194,8 +188,8 @@ function RunConfigOverrides({
|
|
|
194
188
|
{
|
|
195
189
|
variant: "outline",
|
|
196
190
|
onClick: () => {
|
|
197
|
-
|
|
198
|
-
void
|
|
191
|
+
getModelRecords().retryModel(effectiveModelId);
|
|
192
|
+
void getModelRecords().loadModel(effectiveModelId);
|
|
199
193
|
},
|
|
200
194
|
children: "Retry"
|
|
201
195
|
}
|
|
@@ -64,7 +64,6 @@ export declare function makeSelectConversationRequests(conversationId: string):
|
|
|
64
64
|
proposedDirectives: import("../../../redux/proposed-directives/proposedDirectivesSlice.js").ProposedDirectivesState;
|
|
65
65
|
agentSettings: import("../../../redux/agent-settings/types.js").AgentSettingsState;
|
|
66
66
|
conversationAttachments: import("../../../connectors/attachments.slice.js").AttachmentsSliceState;
|
|
67
|
-
modelRegistry: import("../../../model-registry/modelRegistrySlice.js").ModelRegistryState;
|
|
68
67
|
chatHost: import("../../../../store/chat-host.slice.js").ChatHostState;
|
|
69
68
|
} & import("../../../../store/root-state.js").ChatHostReadSlices) => ActiveRequest[]) & {
|
|
70
69
|
clearCache: () => void;
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
selectModelLabelById,
|
|
9
9
|
selectModelLabelWithClass
|
|
10
|
-
} from "
|
|
11
|
-
import { useModelClassLabels } from "
|
|
10
|
+
} from "@ai-matrx/agents/models";
|
|
11
|
+
import { useModelClassLabels, useModelLabel, useModelRecords } from "../identity/model-catalog.js";
|
|
12
12
|
import { useAgentSummaryRow } from "../identity/agent-identity.js";
|
|
13
13
|
function useAgentModelLabel(agentId) {
|
|
14
14
|
useModelClassLabels();
|
|
@@ -21,7 +21,8 @@ function useAgentModelLabel(agentId) {
|
|
|
21
21
|
);
|
|
22
22
|
const modelId = ownModelId ?? summary?.modelId ?? null;
|
|
23
23
|
const offeringId = ownOfferingId !== void 0 ? ownOfferingId : summary?.offeringId;
|
|
24
|
-
|
|
24
|
+
useModelLabel(modelId);
|
|
25
|
+
const label = useModelRecords(
|
|
25
26
|
(state) => offeringId === void 0 ? selectModelLabelById(state, modelId) : selectModelLabelWithClass(state, modelId, offeringId)
|
|
26
27
|
);
|
|
27
28
|
return { modelId, offeringId, label };
|
|
@@ -6,15 +6,13 @@ import {
|
|
|
6
6
|
selectToolIdentityMap
|
|
7
7
|
} from "../redux/tools/tools.selectors.js";
|
|
8
8
|
import { selectMcpCatalog } from "../redux/mcp/mcp.slice.js";
|
|
9
|
-
import {
|
|
9
|
+
import { useModelRecords } from "../identity/model-catalog.js";
|
|
10
10
|
function useDiffEnrichment() {
|
|
11
11
|
const allTools = useAppSelector(selectAllTools);
|
|
12
12
|
const toolIdentities = useAppSelector(selectToolIdentityMap);
|
|
13
13
|
const mcpCatalog = useAppSelector(selectMcpCatalog);
|
|
14
|
-
const modelEntities =
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
const modelIdentities = useAppSelector(selectModelIdentityMap);
|
|
14
|
+
const modelEntities = useModelRecords((s) => s.entities);
|
|
15
|
+
const modelIdentities = useModelRecords((s) => s.identityById);
|
|
18
16
|
return useMemo(
|
|
19
17
|
() => ({
|
|
20
18
|
resolveModelId: (id) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hook to parse and normalize model controls from dynamic API data
|
|
3
3
|
* Keeps snake_case naming for compatibility with Python backend
|
|
4
4
|
*/
|
|
5
|
-
import type { ModelClassControls } from "
|
|
5
|
+
import type { ModelClassControls } from "../identity/model-catalog.js";
|
|
6
6
|
import type { AIModelRecord } from "../redux/model-registry.js";
|
|
7
7
|
export interface ControlDefinition {
|
|
8
8
|
type: "number" | "integer" | "boolean" | "string" | "enum" | "array" | "string_array" | "object_array";
|
|
@@ -160,89 +160,11 @@ export declare function useModelControls(models: AIModelRecord[], selectedModelI
|
|
|
160
160
|
error: string;
|
|
161
161
|
} | {
|
|
162
162
|
normalizedControls: NormalizedControls;
|
|
163
|
-
selectedModel:
|
|
164
|
-
capabilities: import("../../host/db-types.js").Json | null;
|
|
165
|
-
common_name: string | null;
|
|
166
|
-
context_window: number | null;
|
|
167
|
-
cost_rating: number | null;
|
|
168
|
-
created_at: string;
|
|
169
|
-
created_by: string | null;
|
|
170
|
-
deleted_at: string | null;
|
|
171
|
-
description: string | null;
|
|
172
|
-
guest_fallback_id: string | null;
|
|
173
|
-
id: string;
|
|
174
|
-
is_deprecated: boolean | null;
|
|
175
|
-
is_premium: boolean | null;
|
|
176
|
-
is_primary: boolean | null;
|
|
177
|
-
is_system: boolean;
|
|
178
|
-
max_tokens: number | null;
|
|
179
|
-
metadata: import("../../host/db-types.js").Json;
|
|
180
|
-
mid_fallback_id: string | null;
|
|
181
|
-
name: string;
|
|
182
|
-
organization_id: string;
|
|
183
|
-
provider_id: string | null;
|
|
184
|
-
published_to_web: boolean;
|
|
185
|
-
published_to_web_at: string | null;
|
|
186
|
-
published_to_web_by: string | null;
|
|
187
|
-
release_date: string | null;
|
|
188
|
-
retired_at: string | null;
|
|
189
|
-
retry_fallback_id: string | null;
|
|
190
|
-
retry_max_attempts: number;
|
|
191
|
-
shown_to: import("../../host/db-types.js").Database["platform"]["Enums"]["shown_to"] | null;
|
|
192
|
-
speed_rating: number | null;
|
|
193
|
-
successor_id: string | null;
|
|
194
|
-
updated_at: string;
|
|
195
|
-
updated_by: string | null;
|
|
196
|
-
version: number;
|
|
197
|
-
visibility: import("../../host/db-types.js").Database["platform"]["Enums"]["visibility"];
|
|
198
|
-
_fetchType: import("../model-registry/modelRegistrySlice.js").ModelRecordFetchType;
|
|
199
|
-
maker: string | null;
|
|
200
|
-
controls: unknown;
|
|
201
|
-
constraints: unknown;
|
|
202
|
-
};
|
|
163
|
+
selectedModel: AIModelRecord;
|
|
203
164
|
error: null;
|
|
204
165
|
} | {
|
|
205
166
|
normalizedControls: NormalizedControls;
|
|
206
|
-
selectedModel:
|
|
207
|
-
capabilities: import("../../host/db-types.js").Json | null;
|
|
208
|
-
common_name: string | null;
|
|
209
|
-
context_window: number | null;
|
|
210
|
-
cost_rating: number | null;
|
|
211
|
-
created_at: string;
|
|
212
|
-
created_by: string | null;
|
|
213
|
-
deleted_at: string | null;
|
|
214
|
-
description: string | null;
|
|
215
|
-
guest_fallback_id: string | null;
|
|
216
|
-
id: string;
|
|
217
|
-
is_deprecated: boolean | null;
|
|
218
|
-
is_premium: boolean | null;
|
|
219
|
-
is_primary: boolean | null;
|
|
220
|
-
is_system: boolean;
|
|
221
|
-
max_tokens: number | null;
|
|
222
|
-
metadata: import("../../host/db-types.js").Json;
|
|
223
|
-
mid_fallback_id: string | null;
|
|
224
|
-
name: string;
|
|
225
|
-
organization_id: string;
|
|
226
|
-
provider_id: string | null;
|
|
227
|
-
published_to_web: boolean;
|
|
228
|
-
published_to_web_at: string | null;
|
|
229
|
-
published_to_web_by: string | null;
|
|
230
|
-
release_date: string | null;
|
|
231
|
-
retired_at: string | null;
|
|
232
|
-
retry_fallback_id: string | null;
|
|
233
|
-
retry_max_attempts: number;
|
|
234
|
-
shown_to: import("../../host/db-types.js").Database["platform"]["Enums"]["shown_to"] | null;
|
|
235
|
-
speed_rating: number | null;
|
|
236
|
-
successor_id: string | null;
|
|
237
|
-
updated_at: string;
|
|
238
|
-
updated_by: string | null;
|
|
239
|
-
version: number;
|
|
240
|
-
visibility: import("../../host/db-types.js").Database["platform"]["Enums"]["visibility"];
|
|
241
|
-
_fetchType: import("../model-registry/modelRegistrySlice.js").ModelRecordFetchType;
|
|
242
|
-
maker: string | null;
|
|
243
|
-
controls: unknown;
|
|
244
|
-
constraints: unknown;
|
|
245
|
-
};
|
|
167
|
+
selectedModel: AIModelRecord;
|
|
246
168
|
error: string;
|
|
247
169
|
};
|
|
248
170
|
/**
|
|
@@ -265,89 +187,11 @@ export declare function resolveModelControls(models: AIModelRecord[], selectedMo
|
|
|
265
187
|
error: string;
|
|
266
188
|
} | {
|
|
267
189
|
normalizedControls: NormalizedControls;
|
|
268
|
-
selectedModel:
|
|
269
|
-
capabilities: import("../../host/db-types.js").Json | null;
|
|
270
|
-
common_name: string | null;
|
|
271
|
-
context_window: number | null;
|
|
272
|
-
cost_rating: number | null;
|
|
273
|
-
created_at: string;
|
|
274
|
-
created_by: string | null;
|
|
275
|
-
deleted_at: string | null;
|
|
276
|
-
description: string | null;
|
|
277
|
-
guest_fallback_id: string | null;
|
|
278
|
-
id: string;
|
|
279
|
-
is_deprecated: boolean | null;
|
|
280
|
-
is_premium: boolean | null;
|
|
281
|
-
is_primary: boolean | null;
|
|
282
|
-
is_system: boolean;
|
|
283
|
-
max_tokens: number | null;
|
|
284
|
-
metadata: import("../../host/db-types.js").Json;
|
|
285
|
-
mid_fallback_id: string | null;
|
|
286
|
-
name: string;
|
|
287
|
-
organization_id: string;
|
|
288
|
-
provider_id: string | null;
|
|
289
|
-
published_to_web: boolean;
|
|
290
|
-
published_to_web_at: string | null;
|
|
291
|
-
published_to_web_by: string | null;
|
|
292
|
-
release_date: string | null;
|
|
293
|
-
retired_at: string | null;
|
|
294
|
-
retry_fallback_id: string | null;
|
|
295
|
-
retry_max_attempts: number;
|
|
296
|
-
shown_to: import("../../host/db-types.js").Database["platform"]["Enums"]["shown_to"] | null;
|
|
297
|
-
speed_rating: number | null;
|
|
298
|
-
successor_id: string | null;
|
|
299
|
-
updated_at: string;
|
|
300
|
-
updated_by: string | null;
|
|
301
|
-
version: number;
|
|
302
|
-
visibility: import("../../host/db-types.js").Database["platform"]["Enums"]["visibility"];
|
|
303
|
-
_fetchType: import("../model-registry/modelRegistrySlice.js").ModelRecordFetchType;
|
|
304
|
-
maker: string | null;
|
|
305
|
-
controls: unknown;
|
|
306
|
-
constraints: unknown;
|
|
307
|
-
};
|
|
190
|
+
selectedModel: AIModelRecord;
|
|
308
191
|
error: null;
|
|
309
192
|
} | {
|
|
310
193
|
normalizedControls: NormalizedControls;
|
|
311
|
-
selectedModel:
|
|
312
|
-
capabilities: import("../../host/db-types.js").Json | null;
|
|
313
|
-
common_name: string | null;
|
|
314
|
-
context_window: number | null;
|
|
315
|
-
cost_rating: number | null;
|
|
316
|
-
created_at: string;
|
|
317
|
-
created_by: string | null;
|
|
318
|
-
deleted_at: string | null;
|
|
319
|
-
description: string | null;
|
|
320
|
-
guest_fallback_id: string | null;
|
|
321
|
-
id: string;
|
|
322
|
-
is_deprecated: boolean | null;
|
|
323
|
-
is_premium: boolean | null;
|
|
324
|
-
is_primary: boolean | null;
|
|
325
|
-
is_system: boolean;
|
|
326
|
-
max_tokens: number | null;
|
|
327
|
-
metadata: import("../../host/db-types.js").Json;
|
|
328
|
-
mid_fallback_id: string | null;
|
|
329
|
-
name: string;
|
|
330
|
-
organization_id: string;
|
|
331
|
-
provider_id: string | null;
|
|
332
|
-
published_to_web: boolean;
|
|
333
|
-
published_to_web_at: string | null;
|
|
334
|
-
published_to_web_by: string | null;
|
|
335
|
-
release_date: string | null;
|
|
336
|
-
retired_at: string | null;
|
|
337
|
-
retry_fallback_id: string | null;
|
|
338
|
-
retry_max_attempts: number;
|
|
339
|
-
shown_to: import("../../host/db-types.js").Database["platform"]["Enums"]["shown_to"] | null;
|
|
340
|
-
speed_rating: number | null;
|
|
341
|
-
successor_id: string | null;
|
|
342
|
-
updated_at: string;
|
|
343
|
-
updated_by: string | null;
|
|
344
|
-
version: number;
|
|
345
|
-
visibility: import("../../host/db-types.js").Database["platform"]["Enums"]["visibility"];
|
|
346
|
-
_fetchType: import("../model-registry/modelRegistrySlice.js").ModelRecordFetchType;
|
|
347
|
-
maker: string | null;
|
|
348
|
-
controls: unknown;
|
|
349
|
-
constraints: unknown;
|
|
350
|
-
};
|
|
194
|
+
selectedModel: AIModelRecord;
|
|
351
195
|
error: string;
|
|
352
196
|
};
|
|
353
197
|
/**
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ModelCatalog, type ModelClassConfig, type ModelRecord, type ModelRecords, type ModelRecordsState } from "@ai-matrx/agents/models";
|
|
2
|
+
export declare function getModelCatalog(): ModelCatalog;
|
|
3
|
+
export declare const getModelRecords: () => ModelRecords;
|
|
4
|
+
/** The records state now. A host with no database bound yet (a unit test) reads empty. */
|
|
5
|
+
export declare function readModelRecords(): ModelRecordsState;
|
|
6
|
+
/** Subscribe to a slice of the records. `select` must return a stable value for unchanged state. */
|
|
7
|
+
export declare function useModelRecords<T>(select: (state: ModelRecordsState) => T): T;
|
|
8
|
+
/** One model's record (options or full); reads the full record when `full` and it is missing. */
|
|
9
|
+
export declare function useModelRecord(modelId: string | null | undefined, options?: {
|
|
10
|
+
full?: boolean;
|
|
11
|
+
}): ModelRecord | undefined;
|
|
12
|
+
/** A model's display label; loads the options list (then the identity) when it is unknown. */
|
|
13
|
+
export declare function useModelLabel(modelId: string | null | undefined): string | undefined;
|
|
14
|
+
/** "Qwen3.8 27B · Matrx Lightning" when the model has several classes; loads the class index once. */
|
|
15
|
+
export declare function useModelLabelWithClass(modelId: string | null | undefined, offeringId: string | null | undefined): string | undefined;
|
|
16
|
+
/** Loads every model's classes once (no-op after the first success). */
|
|
17
|
+
export declare function useModelClassLabels(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The resolved controls for the CLASS a model runs on. With a pin it loads that class's controls;
|
|
20
|
+
* without one it answers `undefined` and callers keep the model's own (preferred-class) controls.
|
|
21
|
+
* `{ pending: true }` while it loads, `{ failed: true }` when the pin is refused — never another
|
|
22
|
+
* class's controls.
|
|
23
|
+
*/
|
|
24
|
+
export type ModelClassControls = undefined | {
|
|
25
|
+
pending: true;
|
|
26
|
+
failed?: false;
|
|
27
|
+
config?: undefined;
|
|
28
|
+
} | {
|
|
29
|
+
pending?: false;
|
|
30
|
+
failed: true;
|
|
31
|
+
config?: undefined;
|
|
32
|
+
} | {
|
|
33
|
+
pending?: false;
|
|
34
|
+
failed?: false;
|
|
35
|
+
config: ModelClassConfig;
|
|
36
|
+
};
|
|
37
|
+
export declare function useModelClassControls(modelId: string | null | undefined, offeringId: string | null | undefined): ModelClassControls;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import {
|
|
4
|
+
classConfigKey,
|
|
5
|
+
createModelCatalog,
|
|
6
|
+
EMPTY_MODEL_RECORDS,
|
|
7
|
+
selectModelById,
|
|
8
|
+
selectModelLabelById,
|
|
9
|
+
selectModelLabelWithClass
|
|
10
|
+
} from "@ai-matrx/agents/models";
|
|
11
|
+
import { useModelRecordsSelector } from "@ai-matrx/agents/models/react";
|
|
12
|
+
import { supabase } from "../../host/db.js";
|
|
13
|
+
import { captureError } from "../../host/diagnostics.js";
|
|
14
|
+
import { isSignedOutVisitor } from "../../host/identity.js";
|
|
15
|
+
const KEY = /* @__PURE__ */ Symbol.for("ai-matrx.chat.model-catalog");
|
|
16
|
+
function getModelCatalog() {
|
|
17
|
+
const g = globalThis;
|
|
18
|
+
if (g[KEY]) return g[KEY];
|
|
19
|
+
const catalog = createModelCatalog({
|
|
20
|
+
// supabase-js satisfies the catalog's structural client as-is.
|
|
21
|
+
client: supabase,
|
|
22
|
+
isSignedIn: async () => !await isSignedOutVisitor(),
|
|
23
|
+
errorSink: (event) => {
|
|
24
|
+
captureError({
|
|
25
|
+
source: "supabase-postgrest",
|
|
26
|
+
schema: "ai",
|
|
27
|
+
code: event.code,
|
|
28
|
+
message: event.message,
|
|
29
|
+
...event.context ? { details: JSON.stringify(event.context) } : {}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
g[KEY] = catalog;
|
|
34
|
+
return catalog;
|
|
35
|
+
}
|
|
36
|
+
const getModelRecords = () => getModelCatalog().records;
|
|
37
|
+
function readModelRecords() {
|
|
38
|
+
try {
|
|
39
|
+
return getModelRecords().getState();
|
|
40
|
+
} catch {
|
|
41
|
+
return EMPTY_MODEL_RECORDS;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function useModelRecords(select) {
|
|
45
|
+
return useModelRecordsSelector(getModelRecords(), select);
|
|
46
|
+
}
|
|
47
|
+
function useModelRecord(modelId, options) {
|
|
48
|
+
const record = useModelRecords((s) => selectModelById(s, modelId));
|
|
49
|
+
const full = options?.full === true;
|
|
50
|
+
const fetchType = record?._fetchType;
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!modelId) return;
|
|
53
|
+
if (full && fetchType !== "full") void getModelRecords().loadModel(modelId);
|
|
54
|
+
else if (!fetchType) void getModelRecords().loadOptions();
|
|
55
|
+
}, [modelId, full, fetchType]);
|
|
56
|
+
return record;
|
|
57
|
+
}
|
|
58
|
+
function useModelLabel(modelId) {
|
|
59
|
+
const label = useModelRecords((s) => selectModelLabelById(s, modelId));
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!modelId || label) return;
|
|
62
|
+
const records = getModelRecords();
|
|
63
|
+
void records.loadOptions().then(() => {
|
|
64
|
+
if (!selectModelLabelById(records.getState(), modelId)) void records.loadIdentity(modelId);
|
|
65
|
+
});
|
|
66
|
+
}, [modelId, label]);
|
|
67
|
+
return label;
|
|
68
|
+
}
|
|
69
|
+
function useModelLabelWithClass(modelId, offeringId) {
|
|
70
|
+
useModelLabel(modelId);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
void getModelRecords().loadClasses();
|
|
73
|
+
}, []);
|
|
74
|
+
return useModelRecords((s) => selectModelLabelWithClass(s, modelId, offeringId));
|
|
75
|
+
}
|
|
76
|
+
function useModelClassLabels() {
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
void getModelRecords().loadClasses();
|
|
79
|
+
}, []);
|
|
80
|
+
}
|
|
81
|
+
function useModelClassControls(modelId, offeringId) {
|
|
82
|
+
const key = modelId && offeringId ? classConfigKey(modelId, offeringId) : null;
|
|
83
|
+
const config = useModelRecords((s) => key ? s.classConfigByOffering[key] : void 0);
|
|
84
|
+
const status = useModelRecords((s) => key ? s.classConfigStatusByOffering[key] : void 0);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (modelId && offeringId) void getModelRecords().loadClassConfig(modelId, offeringId);
|
|
87
|
+
}, [modelId, offeringId]);
|
|
88
|
+
if (!modelId || !offeringId) return void 0;
|
|
89
|
+
if (config) return { config };
|
|
90
|
+
if (status === "failed") return { failed: true };
|
|
91
|
+
return { pending: true };
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
getModelCatalog,
|
|
95
|
+
getModelRecords,
|
|
96
|
+
readModelRecords,
|
|
97
|
+
useModelClassControls,
|
|
98
|
+
useModelClassLabels,
|
|
99
|
+
useModelLabel,
|
|
100
|
+
useModelLabelWithClass,
|
|
101
|
+
useModelRecord,
|
|
102
|
+
useModelRecords
|
|
103
|
+
};
|