@ai-matrx/agents 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +234 -0
- package/README.md +65 -5
- package/dist/catalog/index.cjs +1344 -0
- package/dist/catalog/index.cjs.map +1 -0
- package/dist/catalog/index.d.cts +868 -0
- package/dist/catalog/index.d.ts +868 -0
- package/dist/catalog/index.js +1321 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/react/index.cjs +2337 -0
- package/dist/catalog/react/index.cjs.map +1 -0
- package/dist/catalog/react/index.d.cts +819 -0
- package/dist/catalog/react/index.d.ts +819 -0
- package/dist/catalog/react/index.js +2340 -0
- package/dist/catalog/react/index.js.map +1 -0
- package/dist/catalog/styles.css +117 -0
- package/package.json +25 -3
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ai-matrx/agents/catalog` — the row shape and the per-consumer view state.
|
|
3
|
+
*
|
|
4
|
+
* `AgentSummary` is the 19-column row `agx_get_list_full()` returns, camelCased.
|
|
5
|
+
* It is deliberately NOT the editable agent record: dirty tracking, undo,
|
|
6
|
+
* messages, tools and `_fetchStatus` stay in whichever host owns the editor.
|
|
7
|
+
* A list row is a list row.
|
|
8
|
+
*
|
|
9
|
+
* The view-state types are a VERBATIM port of matrx-frontend
|
|
10
|
+
* `features/agents/redux/agent-consumers/slice.ts` — only the coupling seam
|
|
11
|
+
* inverts (Redux reducers become store actions in `./store`).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A branded agent id. Every id that reaches `onSelect` is one of these:
|
|
15
|
+
* either a `agent.definition` UUID, or the `mandate:<key>` reference a
|
|
16
|
+
* default row carries (byte-identical to the ref shape matrx-extend
|
|
17
|
+
* `src/lib/mandates.ts` and matrx-local `desktop/src/lib/mandates.ts`
|
|
18
|
+
* already hand back to their hosts).
|
|
19
|
+
*
|
|
20
|
+
* 🚨 The brand is a STRING LITERAL, never `unique symbol`. This package emits
|
|
21
|
+
* `./catalog` and `./catalog/react` as two separate bundles, so each `.d.ts`
|
|
22
|
+
* carries its own copy of these declarations. A `unique symbol` brand is
|
|
23
|
+
* NOMINAL: two copies of it are unrelated types, so `createAgentCatalog()`
|
|
24
|
+
* from `./catalog` was not assignable to `<AgentCatalogProvider catalog=…>`
|
|
25
|
+
* from `./catalog/react` — the exact two-import wiring the README, the
|
|
26
|
+
* CHANGELOG and every consumer use. A literal brand is structural, so the two
|
|
27
|
+
* copies unify, while a bare `string` still cannot be passed where an
|
|
28
|
+
* `AgentId` is required (which is the whole point of branding). Any future
|
|
29
|
+
* brand in this package follows the same rule.
|
|
30
|
+
*/
|
|
31
|
+
type AgentId = string & {
|
|
32
|
+
readonly __agentId: "ai-matrx.agent-id";
|
|
33
|
+
};
|
|
34
|
+
/** Brand a raw string as an `AgentId`. */
|
|
35
|
+
declare function asAgentId(value: string): AgentId;
|
|
36
|
+
/** The `mandate:<key>` ref shape every client already speaks. */
|
|
37
|
+
declare function mandateAgentId(mandateKey: string): AgentId;
|
|
38
|
+
/** True when an id is a mandate default row rather than a stored agent. */
|
|
39
|
+
declare function isMandateAgentId(id: string): boolean;
|
|
40
|
+
/** `agent_type` verbatim. Only `builtin` changes how a row is grouped. */
|
|
41
|
+
type AgentCatalogAgentType = "user" | "builtin";
|
|
42
|
+
/**
|
|
43
|
+
* `access_level` verbatim from `agx_get_list_full`. Widened over the raw
|
|
44
|
+
* string because it is a DB-owned vocabulary: an unknown level renders as
|
|
45
|
+
* itself rather than being coerced into a wrong one.
|
|
46
|
+
*/
|
|
47
|
+
type AgentAccessLevel = "owner" | "admin" | "editor" | "viewer" | "system" | (string & {});
|
|
48
|
+
/**
|
|
49
|
+
* One `agx_get_list_full()` row, camelCased. Nineteen columns, no more:
|
|
50
|
+
* anything richer needs a different read and is a different type.
|
|
51
|
+
*/
|
|
52
|
+
interface AgentSummary {
|
|
53
|
+
id: AgentId;
|
|
54
|
+
name: string | null;
|
|
55
|
+
description: string | null;
|
|
56
|
+
category: string | null;
|
|
57
|
+
tags: string[];
|
|
58
|
+
agentType: AgentCatalogAgentType;
|
|
59
|
+
modelId: string | null;
|
|
60
|
+
isActive: boolean;
|
|
61
|
+
isArchived: boolean;
|
|
62
|
+
isFavorite: boolean;
|
|
63
|
+
createdBy: string | null;
|
|
64
|
+
organizationId: string | null;
|
|
65
|
+
taskId: string | null;
|
|
66
|
+
sourceAgentId: string | null;
|
|
67
|
+
createdAt: string | null;
|
|
68
|
+
updatedAt: string | null;
|
|
69
|
+
isOwner: boolean | null;
|
|
70
|
+
accessLevel: AgentAccessLevel | null;
|
|
71
|
+
sharedByEmail: string | null;
|
|
72
|
+
/**
|
|
73
|
+
* Set only on a mandate default row — the key it resolved through, so a
|
|
74
|
+
* host can tell "the default" from a stored agent without parsing the id.
|
|
75
|
+
*/
|
|
76
|
+
mandateKey?: string;
|
|
77
|
+
}
|
|
78
|
+
type AgentSortOption = "updated-desc" | "created-desc" | "name-asc" | "name-desc" | "category-asc";
|
|
79
|
+
/** Which ownership tab is active in the agent list. */
|
|
80
|
+
type AgentTab = "mine" | "shared" | "all" | "system";
|
|
81
|
+
/** Favorite filter. */
|
|
82
|
+
type AgentFavFilter = "all" | "yes" | "no";
|
|
83
|
+
/** Archive filter. */
|
|
84
|
+
type AgentArchFilter = "active" | "archived" | "both";
|
|
85
|
+
/**
|
|
86
|
+
* Access level filter.
|
|
87
|
+
* 'any' = no restriction (default).
|
|
88
|
+
* 'owned' = only agents the user owns (isOwner = true).
|
|
89
|
+
* 'shared' = only agents shared with the user (isOwner = false).
|
|
90
|
+
* 'editable' = owner + admin + editor.
|
|
91
|
+
*/
|
|
92
|
+
type AgentAccessFilter = "any" | "owned" | "shared" | "editable";
|
|
93
|
+
/** Sentinel meaning "include uncategorized / untagged" items. */
|
|
94
|
+
declare const AGENT_NONE_SENTINEL = "__none__";
|
|
95
|
+
interface AgentConsumerState {
|
|
96
|
+
tab: AgentTab;
|
|
97
|
+
sortBy: AgentSortOption;
|
|
98
|
+
searchTerm: string;
|
|
99
|
+
/** INCLUSION model: empty = show all; non-empty = only matching. */
|
|
100
|
+
includedCats: string[];
|
|
101
|
+
/** INCLUSION model: empty = show all; non-empty = only matching. */
|
|
102
|
+
includedTags: string[];
|
|
103
|
+
favFilter: AgentFavFilter;
|
|
104
|
+
archFilter: AgentArchFilter;
|
|
105
|
+
accessFilter: AgentAccessFilter;
|
|
106
|
+
favoritesFirst: boolean;
|
|
107
|
+
/** Current page for owned-agent list items (after the card section). */
|
|
108
|
+
listPage: number;
|
|
109
|
+
/** Current page for shared-agent list items. */
|
|
110
|
+
sharedPage: number;
|
|
111
|
+
/**
|
|
112
|
+
* Ids returned by the last server-side search (`agx_search`), in server rank
|
|
113
|
+
* order. Additive: an agent in this list survives the search filter even
|
|
114
|
+
* when the local scorer gives it 0.
|
|
115
|
+
*
|
|
116
|
+
* That is load-bearing for tier 2. A deep search matches an agent's prompt
|
|
117
|
+
* content, which the client never loads — so the local scorer cannot see it.
|
|
118
|
+
* Without this list the server would return prompt matches and the UI would
|
|
119
|
+
* immediately filter them back out.
|
|
120
|
+
*
|
|
121
|
+
* Server-only matches sort BELOW every locally-scored match, in server rank
|
|
122
|
+
* order, so obvious matches always come first.
|
|
123
|
+
*/
|
|
124
|
+
serverMatchedIds: string[];
|
|
125
|
+
/** True while a server search is in flight — drives the search spinner. */
|
|
126
|
+
isServerSearching: boolean;
|
|
127
|
+
/** Tier 2: also search agent prompt content. Opt-in, per consumer. */
|
|
128
|
+
deepSearch: boolean;
|
|
129
|
+
}
|
|
130
|
+
declare const DEFAULT_AGENT_CONSUMER_STATE: AgentConsumerState;
|
|
131
|
+
/** The subset of consumer state a caller may patch (paging is derived). */
|
|
132
|
+
type AgentConsumerPatch = Partial<Omit<AgentConsumerState, "listPage" | "sharedPage">>;
|
|
133
|
+
/**
|
|
134
|
+
* Thrown by `createAgentCatalog` when a REQUIRED port is missing or an
|
|
135
|
+
* optional feature was asked for without the port it needs. Never a warning,
|
|
136
|
+
* never a degraded catalog: a picker that cannot read is not a picker.
|
|
137
|
+
*/
|
|
138
|
+
declare class AgentCatalogConfigError extends Error {
|
|
139
|
+
readonly name = "AgentCatalogConfigError";
|
|
140
|
+
/** Machine code, for a host that routes config failures. */
|
|
141
|
+
readonly code: string;
|
|
142
|
+
/** What the host must do, in a sentence a person can act on. */
|
|
143
|
+
readonly remedy: string;
|
|
144
|
+
constructor(args: {
|
|
145
|
+
code: string;
|
|
146
|
+
message: string;
|
|
147
|
+
remedy: string;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* `@ai-matrx/agents/catalog` — THE PORTS.
|
|
153
|
+
*
|
|
154
|
+
* Two are required (`client`, `identity`); every other one ships a working
|
|
155
|
+
* default with a DOCUMENTED degradation, per THE ALL-INCLUSIVE LAW. A host
|
|
156
|
+
* injects identity and a Supabase client and nothing else; the picker's only
|
|
157
|
+
* contract back to the host is `onSelect(agentId)`.
|
|
158
|
+
*
|
|
159
|
+
* React appears nowhere in this file — it is import-inert and legal in any
|
|
160
|
+
* graph, server components included.
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
/** A PostgREST error, structurally. */
|
|
164
|
+
interface PgErrorLike {
|
|
165
|
+
message: string;
|
|
166
|
+
code?: string;
|
|
167
|
+
details?: string | null;
|
|
168
|
+
hint?: string | null;
|
|
169
|
+
}
|
|
170
|
+
/** What every supabase-js call resolves to, structurally. */
|
|
171
|
+
interface PgResultLike {
|
|
172
|
+
data: unknown;
|
|
173
|
+
error: PgErrorLike | null;
|
|
174
|
+
count?: number | null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* The thenable builder supabase-js returns from `.rpc()`. `range` is what
|
|
178
|
+
* makes a COMPLETE list read possible (`readAllRows`); `order` is what makes
|
|
179
|
+
* that paging stable. Both are the real builder's own methods — this is a
|
|
180
|
+
* structural subset, never a re-implementation.
|
|
181
|
+
*/
|
|
182
|
+
interface AgentCatalogRpcCall extends PromiseLike<PgResultLike> {
|
|
183
|
+
range(from: number, to: number): PromiseLike<PgResultLike>;
|
|
184
|
+
order(column: string, options?: {
|
|
185
|
+
ascending?: boolean;
|
|
186
|
+
}): AgentCatalogRpcCall;
|
|
187
|
+
}
|
|
188
|
+
/** The one write this package performs: `agent.definition.is_favorite`. */
|
|
189
|
+
interface AgentCatalogTableQuery {
|
|
190
|
+
update(patch: Record<string, unknown>): {
|
|
191
|
+
eq(column: string, value: string): PromiseLike<{
|
|
192
|
+
data?: unknown;
|
|
193
|
+
error: PgErrorLike | null;
|
|
194
|
+
}>;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* REQUIRED. A structural subset of `SupabaseClient` — anything that can answer
|
|
199
|
+
* `agx_get_list_full`, `agx_search`, `agx_resolve_agent_address` and write one
|
|
200
|
+
* column on `agent.definition`. A real supabase-js client satisfies it as-is.
|
|
201
|
+
*
|
|
202
|
+
* Absent → `createAgentCatalog` throws `AgentCatalogConfigError`. There is no
|
|
203
|
+
* degraded mode: the package IS the catalogue read.
|
|
204
|
+
*/
|
|
205
|
+
interface AgentCatalogClient {
|
|
206
|
+
rpc(fn: string, args?: Record<string, unknown>, options?: {
|
|
207
|
+
count?: "exact" | "planned" | "estimated";
|
|
208
|
+
}): AgentCatalogRpcCall;
|
|
209
|
+
schema(name: string): {
|
|
210
|
+
from(table: string): AgentCatalogTableQuery;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* REQUIRED. Who is asking. Needed for the "zero owned agents → open on the
|
|
215
|
+
* public tab" heuristic and for the favorite write.
|
|
216
|
+
*
|
|
217
|
+
* `requireUserId` THROWS when there is no session — never a silent anonymous
|
|
218
|
+
* read. The catalog catches that throw in exactly ONE place (the tab-default
|
|
219
|
+
* heuristic, where a signed-out visitor legitimately lands on the public
|
|
220
|
+
* catalogue) and reports it to the `errorSink` the first time; every other
|
|
221
|
+
* caller lets it propagate.
|
|
222
|
+
*/
|
|
223
|
+
interface AgentCatalogIdentity {
|
|
224
|
+
requireUserId(): string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Every degraded path, every failed read, every drift detection reports here.
|
|
228
|
+
* DEFAULT: a tagged `console.error` that announces ONCE that no sink is bound
|
|
229
|
+
* and names the remedy.
|
|
230
|
+
*/
|
|
231
|
+
type AgentCatalogErrorSink = (event: {
|
|
232
|
+
code: string;
|
|
233
|
+
message: string;
|
|
234
|
+
context?: object;
|
|
235
|
+
}) => void;
|
|
236
|
+
/**
|
|
237
|
+
* The drift scream's second channel. DEFAULT: none — and that is safe
|
|
238
|
+
* ONLY because the in-picker persistent banner is the primary scream and
|
|
239
|
+
* always renders. A drift is never console-only.
|
|
240
|
+
*/
|
|
241
|
+
type AgentCatalogNotifier = (event: {
|
|
242
|
+
level: "warning" | "error";
|
|
243
|
+
title: string;
|
|
244
|
+
message: string;
|
|
245
|
+
}) => void;
|
|
246
|
+
/**
|
|
247
|
+
* First-paint cache for resolved default rows. DEFAULT: `localStorage` when
|
|
248
|
+
* present, else an in-memory map (so SSR and a Chrome service worker both
|
|
249
|
+
* work). Absent storage degrades to "no first paint of the default row until
|
|
250
|
+
* the mandate resolves" — never a wrong name on screen.
|
|
251
|
+
*/
|
|
252
|
+
interface AgentCatalogStorage {
|
|
253
|
+
getItem(key: string): string | null;
|
|
254
|
+
setItem(key: string, value: string): void;
|
|
255
|
+
removeItem(key: string): void;
|
|
256
|
+
}
|
|
257
|
+
/** Every user-visible string the picker renders, overridable per host. */
|
|
258
|
+
interface AgentCatalogLabels {
|
|
259
|
+
/** User-facing label for the `system` ownership tab. */
|
|
260
|
+
publicTab: string;
|
|
261
|
+
/**
|
|
262
|
+
* Badge label on a builtin row. Default `"system"` — the string
|
|
263
|
+
* `AgentRow` actually rendered in matrx-frontend. (The frontend also
|
|
264
|
+
* declared `AGENT_PUBLIC_BADGE_LABEL = "Public"` for this badge and NOTHING
|
|
265
|
+
* ever read it — a constant that named the badge without being the badge.
|
|
266
|
+
* Recorded in the CHANGELOG and dropped rather than ported.)
|
|
267
|
+
*/
|
|
268
|
+
systemBadge: string;
|
|
269
|
+
searchPlaceholder: string;
|
|
270
|
+
currentAgentHeading: string;
|
|
271
|
+
emptyDefault: string;
|
|
272
|
+
emptyShared: string;
|
|
273
|
+
emptySystem: string;
|
|
274
|
+
loading: string;
|
|
275
|
+
triggerFallback: string;
|
|
276
|
+
triggerResolving: string;
|
|
277
|
+
triggerUnnameable: string;
|
|
278
|
+
hoverHint: string;
|
|
279
|
+
}
|
|
280
|
+
declare const DEFAULT_AGENT_CATALOG_LABELS: AgentCatalogLabels;
|
|
281
|
+
interface AgentCatalogConfig {
|
|
282
|
+
/** REQUIRED — the Supabase client. */
|
|
283
|
+
client: AgentCatalogClient;
|
|
284
|
+
/** REQUIRED — who is asking. */
|
|
285
|
+
identity: AgentCatalogIdentity;
|
|
286
|
+
/**
|
|
287
|
+
* The catalog's registry key on `globalThis`. Two `createAgentCatalog`
|
|
288
|
+
* calls with the same id are the same catalog (and the second one screams
|
|
289
|
+
* through the errorSink before replacing the first). Default `"default"`.
|
|
290
|
+
*/
|
|
291
|
+
catalogId?: string;
|
|
292
|
+
/** OPTIONAL — see `AgentCatalogErrorSink`. */
|
|
293
|
+
errorSink?: AgentCatalogErrorSink;
|
|
294
|
+
/** OPTIONAL — see `AgentCatalogNotifier`. */
|
|
295
|
+
notifier?: AgentCatalogNotifier;
|
|
296
|
+
/** OPTIONAL — see `AgentCatalogStorage`. */
|
|
297
|
+
storage?: AgentCatalogStorage;
|
|
298
|
+
/**
|
|
299
|
+
* OPTIONAL — the package's own `MatrxTransport` (`createMatrxTransport`
|
|
300
|
+
* from `@ai-matrx/agents/matrx`). REQUIRED the moment any picker instance
|
|
301
|
+
* passes a `defaultMandateKey`: THE PLATFORM RULE D-R1 says clients never
|
|
302
|
+
* walk the mandate ladder, so the default row can only be resolved through
|
|
303
|
+
* the aidream door `GET /mandates/{mandate_key}/resolution`. A
|
|
304
|
+
* `defaultMandateKey` with no transport throws `AgentCatalogConfigError`.
|
|
305
|
+
*/
|
|
306
|
+
transport?: AgentCatalogTransport;
|
|
307
|
+
/** OPTIONAL — label overrides. */
|
|
308
|
+
labels?: Partial<AgentCatalogLabels>;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* The transport seam, structurally identical to `MatrxTransport` from
|
|
312
|
+
* `@ai-matrx/agents/matrx` (declared structurally so `./catalog` never
|
|
313
|
+
* imports the transport module and stays import-inert).
|
|
314
|
+
*/
|
|
315
|
+
interface AgentCatalogTransport {
|
|
316
|
+
fetch(path: string, init: {
|
|
317
|
+
method: "GET" | "POST";
|
|
318
|
+
headers: Record<string, string>;
|
|
319
|
+
body?: string;
|
|
320
|
+
signal?: AbortSignal;
|
|
321
|
+
}): Promise<Response>;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Where a row's href goes when someone cmd-clicks it, and where `navigateTo`
|
|
325
|
+
* lands. DEFAULT: `window.location.assign` (so cmd-click and ordinary
|
|
326
|
+
* navigation both work with no host wiring at all).
|
|
327
|
+
*/
|
|
328
|
+
type AgentCatalogNavigate = (href: string) => void;
|
|
329
|
+
/** Resolve a per-row href. DEFAULT: `/agents/go/<id>` — the always-valid door. */
|
|
330
|
+
type AgentCatalogResolveHref = (agent: AgentSummary) => string;
|
|
331
|
+
/**
|
|
332
|
+
* The sneak-peek affordance. Absent → the affordance is HIDDEN, never a dead
|
|
333
|
+
* button (nothing fails silently, and nothing looks alive when it is not).
|
|
334
|
+
*/
|
|
335
|
+
type AgentCatalogOpenPeek = (agent: AgentSummary) => void;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* catalog/default-row-types.ts — @ai-matrx/agents/catalog
|
|
339
|
+
*
|
|
340
|
+
* Split out of `default-row.ts` so `global-state.ts` can name the cached
|
|
341
|
+
* shape without importing the resolver (and its transport work) — the same
|
|
342
|
+
* split-out reflex C8 asks for, at module scale.
|
|
343
|
+
*/
|
|
344
|
+
|
|
345
|
+
/** The wire shape of `GET /mandates/{mandate_key}/resolution`, narrowed. */
|
|
346
|
+
interface MandateResolutionVerdict {
|
|
347
|
+
mandateKey: string;
|
|
348
|
+
holderType: string;
|
|
349
|
+
/** The executable id. `null` for a workflow Holder — a picker cannot run one. */
|
|
350
|
+
agentId: string | null;
|
|
351
|
+
isVersion: boolean;
|
|
352
|
+
/** Always the `agent.definition` id, even when `agentId` is a version. */
|
|
353
|
+
definitionAgentId: string | null;
|
|
354
|
+
/** Which precedence layer answered. Shown so a person can see WHY. */
|
|
355
|
+
provenance: string;
|
|
356
|
+
}
|
|
357
|
+
/** A resolved default row, cached for first paint and compared for drift. */
|
|
358
|
+
interface ResolvedDefaultRow {
|
|
359
|
+
mandateKey: string;
|
|
360
|
+
/** The `agent.definition` id the mandate resolved to. */
|
|
361
|
+
holderId: string;
|
|
362
|
+
/** The holder's REAL name, read from the catalogue — never hardcoded. */
|
|
363
|
+
holderName: string;
|
|
364
|
+
holderDescription: string | null;
|
|
365
|
+
provenance: string;
|
|
366
|
+
/** Epoch ms of this resolution. */
|
|
367
|
+
at: number;
|
|
368
|
+
}
|
|
369
|
+
/** What the picker renders and what it screams, together. */
|
|
370
|
+
interface DefaultRowState {
|
|
371
|
+
mandateKey: string;
|
|
372
|
+
/** The row to render at the top of the list. `null` until resolved. */
|
|
373
|
+
row: AgentSummary | null;
|
|
374
|
+
/** The last live resolution, or the cached one before the live answer lands. */
|
|
375
|
+
resolved: ResolvedDefaultRow | null;
|
|
376
|
+
/** True while the resolution is in flight. */
|
|
377
|
+
loading: boolean;
|
|
378
|
+
/**
|
|
379
|
+
* 🚨 THE DRIFT SCREAM. Set when the cached first-paint row and the LIVE
|
|
380
|
+
* resolution disagree on holder id or holder name. Rendered as a persistent
|
|
381
|
+
* in-picker banner AND sent to the `notifier` port — never console-only.
|
|
382
|
+
*/
|
|
383
|
+
drift: string | null;
|
|
384
|
+
/** Set when the mandate could not be resolved at all. Loud, with a remedy. */
|
|
385
|
+
error: string | null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* catalog/schema.ts — @ai-matrx/agents/catalog
|
|
390
|
+
*
|
|
391
|
+
* THE DEMANDED SCHEMA PROBE (the `@ai-matrx/associations` `assertDemandedSchema`
|
|
392
|
+
* precedent). It proves that the database a host pointed this catalog at can
|
|
393
|
+
* actually answer the three functions the picker demands.
|
|
394
|
+
*
|
|
395
|
+
* 🚨 IT MUST BE ABLE TO FAIL. A probe whose green result is unconditional
|
|
396
|
+
* proves nothing, so `selfTest: true` also probes a fabricated function name
|
|
397
|
+
* and REQUIRES it to come back missing. `catalog/__tests__/schema.test.ts`
|
|
398
|
+
* runs the whole probe against a client whose `rpc` answers PostgreSQL 42883
|
|
399
|
+
* (`undefined_function`, which PostgREST surfaces as PGRST202) and asserts the
|
|
400
|
+
* loud error.
|
|
401
|
+
*/
|
|
402
|
+
|
|
403
|
+
interface AgentCatalogSchemaReport {
|
|
404
|
+
ok: boolean;
|
|
405
|
+
/** Demanded functions the database cannot answer. */
|
|
406
|
+
missing: string[];
|
|
407
|
+
/** Functions the probe could not reach (transport/unknown failure). */
|
|
408
|
+
unreachable: {
|
|
409
|
+
fn: string;
|
|
410
|
+
error: unknown;
|
|
411
|
+
}[];
|
|
412
|
+
/** Functions that answered (success or any non-missing refusal). */
|
|
413
|
+
answered: string[];
|
|
414
|
+
/** True when `agent.definition.is_favorite` is writable by this caller. */
|
|
415
|
+
favoriteWritable: boolean | null;
|
|
416
|
+
}
|
|
417
|
+
interface AssertAgentCatalogSchemaOptions {
|
|
418
|
+
/**
|
|
419
|
+
* Also probe a fabricated function name and REQUIRE it to come back
|
|
420
|
+
* missing — proves this probe can fail.
|
|
421
|
+
*/
|
|
422
|
+
selfTest?: boolean;
|
|
423
|
+
/** Return the report instead of throwing. The self-test failure ALWAYS throws. */
|
|
424
|
+
throwOnViolation?: boolean;
|
|
425
|
+
/**
|
|
426
|
+
* Also probe the ONE write (`agent.definition.is_favorite`) against an
|
|
427
|
+
* impossible id, so a 42501/permission refusal is seen at boot rather than
|
|
428
|
+
* on a user's first click. Default: on.
|
|
429
|
+
*/
|
|
430
|
+
probeWrite?: boolean;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Probe every demanded function. Throws an `Error` naming each missing one
|
|
434
|
+
* (unless `throwOnViolation: false`), and ALWAYS throws when the probe itself
|
|
435
|
+
* cannot be trusted (unreachable database, failed self-test).
|
|
436
|
+
*/
|
|
437
|
+
declare function assertAgentCatalogSchema(client: AgentCatalogClient, options?: AssertAgentCatalogSchemaOptions): Promise<AgentCatalogSchemaReport>;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* catalog/store.ts — @ai-matrx/agents/catalog
|
|
441
|
+
*
|
|
442
|
+
* `createAgentCatalog(config)` — the headless kernel. Everything the picker
|
|
443
|
+
* knows lives here: the row registry, the complete-list read with its
|
|
444
|
+
* session-shared in-flight dedupe and freshness window, the tier-2 server
|
|
445
|
+
* search, the per-consumer view state, the ONE write, and the mandate default
|
|
446
|
+
* row with its drift screamer.
|
|
447
|
+
*
|
|
448
|
+
* The host injects a Supabase client and who the user is. Nothing else.
|
|
449
|
+
*
|
|
450
|
+
* The consumer reducers below are a VERBATIM port of matrx-frontend
|
|
451
|
+
* `features/agents/redux/agent-consumers/slice.ts`; only the seam inverts
|
|
452
|
+
* (a Redux reducer becomes a store method, and Immer's draft mutation becomes
|
|
453
|
+
* an explicit copy so the store can publish a new reference).
|
|
454
|
+
*/
|
|
455
|
+
|
|
456
|
+
type AgentCatalogStatus = "idle" | "loading" | "succeeded" | "failed";
|
|
457
|
+
interface AgentCatalogState {
|
|
458
|
+
/** Every row, one stable array reference per change (memoization depends on it). */
|
|
459
|
+
rows: AgentSummary[];
|
|
460
|
+
byId: Record<string, AgentSummary>;
|
|
461
|
+
status: AgentCatalogStatus;
|
|
462
|
+
error: string | null;
|
|
463
|
+
consumers: Record<string, AgentConsumerState>;
|
|
464
|
+
/** Keyed by mandate key. */
|
|
465
|
+
defaultRows: Record<string, DefaultRowState>;
|
|
466
|
+
}
|
|
467
|
+
interface AgentCatalog {
|
|
468
|
+
readonly catalogId: string;
|
|
469
|
+
readonly labels: AgentCatalogLabels;
|
|
470
|
+
readonly errorSink: AgentCatalogErrorSink;
|
|
471
|
+
readonly notifier: AgentCatalogNotifier | undefined;
|
|
472
|
+
/** True when this catalog was given a transport and can resolve mandates. */
|
|
473
|
+
readonly canResolveMandates: boolean;
|
|
474
|
+
getState(): AgentCatalogState;
|
|
475
|
+
subscribe(listener: () => void): () => void;
|
|
476
|
+
getAgent(agentId: string): AgentSummary | undefined;
|
|
477
|
+
/**
|
|
478
|
+
* The signed-in user id, or `null` when there is no session. The ONE place
|
|
479
|
+
* `identity.requireUserId()`'s throw is caught — a signed-out visitor
|
|
480
|
+
* legitimately lands on the public catalogue — and it is reported to the
|
|
481
|
+
* errorSink the first time so it is never silent.
|
|
482
|
+
*/
|
|
483
|
+
getUserIdOrNull(): string | null;
|
|
484
|
+
/** Load the catalogue if it is not fresh. Safe to call on every mount. */
|
|
485
|
+
ensureLoaded(options?: {
|
|
486
|
+
force?: boolean;
|
|
487
|
+
}): Promise<void>;
|
|
488
|
+
/** True when the last load is inside the 15-minute TTL. */
|
|
489
|
+
isFresh(): boolean;
|
|
490
|
+
/** True when the last load is older than 4 hours (tab-restore threshold). */
|
|
491
|
+
isStale(): boolean;
|
|
492
|
+
getConsumer(consumerId: string): AgentConsumerState;
|
|
493
|
+
registerConsumer(consumerId: string, initial?: AgentConsumerPatch): void;
|
|
494
|
+
unregisterConsumer(consumerId: string): void;
|
|
495
|
+
setConsumerFilter(consumerId: string, patch: AgentConsumerPatch): void;
|
|
496
|
+
setConsumerPage(consumerId: string, which: "list" | "shared", page: number): void;
|
|
497
|
+
setConsumerServerSearch(consumerId: string, args: {
|
|
498
|
+
matchedIds?: string[];
|
|
499
|
+
isSearching?: boolean;
|
|
500
|
+
}): void;
|
|
501
|
+
resetConsumerFilters(consumerId: string): void;
|
|
502
|
+
/** Tier-2 search. Purely additive; merges rows into the registry. */
|
|
503
|
+
searchServer(query: string, deep?: boolean): Promise<string[]>;
|
|
504
|
+
/** THE ONE WRITE. Optimistic, rolled back on failure, loud either way. */
|
|
505
|
+
setFavorite(agentId: string, isFavorite: boolean): Promise<void>;
|
|
506
|
+
/** Resolve (once) the default row for a mandate key. Idempotent. */
|
|
507
|
+
ensureDefaultRow(mandateKey: string): void;
|
|
508
|
+
getDefaultRow(mandateKey: string): DefaultRowState | undefined;
|
|
509
|
+
/** A person acknowledged the drift banner. The notifier already fired. */
|
|
510
|
+
dismissDefaultRowDrift(mandateKey: string): void;
|
|
511
|
+
assertSchema(options?: AssertAgentCatalogSchemaOptions): Promise<AgentCatalogSchemaReport>;
|
|
512
|
+
}
|
|
513
|
+
declare function createAgentCatalog(config: AgentCatalogConfig): AgentCatalog;
|
|
514
|
+
/**
|
|
515
|
+
* The catalog registered under `catalogId`, across loader graphs. Returns
|
|
516
|
+
* `undefined` when none has been created yet — never a silent stub.
|
|
517
|
+
*/
|
|
518
|
+
declare function getRegisteredAgentCatalog(catalogId?: string): AgentCatalog | undefined;
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* catalog/data.ts — @ai-matrx/agents/catalog
|
|
522
|
+
*
|
|
523
|
+
* Every database call the catalog makes, and nothing else. Four of them:
|
|
524
|
+
*
|
|
525
|
+
* 1. `agx_get_list_full()` — the complete catalogue (owned + directly-shared
|
|
526
|
+
* + org-shared user agents, unioned with active builtins).
|
|
527
|
+
* 2. `agx_search(p_query, p_deep, p_limit, p_offset)` — tier-2 server search.
|
|
528
|
+
* 3. `agx_resolve_agent_address(p_ids)` — the single-agent name read, used
|
|
529
|
+
* when a mandate's Holder is not in the caller's own catalogue.
|
|
530
|
+
* 4. ONE write: `agent.definition.is_favorite`.
|
|
531
|
+
*
|
|
532
|
+
* 🚨 THE LIST READ IS COMPLETE OR IT THROWS. PostgREST caps every response at
|
|
533
|
+
* `db-max-rows` (1000 on Matrx Main) and reports success — matrx-frontend's
|
|
534
|
+
* `fetchAgentsListFull` issued a bare `.rpc()` and would silently have
|
|
535
|
+
* returned 1000 rows of a larger catalogue (the ~400-builtin truncation
|
|
536
|
+
* incident is the near-miss). Here the read goes through `readAllRows` with
|
|
537
|
+
* `{ count: "exact" }` and a stable `.order("id")`, so a truncation is a
|
|
538
|
+
* loud `IncompleteReadError` instead of a confidently short picker.
|
|
539
|
+
* The DB's own favourites-first/`updated_at` order is irrelevant: every row
|
|
540
|
+
* is re-sorted client-side by `sortFilteredAgents`.
|
|
541
|
+
*/
|
|
542
|
+
|
|
543
|
+
/** Server search page size — the frontend's `AGENT_SEARCH_LIMIT`. */
|
|
544
|
+
declare const AGENT_SEARCH_LIMIT = 50;
|
|
545
|
+
declare class AgentCatalogReadError extends Error {
|
|
546
|
+
readonly name = "AgentCatalogReadError";
|
|
547
|
+
readonly source: string;
|
|
548
|
+
constructor(source: string, detail: string);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Read the WHOLE agent catalogue. Throws rather than returning a partial
|
|
552
|
+
* list — see the file header.
|
|
553
|
+
*/
|
|
554
|
+
declare function readAgentCatalogRows(client: AgentCatalogClient): Promise<AgentSummary[]>;
|
|
555
|
+
interface AgentServerSearchResult {
|
|
556
|
+
/** Matched ids in SERVER RANK ORDER. */
|
|
557
|
+
ids: string[];
|
|
558
|
+
/** Full rows for every hit — merged additively into the registry. */
|
|
559
|
+
rows: AgentSummary[];
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Tier-2 server search. Purely ADDITIVE: it widens what the local filter
|
|
563
|
+
* admits and never removes a row the local scorer already matched.
|
|
564
|
+
*/
|
|
565
|
+
declare function searchAgentsOnServer(client: AgentCatalogClient, args: {
|
|
566
|
+
query: string;
|
|
567
|
+
deep?: boolean;
|
|
568
|
+
limit?: number;
|
|
569
|
+
}): Promise<AgentServerSearchResult>;
|
|
570
|
+
/**
|
|
571
|
+
* The single-agent read, used when a mandate's resolved Holder is not in the
|
|
572
|
+
* caller's own catalogue (a platform agent nobody has shared, most often).
|
|
573
|
+
*
|
|
574
|
+
* Two existing doors, in order — never a new RPC:
|
|
575
|
+
* 1. `agx_search` with the id as the query. The scorer awards an exact id
|
|
576
|
+
* match 100000, so the row comes back first, and it is the FULL 19-column
|
|
577
|
+
* row (name AND description AND category AND tags).
|
|
578
|
+
* 2. `agx_resolve_agent_address([id])` — the frontend's own name resolver.
|
|
579
|
+
* Name and type only, so the row renders with an honest name and no
|
|
580
|
+
* description rather than a fabricated one.
|
|
581
|
+
*
|
|
582
|
+
* Returns `null` when neither door can name the agent. The caller SCREAMS;
|
|
583
|
+
* it never invents a label.
|
|
584
|
+
*/
|
|
585
|
+
declare function readSingleAgentRow(client: AgentCatalogClient, agentId: string): Promise<AgentSummary | null>;
|
|
586
|
+
/**
|
|
587
|
+
* THE ONE WRITE. Mirrors matrx-frontend's `saveAgentField` for this field
|
|
588
|
+
* exactly: `agent.definition.is_favorite`, addressed by id.
|
|
589
|
+
*/
|
|
590
|
+
declare function writeAgentFavorite(client: AgentCatalogClient, agentId: string, isFavorite: boolean): Promise<void>;
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* catalog/rows.ts — @ai-matrx/agents/catalog
|
|
594
|
+
*
|
|
595
|
+
* The ONE ingress for a database row. `agx_get_list_full()` and `agx_search()`
|
|
596
|
+
* return the same 19 columns (search adds two ranking columns), so both come
|
|
597
|
+
* through here and produce the identical `AgentSummary`.
|
|
598
|
+
*
|
|
599
|
+
* Typed over `unknown` on purpose: the truth of this boundary is a
|
|
600
|
+
* HOST-generated Supabase type this package cannot see (the `@ai-matrx/data`
|
|
601
|
+
* 0.2.1 lesson). Narrowing happens here, once, loudly — a row that is not an
|
|
602
|
+
* object is REFUSED rather than half-read.
|
|
603
|
+
*/
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Map one raw list/search row. Returns `null` when the row is not an object
|
|
607
|
+
* or carries no id — the caller reports that to the errorSink and drops it;
|
|
608
|
+
* a row with no identity cannot be selected, so rendering it would be a lie.
|
|
609
|
+
*/
|
|
610
|
+
declare function toAgentSummary(raw: unknown): AgentSummary | null;
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* catalog/default-row.ts — @ai-matrx/agents/catalog
|
|
614
|
+
*
|
|
615
|
+
* THE DEFAULT ROW, and the drift screamer (design D3).
|
|
616
|
+
*
|
|
617
|
+
* What every client used to do: prepend a placeholder row whose id is
|
|
618
|
+
* `mandate:<key>` and whose name and description are HARDCODED, and let the
|
|
619
|
+
* server resolve the real Holder at run time. That is how matrx-local's row
|
|
620
|
+
* came to be labelled "Matrx Desktop Agent" while `local.cloud_chat` actually
|
|
621
|
+
* resolves to General Chat — a label lying on screen, with nothing anywhere
|
|
622
|
+
* that could notice.
|
|
623
|
+
*
|
|
624
|
+
* What happens here instead:
|
|
625
|
+
*
|
|
626
|
+
* - A picker instance passes `defaultMandateKey`. The package resolves the
|
|
627
|
+
* Holder through the aidream door `GET /mandates/{key}/resolution`
|
|
628
|
+
* (verified against `aidream/api/routers/mandate_bindings.py`,
|
|
629
|
+
* `get_mandate_resolution`, mounted at prefix `/mandates`) using the
|
|
630
|
+
* injected `transport`.
|
|
631
|
+
* 🚨 THE PLATFORM RULE D-R1: a client NEVER walks the mandate ladder
|
|
632
|
+
* itself. It asks. That is why a `defaultMandateKey` with no transport is
|
|
633
|
+
* a loud config error and not a DB read.
|
|
634
|
+
* - The row renders the Holder's REAL name and description, read from the
|
|
635
|
+
* catalogue rows already in hand, or through ONE existing single-agent
|
|
636
|
+
* read when the Holder is not in this caller's catalogue.
|
|
637
|
+
* - The last resolution is cached in the `storage` port for first paint.
|
|
638
|
+
* - Whenever the cached row and the LIVE resolution disagree on holder id
|
|
639
|
+
* or holder name, the picker shows a PERSISTENT in-picker banner AND the
|
|
640
|
+
* `notifier` port fires. Never a console line, never only a console line.
|
|
641
|
+
*
|
|
642
|
+
* The row's id stays `mandate:<key>` byte-for-byte, because matrx-extend
|
|
643
|
+
* (`src/lib/mandates.ts`) and matrx-local (`desktop/src/lib/mandates.ts`)
|
|
644
|
+
* already hand that exact ref to their hosts.
|
|
645
|
+
*/
|
|
646
|
+
|
|
647
|
+
declare class MandateDefaultRowError extends Error {
|
|
648
|
+
readonly name = "MandateDefaultRowError";
|
|
649
|
+
readonly mandateKey: string;
|
|
650
|
+
readonly remedy: string;
|
|
651
|
+
constructor(args: {
|
|
652
|
+
mandateKey: string;
|
|
653
|
+
message: string;
|
|
654
|
+
remedy: string;
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
/** Narrow the server's `MandateResolutionResponse` to what a picker needs. */
|
|
658
|
+
declare function parseMandateResolution(mandateKey: string, raw: unknown): MandateResolutionVerdict;
|
|
659
|
+
/** An in-memory storage, used when the host binds none and there is no DOM. */
|
|
660
|
+
declare function createMemoryStorage(): AgentCatalogStorage;
|
|
661
|
+
/**
|
|
662
|
+
* DEFAULT storage: `localStorage` when it exists AND answers (a private
|
|
663
|
+
* window, a service worker, or SSR all fail differently), else memory.
|
|
664
|
+
*/
|
|
665
|
+
declare function defaultStorage(): AgentCatalogStorage;
|
|
666
|
+
declare function readCachedDefaultRow(storage: AgentCatalogStorage, mandateKey: string): ResolvedDefaultRow | null;
|
|
667
|
+
declare function writeCachedDefaultRow(storage: AgentCatalogStorage, resolved: ResolvedDefaultRow): void;
|
|
668
|
+
/** Build the `mandate:<key>` row from a resolved Holder. Never hardcodes text. */
|
|
669
|
+
declare function defaultRowFromResolution(resolved: ResolvedDefaultRow): AgentSummary;
|
|
670
|
+
/**
|
|
671
|
+
* The drift verdict. Cached vs live: a changed holder id OR a changed holder
|
|
672
|
+
* name is drift. Returns the sentence to show, or `null` when they agree.
|
|
673
|
+
*/
|
|
674
|
+
declare function detectDefaultRowDrift(cached: ResolvedDefaultRow | null, live: ResolvedDefaultRow): string | null;
|
|
675
|
+
interface ResolveDefaultRowArgs {
|
|
676
|
+
mandateKey: string;
|
|
677
|
+
transport: AgentCatalogTransport;
|
|
678
|
+
client: AgentCatalogClient;
|
|
679
|
+
storage: AgentCatalogStorage;
|
|
680
|
+
errorSink: AgentCatalogErrorSink;
|
|
681
|
+
/** Look the Holder up in the rows this catalog already holds. */
|
|
682
|
+
lookupRow: (agentId: string) => AgentSummary | undefined;
|
|
683
|
+
}
|
|
684
|
+
interface ResolveDefaultRowOutcome {
|
|
685
|
+
resolved: ResolvedDefaultRow;
|
|
686
|
+
row: AgentSummary;
|
|
687
|
+
/** Non-null when the cached first-paint row disagreed with the live answer. */
|
|
688
|
+
drift: string | null;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Ask the server, name the Holder for real, cache the answer, and report
|
|
692
|
+
* drift. Throws `MandateDefaultRowError` when the mandate cannot produce a
|
|
693
|
+
* runnable agent — a picker never renders a default row it cannot name.
|
|
694
|
+
*/
|
|
695
|
+
declare function resolveDefaultRow(args: ResolveDefaultRowArgs): Promise<ResolveDefaultRowOutcome>;
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* catalog/labels.ts — @ai-matrx/agents/catalog
|
|
699
|
+
*
|
|
700
|
+
* VERBATIM port of matrx-frontend `features/agents/constants/agent-list-labels.ts`.
|
|
701
|
+
* The only seam inverted: the two label constants moved into the `labels` port
|
|
702
|
+
* (`DEFAULT_AGENT_CATALOG_LABELS.publicTab` / `.publicBadge`) so a host can
|
|
703
|
+
* override them; the FUNCTIONS below keep their exact behaviour.
|
|
704
|
+
*/
|
|
705
|
+
|
|
706
|
+
declare function agentListEmptyLabel(tab: AgentTab, labels: AgentCatalogLabels): string;
|
|
707
|
+
/** Whether a list picker should default to the public (`system`) tab instead of Mine. */
|
|
708
|
+
declare function shouldDefaultAgentListToPublicTab(args: {
|
|
709
|
+
userId: string | null;
|
|
710
|
+
ownedCount: number;
|
|
711
|
+
agentsLoaded: boolean;
|
|
712
|
+
}): boolean;
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* The structural shape a record needs to be searchable. Every field except
|
|
716
|
+
* `id` is optional so both the full gallery record and the slim chat record
|
|
717
|
+
* satisfy it without adapters.
|
|
718
|
+
*/
|
|
719
|
+
interface AgentSearchable {
|
|
720
|
+
id: string;
|
|
721
|
+
name?: string | null;
|
|
722
|
+
description?: string | null;
|
|
723
|
+
category?: string | null;
|
|
724
|
+
tags?: string[] | null;
|
|
725
|
+
modelId?: string | null;
|
|
726
|
+
agentType?: string | null;
|
|
727
|
+
outputFormat?: string | null;
|
|
728
|
+
sharedByEmail?: string | null;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Relevance score for an agent against a query. Higher = more relevant.
|
|
732
|
+
* Returns 0 when nothing matches (0 is the "no match" contract — see
|
|
733
|
+
* `agentMatchesSearch`).
|
|
734
|
+
*
|
|
735
|
+
* Scores only fields carried by the list-level fetches. Message content and
|
|
736
|
+
* variable definitions are deliberately excluded: they are not loaded by the
|
|
737
|
+
* list RPCs, so matching them here would be a false promise. Server-side
|
|
738
|
+
* search owns deep content matching.
|
|
739
|
+
*/
|
|
740
|
+
declare function computeAgentSearchScore(agent: AgentSearchable, query: string): number;
|
|
741
|
+
/** True when the agent matches the query at all. */
|
|
742
|
+
declare function agentMatchesSearch(agent: AgentSearchable, query: string): boolean;
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* catalog/selectors.ts — @ai-matrx/agents/catalog
|
|
746
|
+
*
|
|
747
|
+
* VERBATIM port of matrx-frontend
|
|
748
|
+
* `features/agents/redux/agent-consumers/selectors.ts`.
|
|
749
|
+
*
|
|
750
|
+
* ALL filter, sort, search-scoring, category/tag extraction and pagination
|
|
751
|
+
* logic lives here — not in components. Two coupling seams inverted, nothing
|
|
752
|
+
* else:
|
|
753
|
+
*
|
|
754
|
+
* 1. `createSelector` (reselect) → `memoize1`/`memoize2`/`memoize3` below,
|
|
755
|
+
* the same last-arguments reference-equality memoization reselect
|
|
756
|
+
* defaults to. No Redux, no store types.
|
|
757
|
+
* 2. `AgentDefinitionRecord` → `AgentSummary`, the list-row shape
|
|
758
|
+
* `agx_get_list_full` actually returns.
|
|
759
|
+
*
|
|
760
|
+
* One structural consequence of (2), recorded rather than hidden: the
|
|
761
|
+
* frontend's `selectLiveAgents` filters `isVersion` snapshots out of a store
|
|
762
|
+
* that also holds them. This catalog only ever holds list rows — a version
|
|
763
|
+
* snapshot cannot enter it — so that filter is a no-op here and is not
|
|
764
|
+
* ported. Every ordering, tie-break and count below is byte-identical.
|
|
765
|
+
*/
|
|
766
|
+
|
|
767
|
+
declare const AGENT_CARDS_LIMIT_DESKTOP = 8;
|
|
768
|
+
declare const AGENT_CARDS_LIMIT_MOBILE = 4;
|
|
769
|
+
declare const AGENT_LIST_ITEMS_PER_PAGE = 20;
|
|
770
|
+
/**
|
|
771
|
+
* Last-arguments memoization on reference equality — reselect's default
|
|
772
|
+
* `defaultMemoize` behaviour, in eleven lines and with no dependency. A
|
|
773
|
+
* selector built here is memoized PER INSTANCE, exactly like a
|
|
774
|
+
* `createSelector` result, so the factories below keep their contract:
|
|
775
|
+
* build the selector once per (consumerId, …) and reuse it.
|
|
776
|
+
*/
|
|
777
|
+
declare function memoize1<A, R>(fn: (a: A) => R): (a: A) => R;
|
|
778
|
+
declare function memoize2<A, B, R>(fn: (a: A, b: B) => R): (a: A, b: B) => R;
|
|
779
|
+
declare function memoize3<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (a: A, b: B, c: C) => R;
|
|
780
|
+
declare function applyAgentSortComparator(a: AgentSummary, b: AgentSummary, sortBy: AgentSortOption): number;
|
|
781
|
+
/** All unique categories across live USER agents, sorted alphabetically. */
|
|
782
|
+
declare const selectAllAgentCategories: (a: readonly AgentSummary[]) => string[];
|
|
783
|
+
/**
|
|
784
|
+
* All unique categories across live SYSTEM (builtin) agents. The system tab
|
|
785
|
+
* gets the same category filter every other tab has — its options just come
|
|
786
|
+
* from a different population.
|
|
787
|
+
*/
|
|
788
|
+
declare const selectAllSystemAgentCategories: (a: readonly AgentSummary[]) => string[];
|
|
789
|
+
/** All unique tags across live user agents, sorted alphabetically. */
|
|
790
|
+
declare const selectAllAgentTags: (a: readonly AgentSummary[]) => string[];
|
|
791
|
+
/** All unique tags across live SYSTEM (builtin) agents. */
|
|
792
|
+
declare const selectAllSystemAgentTags: (a: readonly AgentSummary[]) => string[];
|
|
793
|
+
/** Live user-type agents (excludes builtins). */
|
|
794
|
+
declare const selectUserTypeAgents: (a: readonly AgentSummary[]) => AgentSummary[];
|
|
795
|
+
/** Builtin/system agents only. For chat pickers and full catalogues. */
|
|
796
|
+
declare const selectBuiltinTypeAgents: (a: readonly AgentSummary[]) => AgentSummary[];
|
|
797
|
+
declare function sortFilteredAgents(filtered: AgentSummary[], consumer: AgentConsumerState): AgentSummary[];
|
|
798
|
+
/** User-type agents — mine / shared / all tabs with full consumer filters. */
|
|
799
|
+
declare function filterUserTypeAgents(agents: readonly AgentSummary[], consumer: AgentConsumerState): AgentSummary[];
|
|
800
|
+
/**
|
|
801
|
+
* Builtin/system agents (tab === "system").
|
|
802
|
+
*
|
|
803
|
+
* Gets the SAME filter surface every other tab has — search, favorites,
|
|
804
|
+
* category, tags, sort. Ownership/archive/access filters are meaningless here
|
|
805
|
+
* (a builtin is always active and belongs to the platform), so those are the
|
|
806
|
+
* only ones skipped. A picker that offers less on one tab than another is the
|
|
807
|
+
* exact half-built shape this list exists to prevent.
|
|
808
|
+
*/
|
|
809
|
+
declare function filterBuiltinTypeAgents(agents: readonly AgentSummary[], consumer: AgentConsumerState): AgentSummary[];
|
|
810
|
+
/** Factory: owned user-type agents with consumer filters applied (ignores tab). */
|
|
811
|
+
declare const makeSelectFilteredOwnedAgents: () => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
812
|
+
/** Factory: shared user-type agents with consumer filters applied (ignores tab). */
|
|
813
|
+
declare const makeSelectFilteredSharedAgents: () => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
814
|
+
/**
|
|
815
|
+
* Factory: filters and sorts agents for a consumer. User tabs (mine / shared /
|
|
816
|
+
* all) draw from user-type agents; the system tab draws from builtins.
|
|
817
|
+
*
|
|
818
|
+
* `includeSystemInAll` is the ADMIN reading of the "All" tab. For a normal
|
|
819
|
+
* user, system agents are a separate catalogue and "All" means "all of MY
|
|
820
|
+
* agents". For an admin surface, system agents ARE their agents — so "All"
|
|
821
|
+
* must be a single blended list, with each row still labelled (the `system`
|
|
822
|
+
* badge on `AgentRow`) so the two are never confused.
|
|
823
|
+
*/
|
|
824
|
+
declare const makeSelectFilteredAgents: (includeSystemInAll?: boolean) => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
825
|
+
/** Factory: filters and sorts builtin agents for the chat agent picker. */
|
|
826
|
+
declare const makeSelectFilteredBuiltinAgents: () => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
827
|
+
interface AgentListPage {
|
|
828
|
+
items: AgentSummary[];
|
|
829
|
+
hasMore: boolean;
|
|
830
|
+
totalAfterCards: number;
|
|
831
|
+
}
|
|
832
|
+
/** Factory: slices filtered owned agents into the "cards" hero section. */
|
|
833
|
+
declare const makeSelectOwnedAgentCards: (isMobile: boolean) => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
834
|
+
/** Factory: paginated list items for owned agents (everything after cards). */
|
|
835
|
+
declare const makeSelectOwnedAgentListItems: (isMobile: boolean) => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentListPage;
|
|
836
|
+
/** Factory: slices filtered shared agents into the "cards" hero section. */
|
|
837
|
+
declare const makeSelectSharedAgentCards: (isMobile: boolean) => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentSummary[];
|
|
838
|
+
/** Factory: paginated list items for shared agents (everything after cards). */
|
|
839
|
+
declare const makeSelectSharedAgentListItems: (isMobile: boolean) => (a: readonly AgentSummary[], b: AgentConsumerState) => AgentListPage;
|
|
840
|
+
/** Factory: total count of filtered agents for a consumer. */
|
|
841
|
+
declare const makeSelectFilteredAgentsCount: () => (a: readonly AgentSummary[], b: AgentConsumerState) => number;
|
|
842
|
+
/** Factory: total count of filtered builtin agents for a consumer. */
|
|
843
|
+
declare const makeSelectFilteredBuiltinAgentsCount: () => (a: readonly AgentSummary[], b: AgentConsumerState) => number;
|
|
844
|
+
/** Returns whether a consumer has any non-default filters active. */
|
|
845
|
+
declare function agentConsumerHasActiveFilters(consumer: AgentConsumerState, defaults: AgentConsumerState): boolean;
|
|
846
|
+
declare const selectTotalUserAgentsCount: (a: readonly AgentSummary[]) => number;
|
|
847
|
+
declare const selectTotalOwnedAgentsCount: (a: readonly AgentSummary[]) => number;
|
|
848
|
+
declare const selectTotalSharedAgentsCount: (a: readonly AgentSummary[]) => number;
|
|
849
|
+
declare const selectTotalBuiltinAgentsCount: (a: readonly AgentSummary[]) => number;
|
|
850
|
+
declare const selectTotalFavoriteAgentsCount: (a: readonly AgentSummary[]) => number;
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* catalog/global-state.ts — @ai-matrx/agents/catalog
|
|
854
|
+
*
|
|
855
|
+
* 🚨 MODULE-LEVEL MUTABLE STATE IS BANNED IN THIS PACKAGE. With dual ESM+CJS
|
|
856
|
+
* output and `splitting: false`, each loader graph instantiates its own copy
|
|
857
|
+
* of every module — a module-level variable would silently split the
|
|
858
|
+
* in-flight dedupe (so the "one RPC for ~20 mounting surfaces" collapse
|
|
859
|
+
* would become two), the freshness stamp, the catalog registry, and the
|
|
860
|
+
* default-row cache. Everything session-shared therefore lives on
|
|
861
|
+
* `globalThis` under a `Symbol.for` slot, exactly like
|
|
862
|
+
* `@ai-matrx/kit`'s confirm opener. Never "clean this up" into module locals.
|
|
863
|
+
*/
|
|
864
|
+
|
|
865
|
+
/** @internal Test-only: forget every session-shared value. */
|
|
866
|
+
declare function _resetCatalogGlobalState(): void;
|
|
867
|
+
|
|
868
|
+
export { AGENT_CARDS_LIMIT_DESKTOP, AGENT_CARDS_LIMIT_MOBILE, AGENT_LIST_ITEMS_PER_PAGE, AGENT_NONE_SENTINEL, AGENT_SEARCH_LIMIT, type AgentAccessFilter, type AgentAccessLevel, type AgentArchFilter, type AgentCatalog, type AgentCatalogAgentType, type AgentCatalogClient, type AgentCatalogConfig, AgentCatalogConfigError, type AgentCatalogErrorSink, type AgentCatalogIdentity, type AgentCatalogLabels, type AgentCatalogNavigate, type AgentCatalogNotifier, type AgentCatalogOpenPeek, AgentCatalogReadError, type AgentCatalogResolveHref, type AgentCatalogRpcCall, type AgentCatalogSchemaReport, type AgentCatalogState, type AgentCatalogStatus, type AgentCatalogStorage, type AgentCatalogTableQuery, type AgentCatalogTransport, type AgentConsumerPatch, type AgentConsumerState, type AgentFavFilter, type AgentId, type AgentListPage, type AgentSearchable, type AgentServerSearchResult, type AgentSortOption, type AgentSummary, type AgentTab, type AssertAgentCatalogSchemaOptions, DEFAULT_AGENT_CATALOG_LABELS, DEFAULT_AGENT_CONSUMER_STATE, type DefaultRowState, MandateDefaultRowError, type MandateResolutionVerdict, type PgErrorLike, type PgResultLike, type ResolveDefaultRowArgs, type ResolveDefaultRowOutcome, type ResolvedDefaultRow, _resetCatalogGlobalState, agentConsumerHasActiveFilters, agentListEmptyLabel, agentMatchesSearch, applyAgentSortComparator, asAgentId, assertAgentCatalogSchema, computeAgentSearchScore, createAgentCatalog, createMemoryStorage, defaultRowFromResolution, defaultStorage, detectDefaultRowDrift, filterBuiltinTypeAgents, filterUserTypeAgents, getRegisteredAgentCatalog, isMandateAgentId, makeSelectFilteredAgents, makeSelectFilteredAgentsCount, makeSelectFilteredBuiltinAgents, makeSelectFilteredBuiltinAgentsCount, makeSelectFilteredOwnedAgents, makeSelectFilteredSharedAgents, makeSelectOwnedAgentCards, makeSelectOwnedAgentListItems, makeSelectSharedAgentCards, makeSelectSharedAgentListItems, mandateAgentId, memoize1, memoize2, memoize3, parseMandateResolution, readAgentCatalogRows, readCachedDefaultRow, readSingleAgentRow, resolveDefaultRow, searchAgentsOnServer, selectAllAgentCategories, selectAllAgentTags, selectAllSystemAgentCategories, selectAllSystemAgentTags, selectBuiltinTypeAgents, selectTotalBuiltinAgentsCount, selectTotalFavoriteAgentsCount, selectTotalOwnedAgentsCount, selectTotalSharedAgentsCount, selectTotalUserAgentsCount, selectUserTypeAgents, shouldDefaultAgentListToPublicTab, sortFilteredAgents, toAgentSummary, writeAgentFavorite, writeCachedDefaultRow };
|