@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
|
@@ -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.js';
|
|
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 {
|
|
@@ -215,7 +215,7 @@ function AgentCatalogProvider({
|
|
|
215
215
|
import { StyleSheet as StyleSheet9, Text as Text9, View as View7 } from "react-native";
|
|
216
216
|
|
|
217
217
|
// catalog/native/AgentPickerBody.tsx
|
|
218
|
-
import { useEffect as
|
|
218
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
219
219
|
import { StyleSheet as StyleSheet8, View as View6 } from "react-native";
|
|
220
220
|
|
|
221
221
|
// catalog/shared/useAgentListCore-react.ts
|
|
@@ -793,6 +793,14 @@ function agentListFooterLabel(args) {
|
|
|
793
793
|
return archivedHiddenCount > 0 ? `${base} \xB7 ${archivedHiddenCount} archived hidden` : base;
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
// catalog/store.ts
|
|
797
|
+
import { createAssociationsStore } from "@ai-matrx/associations/core";
|
|
798
|
+
var LIST_TTL_MS = 15 * 60 * 1e3;
|
|
799
|
+
var LIST_STALE_MS = 4 * 60 * 60 * 1e3;
|
|
800
|
+
function agentPickerPageKey(query) {
|
|
801
|
+
return `${query.tab}|${query.archive}|${query.includeQuick ? "q" : "-"}`;
|
|
802
|
+
}
|
|
803
|
+
|
|
796
804
|
// catalog/shared/useAgentListCore-react.ts
|
|
797
805
|
function useAgentListCore({
|
|
798
806
|
consumerId,
|
|
@@ -822,19 +830,60 @@ function useAgentListCore({
|
|
|
822
830
|
const allRows = useAgentCatalogRows();
|
|
823
831
|
const rows = useMemo3(() => includeQuickAgents ? allRows : withoutQuickAgents(allRows), [allRows, includeQuickAgents]);
|
|
824
832
|
const userId = catalog.getUserIdOrNull();
|
|
825
|
-
const
|
|
833
|
+
const status = useAgentCatalogState(selectStatus);
|
|
834
|
+
const [setAsideLabel, setSetAsideLabel] = useState2(null);
|
|
835
|
+
const activeAgentFilter = agentFilter && setAsideLabel !== agentFilter.label ? agentFilter : null;
|
|
836
|
+
const [facetsWanted, setFacetsWanted] = useState2(false);
|
|
837
|
+
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";
|
|
838
|
+
const fullCatalogReady = status === "succeeded" && catalog.isFresh();
|
|
839
|
+
const pageQuery = {
|
|
840
|
+
tab: includeSystemInAll && consumer.state.tab === "all" ? "all_system" : consumer.state.tab,
|
|
841
|
+
archive: consumer.state.archFilter,
|
|
842
|
+
includeQuick: includeQuickAgents
|
|
843
|
+
};
|
|
844
|
+
const pageKey = agentPickerPageKey(pageQuery);
|
|
845
|
+
const selectPage = useCallback3((state) => state.pickerPages[pageKey], [pageKey]);
|
|
846
|
+
const pageState = useAgentCatalogState(selectPage);
|
|
847
|
+
const pageUnsupported = pageState?.error === "unsupported";
|
|
848
|
+
const paged = catalog.pickerReads === "page" && !needsFullCatalog && !fullCatalogReady && !pageUnsupported;
|
|
849
|
+
const selectById = useCallback3((state) => state.byId, []);
|
|
850
|
+
const byId = useAgentCatalogState(selectById);
|
|
851
|
+
const pageRows = useMemo3(() => {
|
|
852
|
+
if (!pageState) return [];
|
|
853
|
+
const out = [];
|
|
854
|
+
for (const id of pageState.ids) {
|
|
855
|
+
const row = byId[id];
|
|
856
|
+
if (row) out.push(row);
|
|
857
|
+
}
|
|
858
|
+
return out;
|
|
859
|
+
}, [pageState, byId]);
|
|
860
|
+
const tabCountsForFilter = paged ? {
|
|
861
|
+
mine: pageState?.counts?.mine ?? 0,
|
|
862
|
+
shared: pageState?.counts?.shared ?? 0,
|
|
863
|
+
all: (pageState?.counts?.all ?? 0) + (includeSystemInAll ? pageState?.counts?.system ?? 0 : 0),
|
|
864
|
+
system: pageState?.counts?.system ?? 0
|
|
865
|
+
} : selectAgentTabCounts(rows, consumer.state.archFilter);
|
|
826
866
|
const ownedCount = tabCountsForFilter.mine;
|
|
827
867
|
const selectFiltered = useMemo3(
|
|
828
868
|
() => makeSelectFilteredAgents(includeSystemInAll),
|
|
829
869
|
[includeSystemInAll]
|
|
830
870
|
);
|
|
831
|
-
const
|
|
871
|
+
const searchPool = useMemo3(() => {
|
|
872
|
+
if (!paged || !consumer.state.searchTerm) return null;
|
|
873
|
+
const pool = /* @__PURE__ */ new Map();
|
|
874
|
+
for (const row of pageRows) pool.set(row.id, row);
|
|
875
|
+
for (const id of consumer.state.serverMatchedIds) {
|
|
876
|
+
const row = byId[id];
|
|
877
|
+
if (row) pool.set(id, row);
|
|
878
|
+
}
|
|
879
|
+
const list = [...pool.values()];
|
|
880
|
+
return includeQuickAgents ? list : withoutQuickAgents(list);
|
|
881
|
+
}, [paged, consumer.state.searchTerm, consumer.state.serverMatchedIds, pageRows, byId, includeQuickAgents]);
|
|
882
|
+
const filteredAgents = paged ? searchPool ? selectFiltered(searchPool, consumer.state) : pageRows : selectFiltered(rows, consumer.state);
|
|
832
883
|
const excludedAgentIds = useMemo3(
|
|
833
884
|
() => new Set(excludeAgentIds),
|
|
834
885
|
[excludeAgentIds]
|
|
835
886
|
);
|
|
836
|
-
const [setAsideLabel, setSetAsideLabel] = useState2(null);
|
|
837
|
-
const activeAgentFilter = agentFilter && setAsideLabel !== agentFilter.label ? agentFilter : null;
|
|
838
887
|
const filterTest = activeAgentFilter?.test;
|
|
839
888
|
const applyExcludes = useCallback3(
|
|
840
889
|
(list) => excludedAgentIds.size === 0 && !filterTest ? list : list.filter(
|
|
@@ -857,23 +906,44 @@ function useAgentListCore({
|
|
|
857
906
|
() => ({ ...consumer.state, archFilter: "archived" }),
|
|
858
907
|
[consumer.state]
|
|
859
908
|
);
|
|
860
|
-
const archivedHiddenCount = consumer.archFilter
|
|
861
|
-
const status = useAgentCatalogState(selectStatus);
|
|
909
|
+
const archivedHiddenCount = consumer.archFilter !== "active" || paged && consumer.state.searchTerm ? 0 : paged ? pageState?.counts?.archivedHidden ?? 0 : applyExcludes(selectArchivedProbe(rows, archiveProbeState)).length;
|
|
862
910
|
const activeAgentId = activeAgentIdOverride ?? null;
|
|
863
|
-
const pinnedAgent = activeAgentId ?
|
|
911
|
+
const pinnedAgent = activeAgentId ? byId[activeAgentId] : void 0;
|
|
864
912
|
const onSystemTab = consumer.tab === "system";
|
|
865
913
|
const allCategories = onSystemTab ? selectAllSystemAgentCategories(rows) : selectAllAgentCategories(rows);
|
|
866
914
|
const allTags = onSystemTab ? selectAllSystemAgentTags(rows) : selectAllAgentTags(rows);
|
|
867
915
|
const tabCounts = tabCountsForFilter;
|
|
868
|
-
const
|
|
869
|
-
const
|
|
916
|
+
const [engaged, setEngaged] = useState2(false);
|
|
917
|
+
const pageStatus = pageState?.status ?? "idle";
|
|
918
|
+
const isLoading = paged ? (pageStatus === "loading" || pageStatus === "idle") && pageRows.length === 0 && engaged : status === "loading";
|
|
919
|
+
const agentsLoaded = paged ? pageStatus === "succeeded" || pageStatus === "failed" : status === "succeeded" || status === "failed";
|
|
870
920
|
const ensureLoaded = useCallback3(() => {
|
|
871
921
|
if (!hasFetchedRef.current) {
|
|
872
922
|
hasFetchedRef.current = true;
|
|
873
|
-
|
|
874
|
-
});
|
|
923
|
+
setEngaged(true);
|
|
875
924
|
}
|
|
876
|
-
}, [
|
|
925
|
+
}, []);
|
|
926
|
+
const pageQueryRef = useRef2(pageQuery);
|
|
927
|
+
pageQueryRef.current = pageQuery;
|
|
928
|
+
useEffect2(() => {
|
|
929
|
+
if (!engaged) return;
|
|
930
|
+
if (paged) void catalog.ensurePickerPage(pageQueryRef.current).catch(() => void 0);
|
|
931
|
+
else void catalog.ensureLoaded().catch(() => void 0);
|
|
932
|
+
}, [engaged, paged, pageKey, catalog]);
|
|
933
|
+
const loadMore = useCallback3(() => {
|
|
934
|
+
if (!paged) return;
|
|
935
|
+
void catalog.loadMorePickerPage(pageQueryRef.current).catch(() => void 0);
|
|
936
|
+
}, [paged, catalog]);
|
|
937
|
+
const ensureFullCatalog = useCallback3(() => {
|
|
938
|
+
setFacetsWanted(true);
|
|
939
|
+
}, []);
|
|
940
|
+
const hasMore = paged && pageStatus === "succeeded" && pageState?.done === false;
|
|
941
|
+
const loadingMore = paged && pageState?.loadingMore === true;
|
|
942
|
+
const pinnedMissing = Boolean(activeAgentId) && pinnedAgent === void 0;
|
|
943
|
+
useEffect2(() => {
|
|
944
|
+
if (!engaged || !pinnedMissing || !activeAgentId) return;
|
|
945
|
+
void catalog.ensureAgentRows([activeAgentId]).catch(() => void 0);
|
|
946
|
+
}, [engaged, pinnedMissing, activeAgentId, catalog]);
|
|
877
947
|
const selectDefaultRow = useCallback3(
|
|
878
948
|
(state) => defaultMandateKey ? state.defaultRows[defaultMandateKey] : void 0,
|
|
879
949
|
[defaultMandateKey]
|
|
@@ -950,13 +1020,14 @@ function useAgentListCore({
|
|
|
950
1020
|
const handleAgentHover = useCallback3(
|
|
951
1021
|
(agent, panelOpen) => {
|
|
952
1022
|
if (panelOpen) return;
|
|
1023
|
+
if (agent.isThin) void catalog.ensureAgentRows([agent.id]).catch(() => void 0);
|
|
953
1024
|
if (hoverLeaveTimerRef.current) {
|
|
954
1025
|
clearTimeout(hoverLeaveTimerRef.current);
|
|
955
1026
|
hoverLeaveTimerRef.current = null;
|
|
956
1027
|
}
|
|
957
1028
|
setHoveredAgent(agent);
|
|
958
1029
|
},
|
|
959
|
-
[]
|
|
1030
|
+
[catalog]
|
|
960
1031
|
);
|
|
961
1032
|
const handleAgentHoverEnd = useCallback3(
|
|
962
1033
|
(agent, onClear) => {
|
|
@@ -987,8 +1058,10 @@ function useAgentListCore({
|
|
|
987
1058
|
},
|
|
988
1059
|
[]
|
|
989
1060
|
);
|
|
1061
|
+
const tabTotal = consumer.state.tab === "mine" ? tabCountsForFilter.mine : consumer.state.tab === "shared" ? tabCountsForFilter.shared : consumer.state.tab === "system" ? tabCountsForFilter.system : tabCountsForFilter.all;
|
|
1062
|
+
const totalCount = paged && !consumer.state.searchTerm && excludedAgentIds.size === 0 ? Math.max(tabTotal, agents.length) : agents.length;
|
|
990
1063
|
const footerLabel = agentListFooterLabel({
|
|
991
|
-
count:
|
|
1064
|
+
count: totalCount,
|
|
992
1065
|
archFilter: consumer.archFilter,
|
|
993
1066
|
archivedHiddenCount
|
|
994
1067
|
});
|
|
@@ -1012,6 +1085,14 @@ function useAgentListCore({
|
|
|
1012
1085
|
hoveredAgent,
|
|
1013
1086
|
setHoveredAgent,
|
|
1014
1087
|
ensureLoaded,
|
|
1088
|
+
/** FW-014: the list reads a page at a time; true while the slice has more. */
|
|
1089
|
+
paged,
|
|
1090
|
+
hasMore,
|
|
1091
|
+
loadingMore,
|
|
1092
|
+
loadMore,
|
|
1093
|
+
/** The tab's total (server count when paged) — the footer's number. */
|
|
1094
|
+
totalCount,
|
|
1095
|
+
ensureFullCatalog,
|
|
1015
1096
|
handleSelectAgent,
|
|
1016
1097
|
handleAgentHover,
|
|
1017
1098
|
handleAgentHoverEnd,
|
|
@@ -1031,6 +1112,7 @@ var EMPTY_EXCLUDES = [];
|
|
|
1031
1112
|
var selectStatus = (state) => state.status;
|
|
1032
1113
|
|
|
1033
1114
|
// catalog/native/AgentDetailCard.tsx
|
|
1115
|
+
import { useEffect as useEffect3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1034
1116
|
import { Pressable as Pressable3, ScrollView, StyleSheet, Text as Text3, View } from "react-native";
|
|
1035
1117
|
|
|
1036
1118
|
// catalog/orchestra.ts
|
|
@@ -1358,8 +1440,14 @@ function formatDate(value) {
|
|
|
1358
1440
|
year: "numeric"
|
|
1359
1441
|
});
|
|
1360
1442
|
}
|
|
1361
|
-
function AgentDetailCard({ agent, onSelect }) {
|
|
1362
|
-
const
|
|
1443
|
+
function AgentDetailCard({ agent: given, onSelect }) {
|
|
1444
|
+
const catalog = useAgentCatalog();
|
|
1445
|
+
const { errorSink } = catalog;
|
|
1446
|
+
const held = useSyncExternalStore2(catalog.subscribe, () => catalog.getState().byId[given.id], () => catalog.getState().byId[given.id]);
|
|
1447
|
+
const agent = held && !held.isThin ? held : given;
|
|
1448
|
+
useEffect3(() => {
|
|
1449
|
+
if (given.isThin && !(held && !held.isThin)) void catalog.ensureAgentRows([given.id]).catch(() => void 0);
|
|
1450
|
+
}, [catalog, given.id, given.isThin, held]);
|
|
1363
1451
|
const { renderModelRef, openPeek } = useAgentCatalogUiPorts();
|
|
1364
1452
|
const theme = useAgentCatalogNativeTheme();
|
|
1365
1453
|
const isDefaultRow = isMandateAgentId(agent.id);
|
|
@@ -2407,7 +2495,9 @@ function AgentListContent({
|
|
|
2407
2495
|
pinnedAgent = null,
|
|
2408
2496
|
defaultRow = null,
|
|
2409
2497
|
autoFocusSearch = false,
|
|
2410
|
-
archivedHiddenCount = 0
|
|
2498
|
+
archivedHiddenCount = 0,
|
|
2499
|
+
onReachEnd,
|
|
2500
|
+
totalCount
|
|
2411
2501
|
}) {
|
|
2412
2502
|
const catalog = useAgentCatalog();
|
|
2413
2503
|
const theme = useAgentCatalogNativeTheme();
|
|
@@ -2592,6 +2682,7 @@ function AgentListContent({
|
|
|
2592
2682
|
data: items,
|
|
2593
2683
|
keyExtractor: (item) => item.key,
|
|
2594
2684
|
keyboardShouldPersistTaps: "handled",
|
|
2685
|
+
...onReachEnd ? { onEndReached: onReachEnd, onEndReachedThreshold: 0.5 } : {},
|
|
2595
2686
|
renderItem: ({ item }) => {
|
|
2596
2687
|
if (item.kind === "divider") return /* @__PURE__ */ jsx10(View4, { style: hairline });
|
|
2597
2688
|
if (item.kind === "label") {
|
|
@@ -2645,7 +2736,7 @@ function AgentListContent({
|
|
|
2645
2736
|
fontVariant: ["tabular-nums"]
|
|
2646
2737
|
},
|
|
2647
2738
|
children: agentListFooterLabel({
|
|
2648
|
-
count: agents.length,
|
|
2739
|
+
count: totalCount ?? agents.length,
|
|
2649
2740
|
archFilter: consumer.archFilter,
|
|
2650
2741
|
archivedHiddenCount
|
|
2651
2742
|
})
|
|
@@ -2825,6 +2916,9 @@ function AgentPickerBody({
|
|
|
2825
2916
|
pinnedAgent,
|
|
2826
2917
|
defaultRow,
|
|
2827
2918
|
ensureLoaded,
|
|
2919
|
+
loadMore,
|
|
2920
|
+
totalCount,
|
|
2921
|
+
ensureFullCatalog,
|
|
2828
2922
|
handleSelectAgent: coreSelectAgent
|
|
2829
2923
|
} = useAgentListCore({
|
|
2830
2924
|
consumerId,
|
|
@@ -2837,7 +2931,7 @@ function AgentPickerBody({
|
|
|
2837
2931
|
...excludeAgentIds ? { excludeAgentIds } : {},
|
|
2838
2932
|
...defaultMandateKey ? { defaultMandateKey } : {}
|
|
2839
2933
|
});
|
|
2840
|
-
|
|
2934
|
+
useEffect4(() => {
|
|
2841
2935
|
ensureLoaded();
|
|
2842
2936
|
}, [ensureLoaded]);
|
|
2843
2937
|
const selectAgent = (agent) => {
|
|
@@ -2883,11 +2977,16 @@ function AgentPickerBody({
|
|
|
2883
2977
|
allTags,
|
|
2884
2978
|
onSelectAgent: selectAgent,
|
|
2885
2979
|
onDetailPress: setDetailAgent,
|
|
2886
|
-
onFilterChipPress:
|
|
2980
|
+
onFilterChipPress: (panel) => {
|
|
2981
|
+
if (panel !== "sort") ensureFullCatalog();
|
|
2982
|
+
setSubView(panel);
|
|
2983
|
+
},
|
|
2887
2984
|
onReset: consumer.resetFilters,
|
|
2888
2985
|
activeFilterCount,
|
|
2889
2986
|
tabCounts,
|
|
2890
2987
|
archivedHiddenCount,
|
|
2988
|
+
onReachEnd: loadMore,
|
|
2989
|
+
totalCount,
|
|
2891
2990
|
...visibleTabs ? { visibleTabs } : {},
|
|
2892
2991
|
...systemTabLabel ?? (includeSystemInAll ? "System" : void 0) ? {
|
|
2893
2992
|
systemTabLabel: systemTabLabel ?? (includeSystemInAll ? "System" : void 0)
|