@ai-matrx/agents 0.59.264 → 0.59.266
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 +55 -0
- package/dist/catalog/index.cjs +233 -5
- package/dist/catalog/index.d.cts +164 -83
- package/dist/catalog/index.d.ts +164 -83
- package/dist/catalog/index.js +233 -5
- package/dist/catalog/native/index.cjs +123 -24
- package/dist/catalog/native/index.d.cts +150 -42
- package/dist/catalog/native/index.d.ts +150 -42
- package/dist/catalog/native/index.js +120 -21
- package/dist/catalog/react/index.cjs +143 -20
- package/dist/catalog/react/index.d.cts +170 -44
- package/dist/catalog/react/index.d.ts +170 -44
- package/dist/catalog/react/index.js +143 -20
- package/dist/generated/provision-offers.cjs +0 -1
- package/dist/generated/provision-offers.d.cts +53 -23
- package/dist/generated/provision-offers.d.ts +53 -23
- package/dist/generated/provision-offers.js +0 -1
- package/dist/models/index.cjs +48 -1
- package/dist/models/index.d.cts +6 -0
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.js +48 -1
- package/dist/models/react/index.d.cts +6 -0
- package/dist/models/react/index.d.ts +6 -0
- package/dist/quick/index.d.cts +1 -1
- package/dist/quick/index.d.ts +1 -1
- package/dist/{types-DZhDqrVE.d.cts → types-5pX8AZBM.d.cts} +10 -0
- package/dist/{types-DZhDqrVE.d.ts → types-5pX8AZBM.d.ts} +10 -0
- package/package.json +2 -28
- package/scripts/check-model-catalog-reads.mjs +1 -1
|
@@ -263,7 +263,7 @@ function AgentCatalogProvider({
|
|
|
263
263
|
var import_react_native12 = require("react-native");
|
|
264
264
|
|
|
265
265
|
// catalog/native/AgentPickerBody.tsx
|
|
266
|
-
var
|
|
266
|
+
var import_react7 = require("react");
|
|
267
267
|
var import_react_native11 = require("react-native");
|
|
268
268
|
|
|
269
269
|
// catalog/shared/useAgentListCore-react.ts
|
|
@@ -841,6 +841,14 @@ function agentListFooterLabel(args) {
|
|
|
841
841
|
return archivedHiddenCount > 0 ? `${base} \xB7 ${archivedHiddenCount} archived hidden` : base;
|
|
842
842
|
}
|
|
843
843
|
|
|
844
|
+
// catalog/store.ts
|
|
845
|
+
var import_core = require("@ai-matrx/associations/core");
|
|
846
|
+
var LIST_TTL_MS = 15 * 60 * 1e3;
|
|
847
|
+
var LIST_STALE_MS = 4 * 60 * 60 * 1e3;
|
|
848
|
+
function agentPickerPageKey(query) {
|
|
849
|
+
return `${query.tab}|${query.archive}|${query.includeQuick ? "q" : "-"}`;
|
|
850
|
+
}
|
|
851
|
+
|
|
844
852
|
// catalog/shared/useAgentListCore-react.ts
|
|
845
853
|
function useAgentListCore({
|
|
846
854
|
consumerId,
|
|
@@ -870,19 +878,60 @@ function useAgentListCore({
|
|
|
870
878
|
const allRows = useAgentCatalogRows();
|
|
871
879
|
const rows = (0, import_react4.useMemo)(() => includeQuickAgents ? allRows : withoutQuickAgents(allRows), [allRows, includeQuickAgents]);
|
|
872
880
|
const userId = catalog.getUserIdOrNull();
|
|
873
|
-
const
|
|
881
|
+
const status = useAgentCatalogState(selectStatus);
|
|
882
|
+
const [setAsideLabel, setSetAsideLabel] = (0, import_react4.useState)(null);
|
|
883
|
+
const activeAgentFilter = agentFilter && setAsideLabel !== agentFilter.label ? agentFilter : null;
|
|
884
|
+
const [facetsWanted, setFacetsWanted] = (0, import_react4.useState)(false);
|
|
885
|
+
const needsFullCatalog = facetsWanted || activeAgentFilter !== null || consumer.state.includedCats.length > 0 || consumer.state.includedTags.length > 0 || consumer.state.favFilter !== "all" || consumer.state.accessFilter !== "any" || !consumer.state.favoritesFirst || consumer.state.sortBy !== "updated-desc";
|
|
886
|
+
const fullCatalogReady = status === "succeeded" && catalog.isFresh();
|
|
887
|
+
const pageQuery = {
|
|
888
|
+
tab: includeSystemInAll && consumer.state.tab === "all" ? "all_system" : consumer.state.tab,
|
|
889
|
+
archive: consumer.state.archFilter,
|
|
890
|
+
includeQuick: includeQuickAgents
|
|
891
|
+
};
|
|
892
|
+
const pageKey = agentPickerPageKey(pageQuery);
|
|
893
|
+
const selectPage = (0, import_react4.useCallback)((state) => state.pickerPages[pageKey], [pageKey]);
|
|
894
|
+
const pageState = useAgentCatalogState(selectPage);
|
|
895
|
+
const pageUnsupported = pageState?.error === "unsupported";
|
|
896
|
+
const paged = catalog.pickerReads === "page" && !needsFullCatalog && !fullCatalogReady && !pageUnsupported;
|
|
897
|
+
const selectById = (0, import_react4.useCallback)((state) => state.byId, []);
|
|
898
|
+
const byId = useAgentCatalogState(selectById);
|
|
899
|
+
const pageRows = (0, import_react4.useMemo)(() => {
|
|
900
|
+
if (!pageState) return [];
|
|
901
|
+
const out = [];
|
|
902
|
+
for (const id of pageState.ids) {
|
|
903
|
+
const row = byId[id];
|
|
904
|
+
if (row) out.push(row);
|
|
905
|
+
}
|
|
906
|
+
return out;
|
|
907
|
+
}, [pageState, byId]);
|
|
908
|
+
const tabCountsForFilter = paged ? {
|
|
909
|
+
mine: pageState?.counts?.mine ?? 0,
|
|
910
|
+
shared: pageState?.counts?.shared ?? 0,
|
|
911
|
+
all: (pageState?.counts?.all ?? 0) + (includeSystemInAll ? pageState?.counts?.system ?? 0 : 0),
|
|
912
|
+
system: pageState?.counts?.system ?? 0
|
|
913
|
+
} : selectAgentTabCounts(rows, consumer.state.archFilter);
|
|
874
914
|
const ownedCount = tabCountsForFilter.mine;
|
|
875
915
|
const selectFiltered = (0, import_react4.useMemo)(
|
|
876
916
|
() => makeSelectFilteredAgents(includeSystemInAll),
|
|
877
917
|
[includeSystemInAll]
|
|
878
918
|
);
|
|
879
|
-
const
|
|
919
|
+
const searchPool = (0, import_react4.useMemo)(() => {
|
|
920
|
+
if (!paged || !consumer.state.searchTerm) return null;
|
|
921
|
+
const pool = /* @__PURE__ */ new Map();
|
|
922
|
+
for (const row of pageRows) pool.set(row.id, row);
|
|
923
|
+
for (const id of consumer.state.serverMatchedIds) {
|
|
924
|
+
const row = byId[id];
|
|
925
|
+
if (row) pool.set(id, row);
|
|
926
|
+
}
|
|
927
|
+
const list = [...pool.values()];
|
|
928
|
+
return includeQuickAgents ? list : withoutQuickAgents(list);
|
|
929
|
+
}, [paged, consumer.state.searchTerm, consumer.state.serverMatchedIds, pageRows, byId, includeQuickAgents]);
|
|
930
|
+
const filteredAgents = paged ? searchPool ? selectFiltered(searchPool, consumer.state) : pageRows : selectFiltered(rows, consumer.state);
|
|
880
931
|
const excludedAgentIds = (0, import_react4.useMemo)(
|
|
881
932
|
() => new Set(excludeAgentIds),
|
|
882
933
|
[excludeAgentIds]
|
|
883
934
|
);
|
|
884
|
-
const [setAsideLabel, setSetAsideLabel] = (0, import_react4.useState)(null);
|
|
885
|
-
const activeAgentFilter = agentFilter && setAsideLabel !== agentFilter.label ? agentFilter : null;
|
|
886
935
|
const filterTest = activeAgentFilter?.test;
|
|
887
936
|
const applyExcludes = (0, import_react4.useCallback)(
|
|
888
937
|
(list) => excludedAgentIds.size === 0 && !filterTest ? list : list.filter(
|
|
@@ -905,23 +954,44 @@ function useAgentListCore({
|
|
|
905
954
|
() => ({ ...consumer.state, archFilter: "archived" }),
|
|
906
955
|
[consumer.state]
|
|
907
956
|
);
|
|
908
|
-
const archivedHiddenCount = consumer.archFilter
|
|
909
|
-
const status = useAgentCatalogState(selectStatus);
|
|
957
|
+
const archivedHiddenCount = consumer.archFilter !== "active" || paged && consumer.state.searchTerm ? 0 : paged ? pageState?.counts?.archivedHidden ?? 0 : applyExcludes(selectArchivedProbe(rows, archiveProbeState)).length;
|
|
910
958
|
const activeAgentId = activeAgentIdOverride ?? null;
|
|
911
|
-
const pinnedAgent = activeAgentId ?
|
|
959
|
+
const pinnedAgent = activeAgentId ? byId[activeAgentId] : void 0;
|
|
912
960
|
const onSystemTab = consumer.tab === "system";
|
|
913
961
|
const allCategories = onSystemTab ? selectAllSystemAgentCategories(rows) : selectAllAgentCategories(rows);
|
|
914
962
|
const allTags = onSystemTab ? selectAllSystemAgentTags(rows) : selectAllAgentTags(rows);
|
|
915
963
|
const tabCounts = tabCountsForFilter;
|
|
916
|
-
const
|
|
917
|
-
const
|
|
964
|
+
const [engaged, setEngaged] = (0, import_react4.useState)(false);
|
|
965
|
+
const pageStatus = pageState?.status ?? "idle";
|
|
966
|
+
const isLoading = paged ? (pageStatus === "loading" || pageStatus === "idle") && pageRows.length === 0 && engaged : status === "loading";
|
|
967
|
+
const agentsLoaded = paged ? pageStatus === "succeeded" || pageStatus === "failed" : status === "succeeded" || status === "failed";
|
|
918
968
|
const ensureLoaded = (0, import_react4.useCallback)(() => {
|
|
919
969
|
if (!hasFetchedRef.current) {
|
|
920
970
|
hasFetchedRef.current = true;
|
|
921
|
-
|
|
922
|
-
});
|
|
971
|
+
setEngaged(true);
|
|
923
972
|
}
|
|
924
|
-
}, [
|
|
973
|
+
}, []);
|
|
974
|
+
const pageQueryRef = (0, import_react4.useRef)(pageQuery);
|
|
975
|
+
pageQueryRef.current = pageQuery;
|
|
976
|
+
(0, import_react4.useEffect)(() => {
|
|
977
|
+
if (!engaged) return;
|
|
978
|
+
if (paged) void catalog.ensurePickerPage(pageQueryRef.current).catch(() => void 0);
|
|
979
|
+
else void catalog.ensureLoaded().catch(() => void 0);
|
|
980
|
+
}, [engaged, paged, pageKey, catalog]);
|
|
981
|
+
const loadMore = (0, import_react4.useCallback)(() => {
|
|
982
|
+
if (!paged) return;
|
|
983
|
+
void catalog.loadMorePickerPage(pageQueryRef.current).catch(() => void 0);
|
|
984
|
+
}, [paged, catalog]);
|
|
985
|
+
const ensureFullCatalog = (0, import_react4.useCallback)(() => {
|
|
986
|
+
setFacetsWanted(true);
|
|
987
|
+
}, []);
|
|
988
|
+
const hasMore = paged && pageStatus === "succeeded" && pageState?.done === false;
|
|
989
|
+
const loadingMore = paged && pageState?.loadingMore === true;
|
|
990
|
+
const pinnedMissing = Boolean(activeAgentId) && pinnedAgent === void 0;
|
|
991
|
+
(0, import_react4.useEffect)(() => {
|
|
992
|
+
if (!engaged || !pinnedMissing || !activeAgentId) return;
|
|
993
|
+
void catalog.ensureAgentRows([activeAgentId]).catch(() => void 0);
|
|
994
|
+
}, [engaged, pinnedMissing, activeAgentId, catalog]);
|
|
925
995
|
const selectDefaultRow = (0, import_react4.useCallback)(
|
|
926
996
|
(state) => defaultMandateKey ? state.defaultRows[defaultMandateKey] : void 0,
|
|
927
997
|
[defaultMandateKey]
|
|
@@ -998,13 +1068,14 @@ function useAgentListCore({
|
|
|
998
1068
|
const handleAgentHover = (0, import_react4.useCallback)(
|
|
999
1069
|
(agent, panelOpen) => {
|
|
1000
1070
|
if (panelOpen) return;
|
|
1071
|
+
if (agent.isThin) void catalog.ensureAgentRows([agent.id]).catch(() => void 0);
|
|
1001
1072
|
if (hoverLeaveTimerRef.current) {
|
|
1002
1073
|
clearTimeout(hoverLeaveTimerRef.current);
|
|
1003
1074
|
hoverLeaveTimerRef.current = null;
|
|
1004
1075
|
}
|
|
1005
1076
|
setHoveredAgent(agent);
|
|
1006
1077
|
},
|
|
1007
|
-
[]
|
|
1078
|
+
[catalog]
|
|
1008
1079
|
);
|
|
1009
1080
|
const handleAgentHoverEnd = (0, import_react4.useCallback)(
|
|
1010
1081
|
(agent, onClear) => {
|
|
@@ -1035,8 +1106,10 @@ function useAgentListCore({
|
|
|
1035
1106
|
},
|
|
1036
1107
|
[]
|
|
1037
1108
|
);
|
|
1109
|
+
const tabTotal = consumer.state.tab === "mine" ? tabCountsForFilter.mine : consumer.state.tab === "shared" ? tabCountsForFilter.shared : consumer.state.tab === "system" ? tabCountsForFilter.system : tabCountsForFilter.all;
|
|
1110
|
+
const totalCount = paged && !consumer.state.searchTerm && excludedAgentIds.size === 0 ? Math.max(tabTotal, agents.length) : agents.length;
|
|
1038
1111
|
const footerLabel = agentListFooterLabel({
|
|
1039
|
-
count:
|
|
1112
|
+
count: totalCount,
|
|
1040
1113
|
archFilter: consumer.archFilter,
|
|
1041
1114
|
archivedHiddenCount
|
|
1042
1115
|
});
|
|
@@ -1060,6 +1133,14 @@ function useAgentListCore({
|
|
|
1060
1133
|
hoveredAgent,
|
|
1061
1134
|
setHoveredAgent,
|
|
1062
1135
|
ensureLoaded,
|
|
1136
|
+
/** FW-014: the list reads a page at a time; true while the slice has more. */
|
|
1137
|
+
paged,
|
|
1138
|
+
hasMore,
|
|
1139
|
+
loadingMore,
|
|
1140
|
+
loadMore,
|
|
1141
|
+
/** The tab's total (server count when paged) — the footer's number. */
|
|
1142
|
+
totalCount,
|
|
1143
|
+
ensureFullCatalog,
|
|
1063
1144
|
handleSelectAgent,
|
|
1064
1145
|
handleAgentHover,
|
|
1065
1146
|
handleAgentHoverEnd,
|
|
@@ -1079,6 +1160,7 @@ var EMPTY_EXCLUDES = [];
|
|
|
1079
1160
|
var selectStatus = (state) => state.status;
|
|
1080
1161
|
|
|
1081
1162
|
// catalog/native/AgentDetailCard.tsx
|
|
1163
|
+
var import_react6 = require("react");
|
|
1082
1164
|
var import_react_native4 = require("react-native");
|
|
1083
1165
|
|
|
1084
1166
|
// catalog/orchestra.ts
|
|
@@ -1406,8 +1488,14 @@ function formatDate(value) {
|
|
|
1406
1488
|
year: "numeric"
|
|
1407
1489
|
});
|
|
1408
1490
|
}
|
|
1409
|
-
function AgentDetailCard({ agent, onSelect }) {
|
|
1410
|
-
const
|
|
1491
|
+
function AgentDetailCard({ agent: given, onSelect }) {
|
|
1492
|
+
const catalog = useAgentCatalog();
|
|
1493
|
+
const { errorSink } = catalog;
|
|
1494
|
+
const held = (0, import_react6.useSyncExternalStore)(catalog.subscribe, () => catalog.getState().byId[given.id], () => catalog.getState().byId[given.id]);
|
|
1495
|
+
const agent = held && !held.isThin ? held : given;
|
|
1496
|
+
(0, import_react6.useEffect)(() => {
|
|
1497
|
+
if (given.isThin && !(held && !held.isThin)) void catalog.ensureAgentRows([given.id]).catch(() => void 0);
|
|
1498
|
+
}, [catalog, given.id, given.isThin, held]);
|
|
1411
1499
|
const { renderModelRef, openPeek } = useAgentCatalogUiPorts();
|
|
1412
1500
|
const theme = useAgentCatalogNativeTheme();
|
|
1413
1501
|
const isDefaultRow = isMandateAgentId(agent.id);
|
|
@@ -2455,7 +2543,9 @@ function AgentListContent({
|
|
|
2455
2543
|
pinnedAgent = null,
|
|
2456
2544
|
defaultRow = null,
|
|
2457
2545
|
autoFocusSearch = false,
|
|
2458
|
-
archivedHiddenCount = 0
|
|
2546
|
+
archivedHiddenCount = 0,
|
|
2547
|
+
onReachEnd,
|
|
2548
|
+
totalCount
|
|
2459
2549
|
}) {
|
|
2460
2550
|
const catalog = useAgentCatalog();
|
|
2461
2551
|
const theme = useAgentCatalogNativeTheme();
|
|
@@ -2640,6 +2730,7 @@ function AgentListContent({
|
|
|
2640
2730
|
data: items,
|
|
2641
2731
|
keyExtractor: (item) => item.key,
|
|
2642
2732
|
keyboardShouldPersistTaps: "handled",
|
|
2733
|
+
...onReachEnd ? { onEndReached: onReachEnd, onEndReachedThreshold: 0.5 } : {},
|
|
2643
2734
|
renderItem: ({ item }) => {
|
|
2644
2735
|
if (item.kind === "divider") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: hairline });
|
|
2645
2736
|
if (item.kind === "label") {
|
|
@@ -2693,7 +2784,7 @@ function AgentListContent({
|
|
|
2693
2784
|
fontVariant: ["tabular-nums"]
|
|
2694
2785
|
},
|
|
2695
2786
|
children: agentListFooterLabel({
|
|
2696
|
-
count: agents.length,
|
|
2787
|
+
count: totalCount ?? agents.length,
|
|
2697
2788
|
archFilter: consumer.archFilter,
|
|
2698
2789
|
archivedHiddenCount
|
|
2699
2790
|
})
|
|
@@ -2858,9 +2949,9 @@ function AgentPickerBody({
|
|
|
2858
2949
|
compact = false,
|
|
2859
2950
|
onAfterSelect
|
|
2860
2951
|
}) {
|
|
2861
|
-
const [detailAgent, setDetailAgent] = (0,
|
|
2862
|
-
const [subView, setSubView] = (0,
|
|
2863
|
-
const [panelSearch, setPanelSearch] = (0,
|
|
2952
|
+
const [detailAgent, setDetailAgent] = (0, import_react7.useState)(null);
|
|
2953
|
+
const [subView, setSubView] = (0, import_react7.useState)(null);
|
|
2954
|
+
const [panelSearch, setPanelSearch] = (0, import_react7.useState)("");
|
|
2864
2955
|
const {
|
|
2865
2956
|
agents,
|
|
2866
2957
|
archivedHiddenCount,
|
|
@@ -2873,6 +2964,9 @@ function AgentPickerBody({
|
|
|
2873
2964
|
pinnedAgent,
|
|
2874
2965
|
defaultRow,
|
|
2875
2966
|
ensureLoaded,
|
|
2967
|
+
loadMore,
|
|
2968
|
+
totalCount,
|
|
2969
|
+
ensureFullCatalog,
|
|
2876
2970
|
handleSelectAgent: coreSelectAgent
|
|
2877
2971
|
} = useAgentListCore({
|
|
2878
2972
|
consumerId,
|
|
@@ -2885,7 +2979,7 @@ function AgentPickerBody({
|
|
|
2885
2979
|
...excludeAgentIds ? { excludeAgentIds } : {},
|
|
2886
2980
|
...defaultMandateKey ? { defaultMandateKey } : {}
|
|
2887
2981
|
});
|
|
2888
|
-
(0,
|
|
2982
|
+
(0, import_react7.useEffect)(() => {
|
|
2889
2983
|
ensureLoaded();
|
|
2890
2984
|
}, [ensureLoaded]);
|
|
2891
2985
|
const selectAgent = (agent) => {
|
|
@@ -2931,11 +3025,16 @@ function AgentPickerBody({
|
|
|
2931
3025
|
allTags,
|
|
2932
3026
|
onSelectAgent: selectAgent,
|
|
2933
3027
|
onDetailPress: setDetailAgent,
|
|
2934
|
-
onFilterChipPress:
|
|
3028
|
+
onFilterChipPress: (panel) => {
|
|
3029
|
+
if (panel !== "sort") ensureFullCatalog();
|
|
3030
|
+
setSubView(panel);
|
|
3031
|
+
},
|
|
2935
3032
|
onReset: consumer.resetFilters,
|
|
2936
3033
|
activeFilterCount,
|
|
2937
3034
|
tabCounts,
|
|
2938
3035
|
archivedHiddenCount,
|
|
3036
|
+
onReachEnd: loadMore,
|
|
3037
|
+
totalCount,
|
|
2939
3038
|
...visibleTabs ? { visibleTabs } : {},
|
|
2940
3039
|
...systemTabLabel ?? (includeSystemInAll ? "System" : void 0) ? {
|
|
2941
3040
|
systemTabLabel: systemTabLabel ?? (includeSystemInAll ? "System" : void 0)
|
|
@@ -1,45 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
|
-
import { A as AgentSummary, a as AgentConsumerState, b as AgentConsumerPatch, c as AgentTab, d as AgentSortOption, e as AgentFavFilter, f as AgentArchFilter, g as AgentAccessFilter, O as OrchestraBadge } from '../../types-
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* catalog/default-row-types.ts — @ai-matrx/agents/catalog
|
|
7
|
-
*
|
|
8
|
-
* Split out of `default-row.ts` so `global-state.ts` can name the cached
|
|
9
|
-
* shape without importing the resolver (and its transport work) — the same
|
|
10
|
-
* split-out reflex C8 asks for, at module scale.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/** A resolved default row, cached for first paint and compared for drift. */
|
|
14
|
-
interface ResolvedDefaultRow {
|
|
15
|
-
mandateKey: string;
|
|
16
|
-
/** The `agent.definition` id the mandate resolved to. */
|
|
17
|
-
holderId: string;
|
|
18
|
-
/** The holder's REAL name, read from the catalog — never hardcoded. */
|
|
19
|
-
holderName: string;
|
|
20
|
-
holderDescription: string | null;
|
|
21
|
-
provenance: string;
|
|
22
|
-
/** Epoch ms of this resolution. */
|
|
23
|
-
at: number;
|
|
24
|
-
}
|
|
25
|
-
/** What the picker renders and what it screams, together. */
|
|
26
|
-
interface DefaultRowState {
|
|
27
|
-
mandateKey: string;
|
|
28
|
-
/** The row to render at the top of the list. `null` until resolved. */
|
|
29
|
-
row: AgentSummary | null;
|
|
30
|
-
/** The last live resolution, or the cached one before the live answer lands. */
|
|
31
|
-
resolved: ResolvedDefaultRow | null;
|
|
32
|
-
/** True while the resolution is in flight. */
|
|
33
|
-
loading: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* 🚨 THE DRIFT SCREAM. Set when the cached first-paint row and the LIVE
|
|
36
|
-
* resolution disagree on holder id or holder name. Rendered as a persistent
|
|
37
|
-
* in-picker banner AND sent to the `notifier` port — never console-only.
|
|
38
|
-
*/
|
|
39
|
-
drift: string | null;
|
|
40
|
-
/** Set when the mandate could not be resolved at all. Loud, with a remedy. */
|
|
41
|
-
error: string | null;
|
|
42
|
-
}
|
|
3
|
+
import { A as AgentSummary, a as AgentConsumerState, b as AgentConsumerPatch, c as AgentTab, d as AgentSortOption, e as AgentFavFilter, f as AgentArchFilter, g as AgentAccessFilter, O as OrchestraBadge } from '../../types-5pX8AZBM.cjs';
|
|
43
4
|
|
|
44
5
|
/**
|
|
45
6
|
* `@ai-matrx/agents/catalog` — THE PORTS.
|
|
@@ -116,6 +77,101 @@ type AgentCatalogNavigate = (href: string) => void;
|
|
|
116
77
|
*/
|
|
117
78
|
type AgentCatalogOpenPeek = (agent: AgentSummary) => void;
|
|
118
79
|
|
|
80
|
+
/**
|
|
81
|
+
* catalog/data.ts — @ai-matrx/agents/catalog
|
|
82
|
+
*
|
|
83
|
+
* Every database call the catalog makes, and nothing else. Five of them:
|
|
84
|
+
*
|
|
85
|
+
* 1. `agx_get_list_full()` — the complete catalog (owned + directly-shared
|
|
86
|
+
* + org-shared user agents, unioned with active builtins).
|
|
87
|
+
* 2. `agx_search(p_query, p_deep, p_limit, p_offset)` — tier-2 server search.
|
|
88
|
+
* 3. `agx_resolve_agent_address(p_ids)` — the single-agent name read, used
|
|
89
|
+
* when a mandate's Holder is not in the caller's own catalog.
|
|
90
|
+
* 4. The caller's stars arrive ON the rows: every read above computes
|
|
91
|
+
* `is_favorite` server-side from `platform.user_entity_state`
|
|
92
|
+
* (`platform.my_favorite`). There is no second star read (FW-014; the
|
|
93
|
+
* `ues_get_bulk` overlay over every id was retired 2026-10-23).
|
|
94
|
+
* 5. ONE write: the caller's star, `ues_set` through the same port. The
|
|
95
|
+
* retired `agent.definition.is_favorite` column is never read or written.
|
|
96
|
+
* 6. THE PINNED READ (2026-10-09; by-ids 2026-10-23): the caller's starred
|
|
97
|
+
* ids (`ues_list` through the favorites port), then
|
|
98
|
+
* `agent.agx_get_by_ids(p_ids)` for exactly those ids. A sidebar's Pinned
|
|
99
|
+
* section shows a handful of rows; it never pays for the whole catalog,
|
|
100
|
+
* in the browser or on the server, to find them.
|
|
101
|
+
* 7. THE PICKER PAGE (FW-014, 2026-10-23): `agent.agx_picker_page` — the
|
|
102
|
+
* menu opens with ~50 thin rows (favorites, recently used, name) and the
|
|
103
|
+
* tab counts; scrolling reads the next keyset page. `agent.agx_get_by_ids`
|
|
104
|
+
* fills in a full row on hover/open. The whole-catalog read above remains
|
|
105
|
+
* for surfaces that genuinely list everything, and for a picker whose
|
|
106
|
+
* person narrows by category or tag (the facets need every row).
|
|
107
|
+
*
|
|
108
|
+
* 🚨 THE LIST READ IS COMPLETE OR IT THROWS. PostgREST caps every response at
|
|
109
|
+
* `db-max-rows` (1000 on Matrx Main) and reports success — matrx-frontend's
|
|
110
|
+
* `fetchAgentsListFull` issued a bare `.rpc()` and would silently have
|
|
111
|
+
* returned 1000 rows of a larger catalog (the ~400-builtin truncation
|
|
112
|
+
* incident is the near-miss). Here the read goes through `readAllRows` with
|
|
113
|
+
* `{ count: "exact" }` and a stable `.order("id")`, so a truncation is a
|
|
114
|
+
* loud `IncompleteReadError` instead of a confidently short picker.
|
|
115
|
+
* The DB's own favourites-first/`updated_at` order is irrelevant: every row
|
|
116
|
+
* is re-sorted client-side by `sortFilteredAgents`.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/** Which slice of the caller's catalog a picker page reads. */
|
|
120
|
+
interface AgentPickerPageQuery {
|
|
121
|
+
/** `all_system` = the admin "All" tab that blends system agents in. */
|
|
122
|
+
tab: "mine" | "shared" | "all" | "all_system" | "system";
|
|
123
|
+
archive: "active" | "archived" | "both";
|
|
124
|
+
includeQuick: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** The tab badges, counted server-side over the same reach as the rows. */
|
|
127
|
+
interface AgentPickerCounts {
|
|
128
|
+
mine: number;
|
|
129
|
+
shared: number;
|
|
130
|
+
all: number;
|
|
131
|
+
system: number;
|
|
132
|
+
/** Archived rows the active filter hides behind THIS tab (0 unless archive = active). */
|
|
133
|
+
archivedHidden: number;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* catalog/default-row-types.ts — @ai-matrx/agents/catalog
|
|
138
|
+
*
|
|
139
|
+
* Split out of `default-row.ts` so `global-state.ts` can name the cached
|
|
140
|
+
* shape without importing the resolver (and its transport work) — the same
|
|
141
|
+
* split-out reflex C8 asks for, at module scale.
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/** A resolved default row, cached for first paint and compared for drift. */
|
|
145
|
+
interface ResolvedDefaultRow {
|
|
146
|
+
mandateKey: string;
|
|
147
|
+
/** The `agent.definition` id the mandate resolved to. */
|
|
148
|
+
holderId: string;
|
|
149
|
+
/** The holder's REAL name, read from the catalog — never hardcoded. */
|
|
150
|
+
holderName: string;
|
|
151
|
+
holderDescription: string | null;
|
|
152
|
+
provenance: string;
|
|
153
|
+
/** Epoch ms of this resolution. */
|
|
154
|
+
at: number;
|
|
155
|
+
}
|
|
156
|
+
/** What the picker renders and what it screams, together. */
|
|
157
|
+
interface DefaultRowState {
|
|
158
|
+
mandateKey: string;
|
|
159
|
+
/** The row to render at the top of the list. `null` until resolved. */
|
|
160
|
+
row: AgentSummary | null;
|
|
161
|
+
/** The last live resolution, or the cached one before the live answer lands. */
|
|
162
|
+
resolved: ResolvedDefaultRow | null;
|
|
163
|
+
/** True while the resolution is in flight. */
|
|
164
|
+
loading: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* 🚨 THE DRIFT SCREAM. Set when the cached first-paint row and the LIVE
|
|
167
|
+
* resolution disagree on holder id or holder name. Rendered as a persistent
|
|
168
|
+
* in-picker banner AND sent to the `notifier` port — never console-only.
|
|
169
|
+
*/
|
|
170
|
+
drift: string | null;
|
|
171
|
+
/** Set when the mandate could not be resolved at all. Loud, with a remedy. */
|
|
172
|
+
error: string | null;
|
|
173
|
+
}
|
|
174
|
+
|
|
119
175
|
/**
|
|
120
176
|
* catalog/schema.ts — @ai-matrx/agents/catalog
|
|
121
177
|
*
|
|
@@ -184,6 +240,20 @@ interface AssertAgentCatalogSchemaOptions {
|
|
|
184
240
|
*/
|
|
185
241
|
|
|
186
242
|
type AgentCatalogStatus = "idle" | "loading" | "succeeded" | "failed";
|
|
243
|
+
/** One picker slice (tab × archive × quick) read a page at a time (FW-014). */
|
|
244
|
+
interface AgentPickerPageState {
|
|
245
|
+
/** Row ids in server order across every page read so far. */
|
|
246
|
+
ids: string[];
|
|
247
|
+
/** Keyset position of the next page; `null` once the last page is in. */
|
|
248
|
+
nextCursor: unknown;
|
|
249
|
+
done: boolean;
|
|
250
|
+
status: AgentCatalogStatus;
|
|
251
|
+
/** True while a next page (not the first) is in flight. */
|
|
252
|
+
loadingMore: boolean;
|
|
253
|
+
error: string | null;
|
|
254
|
+
counts: AgentPickerCounts | null;
|
|
255
|
+
fetchedAt: number;
|
|
256
|
+
}
|
|
187
257
|
interface AgentCatalogState {
|
|
188
258
|
/** Every row, one stable array reference per change (memoization depends on it). */
|
|
189
259
|
rows: AgentSummary[];
|
|
@@ -199,6 +269,8 @@ interface AgentCatalogState {
|
|
|
199
269
|
* or by a complete catalog load, whichever came first.
|
|
200
270
|
*/
|
|
201
271
|
favoriteRowsStatus: AgentCatalogStatus;
|
|
272
|
+
/** The picker's paged slices, keyed by `agentPickerPageKey` (FW-014). */
|
|
273
|
+
pickerPages: Record<string, AgentPickerPageState>;
|
|
202
274
|
}
|
|
203
275
|
interface AgentCatalog {
|
|
204
276
|
readonly catalogId: string;
|
|
@@ -207,6 +279,8 @@ interface AgentCatalog {
|
|
|
207
279
|
readonly notifier: AgentCatalogNotifier | undefined;
|
|
208
280
|
/** True when this catalog was given a transport and can resolve mandates. */
|
|
209
281
|
readonly canResolveMandates: boolean;
|
|
282
|
+
/** `AgentCatalogConfig.pickerReads`, resolved (default `"page"`). */
|
|
283
|
+
readonly pickerReads: "page" | "catalog";
|
|
210
284
|
/**
|
|
211
285
|
* The consumer state a brand-new consumer starts from, AFTER the host's
|
|
212
286
|
* `defaults` knob is applied. Read it instead of
|
|
@@ -245,6 +319,28 @@ interface AgentCatalog {
|
|
|
245
319
|
* makes no request. Rows that do not parse are skipped.
|
|
246
320
|
*/
|
|
247
321
|
seedFavoriteRows(rawRows: unknown[]): void;
|
|
322
|
+
/**
|
|
323
|
+
* THE PICKER'S OPEN (FW-014): the first page (~50 thin rows) of one slice,
|
|
324
|
+
* plus its tab counts — never the whole catalog. Fresh for the list's TTL;
|
|
325
|
+
* deduped in flight; safe on every open.
|
|
326
|
+
*/
|
|
327
|
+
ensurePickerPage(query: AgentPickerPageQuery): Promise<void>;
|
|
328
|
+
/** The next page of a slice (scroll). No-op when the slice is done or already loading. */
|
|
329
|
+
loadMorePickerPage(query: AgentPickerPageQuery): Promise<void>;
|
|
330
|
+
/**
|
|
331
|
+
* FULL rows for these ids (`agent.agx_get_by_ids`), merged into the registry:
|
|
332
|
+
* a hover card's details, the pinned current agent, a name for an id that is
|
|
333
|
+
* not on page 1. Ids already held as full rows are not asked again; deduped
|
|
334
|
+
* in flight.
|
|
335
|
+
*/
|
|
336
|
+
ensureAgentRows(agentIds: readonly string[]): Promise<void>;
|
|
337
|
+
/**
|
|
338
|
+
* The caller's live agents carrying any of these tags, merged into the
|
|
339
|
+
* registry (`agent.agx_picker_tagged`) — the composer's quick agents and
|
|
340
|
+
* presets, never the catalog. Fresh for the list's TTL; deduped in flight;
|
|
341
|
+
* answered at once when the whole catalog is already fresh.
|
|
342
|
+
*/
|
|
343
|
+
ensureTaggedRows(tags: readonly string[]): Promise<void>;
|
|
248
344
|
/** True when the last load is inside the 15-minute TTL. */
|
|
249
345
|
isFresh(): boolean;
|
|
250
346
|
/** True when the last load is older than 4 hours (tab-restore threshold). */
|
|
@@ -587,6 +683,14 @@ declare function useAgentListCore({ consumerId, onSelect, navigateTo, activeAgen
|
|
|
587
683
|
hoveredAgent: AgentSummary | null;
|
|
588
684
|
setHoveredAgent: react.Dispatch<react.SetStateAction<AgentSummary | null>>;
|
|
589
685
|
ensureLoaded: () => void;
|
|
686
|
+
/** FW-014: the list reads a page at a time; true while the slice has more. */
|
|
687
|
+
paged: boolean;
|
|
688
|
+
hasMore: boolean;
|
|
689
|
+
loadingMore: boolean;
|
|
690
|
+
loadMore: () => void;
|
|
691
|
+
/** The tab's total (server count when paged) — the footer's number. */
|
|
692
|
+
totalCount: number;
|
|
693
|
+
ensureFullCatalog: () => void;
|
|
590
694
|
handleSelectAgent: (agent: AgentSummary) => void;
|
|
591
695
|
handleAgentHover: (agent: AgentSummary, panelOpen: boolean) => void;
|
|
592
696
|
handleAgentHoverEnd: (agent: AgentSummary, onClear: () => void) => void;
|
|
@@ -732,8 +836,12 @@ interface AgentListContentProps {
|
|
|
732
836
|
* `useAgentListCore`. The footer names them, exactly as on the web.
|
|
733
837
|
*/
|
|
734
838
|
archivedHiddenCount?: number | undefined;
|
|
839
|
+
/** FW-014 paging: asked for the next page when the list nears its end. */
|
|
840
|
+
onReachEnd?: (() => void) | undefined;
|
|
841
|
+
/** The tab's total for the footer (server count when paged). */
|
|
842
|
+
totalCount?: number | undefined;
|
|
735
843
|
}
|
|
736
|
-
declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, onSelectAgent, onDetailPress, onFilterChipPress, onReset, activeFilterCount, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, autoFocusSearch, archivedHiddenCount, }: AgentListContentProps): react.JSX.Element;
|
|
844
|
+
declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, onSelectAgent, onDetailPress, onFilterChipPress, onReset, activeFilterCount, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, autoFocusSearch, archivedHiddenCount, onReachEnd, totalCount, }: AgentListContentProps): react.JSX.Element;
|
|
737
845
|
|
|
738
846
|
interface AgentListTabsProps {
|
|
739
847
|
consumer: UseAgentConsumerReturn;
|
|
@@ -766,7 +874,7 @@ interface AgentDetailCardProps {
|
|
|
766
874
|
agent: AgentSummary;
|
|
767
875
|
onSelect: () => void;
|
|
768
876
|
}
|
|
769
|
-
declare function AgentDetailCard({ agent, onSelect }: AgentDetailCardProps): react.JSX.Element;
|
|
877
|
+
declare function AgentDetailCard({ agent: given, onSelect }: AgentDetailCardProps): react.JSX.Element;
|
|
770
878
|
|
|
771
879
|
type AgentSubViewName = "sort" | "categories" | "tags";
|
|
772
880
|
interface AgentSubViewProps {
|