@ai-matrx/agents 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +194 -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 +857 -0
- package/dist/catalog/index.d.ts +857 -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 +808 -0
- package/dist/catalog/react/index.d.ts +808 -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,1344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// catalog/index.ts
|
|
21
|
+
var catalog_exports = {};
|
|
22
|
+
__export(catalog_exports, {
|
|
23
|
+
AGENT_CARDS_LIMIT_DESKTOP: () => AGENT_CARDS_LIMIT_DESKTOP,
|
|
24
|
+
AGENT_CARDS_LIMIT_MOBILE: () => AGENT_CARDS_LIMIT_MOBILE,
|
|
25
|
+
AGENT_LIST_ITEMS_PER_PAGE: () => AGENT_LIST_ITEMS_PER_PAGE,
|
|
26
|
+
AGENT_NONE_SENTINEL: () => AGENT_NONE_SENTINEL,
|
|
27
|
+
AGENT_SEARCH_LIMIT: () => AGENT_SEARCH_LIMIT,
|
|
28
|
+
AgentCatalogConfigError: () => AgentCatalogConfigError,
|
|
29
|
+
AgentCatalogReadError: () => AgentCatalogReadError,
|
|
30
|
+
DEFAULT_AGENT_CATALOG_LABELS: () => DEFAULT_AGENT_CATALOG_LABELS,
|
|
31
|
+
DEFAULT_AGENT_CONSUMER_STATE: () => DEFAULT_AGENT_CONSUMER_STATE,
|
|
32
|
+
MandateDefaultRowError: () => MandateDefaultRowError,
|
|
33
|
+
_resetCatalogGlobalState: () => _resetCatalogGlobalState,
|
|
34
|
+
agentConsumerHasActiveFilters: () => agentConsumerHasActiveFilters,
|
|
35
|
+
agentListEmptyLabel: () => agentListEmptyLabel,
|
|
36
|
+
agentMatchesSearch: () => agentMatchesSearch,
|
|
37
|
+
applyAgentSortComparator: () => applyAgentSortComparator,
|
|
38
|
+
asAgentId: () => asAgentId,
|
|
39
|
+
assertAgentCatalogSchema: () => assertAgentCatalogSchema,
|
|
40
|
+
computeAgentSearchScore: () => computeAgentSearchScore,
|
|
41
|
+
createAgentCatalog: () => createAgentCatalog,
|
|
42
|
+
createMemoryStorage: () => createMemoryStorage,
|
|
43
|
+
defaultRowFromResolution: () => defaultRowFromResolution,
|
|
44
|
+
defaultStorage: () => defaultStorage,
|
|
45
|
+
detectDefaultRowDrift: () => detectDefaultRowDrift,
|
|
46
|
+
filterBuiltinTypeAgents: () => filterBuiltinTypeAgents,
|
|
47
|
+
filterUserTypeAgents: () => filterUserTypeAgents,
|
|
48
|
+
getRegisteredAgentCatalog: () => getRegisteredAgentCatalog,
|
|
49
|
+
isMandateAgentId: () => isMandateAgentId,
|
|
50
|
+
makeSelectFilteredAgents: () => makeSelectFilteredAgents,
|
|
51
|
+
makeSelectFilteredAgentsCount: () => makeSelectFilteredAgentsCount,
|
|
52
|
+
makeSelectFilteredBuiltinAgents: () => makeSelectFilteredBuiltinAgents,
|
|
53
|
+
makeSelectFilteredBuiltinAgentsCount: () => makeSelectFilteredBuiltinAgentsCount,
|
|
54
|
+
makeSelectFilteredOwnedAgents: () => makeSelectFilteredOwnedAgents,
|
|
55
|
+
makeSelectFilteredSharedAgents: () => makeSelectFilteredSharedAgents,
|
|
56
|
+
makeSelectOwnedAgentCards: () => makeSelectOwnedAgentCards,
|
|
57
|
+
makeSelectOwnedAgentListItems: () => makeSelectOwnedAgentListItems,
|
|
58
|
+
makeSelectSharedAgentCards: () => makeSelectSharedAgentCards,
|
|
59
|
+
makeSelectSharedAgentListItems: () => makeSelectSharedAgentListItems,
|
|
60
|
+
mandateAgentId: () => mandateAgentId,
|
|
61
|
+
memoize1: () => memoize1,
|
|
62
|
+
memoize2: () => memoize2,
|
|
63
|
+
memoize3: () => memoize3,
|
|
64
|
+
parseMandateResolution: () => parseMandateResolution,
|
|
65
|
+
readAgentCatalogRows: () => readAgentCatalogRows,
|
|
66
|
+
readCachedDefaultRow: () => readCachedDefaultRow,
|
|
67
|
+
readSingleAgentRow: () => readSingleAgentRow,
|
|
68
|
+
resolveDefaultRow: () => resolveDefaultRow,
|
|
69
|
+
searchAgentsOnServer: () => searchAgentsOnServer,
|
|
70
|
+
selectAllAgentCategories: () => selectAllAgentCategories,
|
|
71
|
+
selectAllAgentTags: () => selectAllAgentTags,
|
|
72
|
+
selectAllSystemAgentCategories: () => selectAllSystemAgentCategories,
|
|
73
|
+
selectAllSystemAgentTags: () => selectAllSystemAgentTags,
|
|
74
|
+
selectBuiltinTypeAgents: () => selectBuiltinTypeAgents,
|
|
75
|
+
selectTotalBuiltinAgentsCount: () => selectTotalBuiltinAgentsCount,
|
|
76
|
+
selectTotalFavoriteAgentsCount: () => selectTotalFavoriteAgentsCount,
|
|
77
|
+
selectTotalOwnedAgentsCount: () => selectTotalOwnedAgentsCount,
|
|
78
|
+
selectTotalSharedAgentsCount: () => selectTotalSharedAgentsCount,
|
|
79
|
+
selectTotalUserAgentsCount: () => selectTotalUserAgentsCount,
|
|
80
|
+
selectUserTypeAgents: () => selectUserTypeAgents,
|
|
81
|
+
shouldDefaultAgentListToPublicTab: () => shouldDefaultAgentListToPublicTab,
|
|
82
|
+
sortFilteredAgents: () => sortFilteredAgents,
|
|
83
|
+
toAgentSummary: () => toAgentSummary,
|
|
84
|
+
writeAgentFavorite: () => writeAgentFavorite,
|
|
85
|
+
writeCachedDefaultRow: () => writeCachedDefaultRow
|
|
86
|
+
});
|
|
87
|
+
module.exports = __toCommonJS(catalog_exports);
|
|
88
|
+
|
|
89
|
+
// catalog/types.ts
|
|
90
|
+
function asAgentId(value) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
function mandateAgentId(mandateKey) {
|
|
94
|
+
return `mandate:${mandateKey}`;
|
|
95
|
+
}
|
|
96
|
+
function isMandateAgentId(id) {
|
|
97
|
+
return id.startsWith("mandate:");
|
|
98
|
+
}
|
|
99
|
+
var AGENT_NONE_SENTINEL = "__none__";
|
|
100
|
+
var DEFAULT_AGENT_CONSUMER_STATE = {
|
|
101
|
+
tab: "mine",
|
|
102
|
+
sortBy: "updated-desc",
|
|
103
|
+
searchTerm: "",
|
|
104
|
+
includedCats: [],
|
|
105
|
+
includedTags: [],
|
|
106
|
+
favFilter: "all",
|
|
107
|
+
archFilter: "active",
|
|
108
|
+
accessFilter: "any",
|
|
109
|
+
favoritesFirst: true,
|
|
110
|
+
listPage: 1,
|
|
111
|
+
sharedPage: 1,
|
|
112
|
+
serverMatchedIds: [],
|
|
113
|
+
isServerSearching: false,
|
|
114
|
+
deepSearch: false
|
|
115
|
+
};
|
|
116
|
+
var AgentCatalogConfigError = class extends Error {
|
|
117
|
+
name = "AgentCatalogConfigError";
|
|
118
|
+
/** Machine code, for a host that routes config failures. */
|
|
119
|
+
code;
|
|
120
|
+
/** What the host must do, in a sentence a person can act on. */
|
|
121
|
+
remedy;
|
|
122
|
+
constructor(args) {
|
|
123
|
+
super(`${args.message} \u2014 ${args.remedy}`);
|
|
124
|
+
this.code = args.code;
|
|
125
|
+
this.remedy = args.remedy;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// catalog/ports.ts
|
|
130
|
+
var DEFAULT_AGENT_CATALOG_LABELS = {
|
|
131
|
+
publicTab: "Public",
|
|
132
|
+
systemBadge: "system",
|
|
133
|
+
searchPlaceholder: "Search agents...",
|
|
134
|
+
currentAgentHeading: "Current agent",
|
|
135
|
+
emptyDefault: "No agents found",
|
|
136
|
+
emptyShared: "No shared agents found",
|
|
137
|
+
emptySystem: "No system agents found",
|
|
138
|
+
loading: "Loading...",
|
|
139
|
+
triggerFallback: "Agents",
|
|
140
|
+
triggerResolving: "Naming the agent\u2026",
|
|
141
|
+
triggerUnnameable: "An agent this list cannot name",
|
|
142
|
+
hoverHint: "Hover an agent to preview its details, or click to select."
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// catalog/data.ts
|
|
146
|
+
var import_db = require("@ai-matrx/data/db");
|
|
147
|
+
|
|
148
|
+
// catalog/rows.ts
|
|
149
|
+
function isRecord(value) {
|
|
150
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
151
|
+
}
|
|
152
|
+
function str(value) {
|
|
153
|
+
return typeof value === "string" ? value : null;
|
|
154
|
+
}
|
|
155
|
+
function bool(value) {
|
|
156
|
+
return value === true;
|
|
157
|
+
}
|
|
158
|
+
function boolOrNull(value) {
|
|
159
|
+
return typeof value === "boolean" ? value : null;
|
|
160
|
+
}
|
|
161
|
+
function stringArray(value) {
|
|
162
|
+
if (!Array.isArray(value)) return [];
|
|
163
|
+
return value.filter((v) => typeof v === "string");
|
|
164
|
+
}
|
|
165
|
+
function agentType(value) {
|
|
166
|
+
return value === "builtin" ? "builtin" : "user";
|
|
167
|
+
}
|
|
168
|
+
function toAgentSummary(raw) {
|
|
169
|
+
if (!isRecord(raw)) return null;
|
|
170
|
+
const id = str(raw["id"]);
|
|
171
|
+
if (!id) return null;
|
|
172
|
+
return {
|
|
173
|
+
id: asAgentId(id),
|
|
174
|
+
name: str(raw["name"]),
|
|
175
|
+
description: str(raw["description"]),
|
|
176
|
+
category: str(raw["category"]),
|
|
177
|
+
tags: stringArray(raw["tags"]),
|
|
178
|
+
agentType: agentType(raw["agent_type"]),
|
|
179
|
+
modelId: str(raw["model_id"]),
|
|
180
|
+
isActive: bool(raw["is_active"]),
|
|
181
|
+
isArchived: bool(raw["is_archived"]),
|
|
182
|
+
isFavorite: bool(raw["is_favorite"]),
|
|
183
|
+
createdBy: str(raw["created_by"]),
|
|
184
|
+
organizationId: str(raw["organization_id"]),
|
|
185
|
+
taskId: str(raw["task_id"]),
|
|
186
|
+
sourceAgentId: str(raw["source_agent_id"]),
|
|
187
|
+
createdAt: str(raw["created_at"]),
|
|
188
|
+
updatedAt: str(raw["updated_at"]),
|
|
189
|
+
isOwner: boolOrNull(raw["is_owner"]),
|
|
190
|
+
accessLevel: str(raw["access_level"]),
|
|
191
|
+
sharedByEmail: str(raw["shared_by_email"])
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// catalog/data.ts
|
|
196
|
+
var LIST_PAGE_SIZE = 1e3;
|
|
197
|
+
var AGENT_SEARCH_LIMIT = 50;
|
|
198
|
+
var AgentCatalogReadError = class extends Error {
|
|
199
|
+
name = "AgentCatalogReadError";
|
|
200
|
+
source;
|
|
201
|
+
constructor(source, detail) {
|
|
202
|
+
super(`${source}: ${detail}`);
|
|
203
|
+
this.source = source;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
function pgDetail(error) {
|
|
207
|
+
return error.code ? `${error.message} (${error.code})` : error.message;
|
|
208
|
+
}
|
|
209
|
+
async function readAgentCatalogRows(client) {
|
|
210
|
+
const raw = await (0, import_db.readAllRows)(
|
|
211
|
+
({ from, to }) => Promise.resolve(
|
|
212
|
+
client.rpc("agx_get_list_full", {}, { count: "exact" }).order("id", { ascending: true }).range(from, to)
|
|
213
|
+
).then((res) => ({
|
|
214
|
+
// `data` crosses a HOST-generated-type boundary, so it arrives as
|
|
215
|
+
// `unknown` and is narrowed here rather than asserted anywhere.
|
|
216
|
+
data: Array.isArray(res.data) ? res.data : null,
|
|
217
|
+
error: res.error,
|
|
218
|
+
count: res.count ?? null
|
|
219
|
+
})),
|
|
220
|
+
{ label: "agx_get_list_full", pageSize: LIST_PAGE_SIZE }
|
|
221
|
+
);
|
|
222
|
+
const rows = [];
|
|
223
|
+
let dropped = 0;
|
|
224
|
+
for (const item of raw) {
|
|
225
|
+
const summary = toAgentSummary(item);
|
|
226
|
+
if (summary) rows.push(summary);
|
|
227
|
+
else dropped += 1;
|
|
228
|
+
}
|
|
229
|
+
if (dropped > 0) {
|
|
230
|
+
throw new AgentCatalogReadError(
|
|
231
|
+
"agx_get_list_full",
|
|
232
|
+
`${dropped} row(s) came back without an id and were refused. A row that cannot be identified cannot be selected, so the catalogue is not trustworthy \u2014 check the RPC's return shape.`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return rows;
|
|
236
|
+
}
|
|
237
|
+
async function searchAgentsOnServer(client, args) {
|
|
238
|
+
const q = args.query.trim();
|
|
239
|
+
if (!q) return { ids: [], rows: [] };
|
|
240
|
+
const { data, error } = await client.rpc("agx_search", {
|
|
241
|
+
p_query: q,
|
|
242
|
+
p_deep: args.deep ?? false,
|
|
243
|
+
p_limit: args.limit ?? AGENT_SEARCH_LIMIT,
|
|
244
|
+
p_offset: 0
|
|
245
|
+
});
|
|
246
|
+
if (error) throw new AgentCatalogReadError("agx_search", pgDetail(error));
|
|
247
|
+
const rows = [];
|
|
248
|
+
if (Array.isArray(data)) {
|
|
249
|
+
for (const item of data) {
|
|
250
|
+
const summary = toAgentSummary(item);
|
|
251
|
+
if (summary) rows.push(summary);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return { ids: rows.map((r) => r.id), rows };
|
|
255
|
+
}
|
|
256
|
+
async function readSingleAgentRow(client, agentId) {
|
|
257
|
+
try {
|
|
258
|
+
const hit = await searchAgentsOnServer(client, {
|
|
259
|
+
query: agentId,
|
|
260
|
+
limit: 5
|
|
261
|
+
});
|
|
262
|
+
const exact = hit.rows.find((r) => r.id === agentId);
|
|
263
|
+
if (exact) return exact;
|
|
264
|
+
} catch {
|
|
265
|
+
}
|
|
266
|
+
const { data, error } = await client.rpc("agx_resolve_agent_address", {
|
|
267
|
+
p_ids: [agentId]
|
|
268
|
+
});
|
|
269
|
+
if (error) {
|
|
270
|
+
throw new AgentCatalogReadError(
|
|
271
|
+
"agx_resolve_agent_address",
|
|
272
|
+
pgDetail(error)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
if (!Array.isArray(data)) return null;
|
|
276
|
+
for (const item of data) {
|
|
277
|
+
if (typeof item !== "object" || item === null) continue;
|
|
278
|
+
const record = item;
|
|
279
|
+
if (record["agent_id"] !== agentId) continue;
|
|
280
|
+
const name = record["agent_name"];
|
|
281
|
+
return toAgentSummary({
|
|
282
|
+
id: agentId,
|
|
283
|
+
name: typeof name === "string" ? name : null,
|
|
284
|
+
agent_type: record["agent_type"],
|
|
285
|
+
is_active: true
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
async function writeAgentFavorite(client, agentId, isFavorite) {
|
|
291
|
+
const { error } = await client.schema("agent").from("definition").update({ is_favorite: isFavorite }).eq("id", agentId);
|
|
292
|
+
if (error) {
|
|
293
|
+
throw new AgentCatalogReadError(
|
|
294
|
+
"agent.definition.is_favorite",
|
|
295
|
+
pgDetail(error)
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// catalog/default-row.ts
|
|
301
|
+
var CACHE_PREFIX = "ai-matrx.agents.catalog.default-row:";
|
|
302
|
+
var MandateDefaultRowError = class extends Error {
|
|
303
|
+
name = "MandateDefaultRowError";
|
|
304
|
+
mandateKey;
|
|
305
|
+
remedy;
|
|
306
|
+
constructor(args) {
|
|
307
|
+
super(`${args.message} \u2014 ${args.remedy}`);
|
|
308
|
+
this.mandateKey = args.mandateKey;
|
|
309
|
+
this.remedy = args.remedy;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
function isRecord2(v) {
|
|
313
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
314
|
+
}
|
|
315
|
+
function parseMandateResolution(mandateKey, raw) {
|
|
316
|
+
if (!isRecord2(raw)) {
|
|
317
|
+
throw new MandateDefaultRowError({
|
|
318
|
+
mandateKey,
|
|
319
|
+
message: `mandate "${mandateKey}": the resolution endpoint did not return an object`,
|
|
320
|
+
remedy: "check that the transport points at the AI Matrx server and that GET /mandates/{key}/resolution is reachable"
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const agentId = raw["agent_id"];
|
|
324
|
+
const definitionAgentId = raw["definition_agent_id"];
|
|
325
|
+
const provenance = raw["provenance"];
|
|
326
|
+
const holderType = raw["holder_type"];
|
|
327
|
+
return {
|
|
328
|
+
mandateKey: typeof raw["mandate_key"] === "string" ? raw["mandate_key"] : mandateKey,
|
|
329
|
+
holderType: typeof holderType === "string" ? holderType : "agent",
|
|
330
|
+
agentId: typeof agentId === "string" ? agentId : null,
|
|
331
|
+
isVersion: raw["is_version"] === true,
|
|
332
|
+
definitionAgentId: typeof definitionAgentId === "string" ? definitionAgentId : null,
|
|
333
|
+
provenance: typeof provenance === "string" ? provenance : "system"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
async function askTheServer(transport, mandateKey) {
|
|
337
|
+
const path = `/mandates/${encodeURIComponent(mandateKey)}/resolution`;
|
|
338
|
+
const response = await transport.fetch(path, {
|
|
339
|
+
method: "GET",
|
|
340
|
+
headers: { Accept: "application/json" }
|
|
341
|
+
});
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
throw new MandateDefaultRowError({
|
|
344
|
+
mandateKey,
|
|
345
|
+
message: `mandate "${mandateKey}": the server refused to resolve it (HTTP ${response.status})`,
|
|
346
|
+
remedy: response.status === 404 ? "the mandate does not exist \u2014 check the key this picker was given" : "check the caller's session and organization context, then retry"
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return parseMandateResolution(mandateKey, await response.json());
|
|
350
|
+
}
|
|
351
|
+
function createMemoryStorage() {
|
|
352
|
+
const map = /* @__PURE__ */ new Map();
|
|
353
|
+
return {
|
|
354
|
+
getItem: (k) => map.get(k) ?? null,
|
|
355
|
+
setItem: (k, v) => {
|
|
356
|
+
map.set(k, v);
|
|
357
|
+
},
|
|
358
|
+
removeItem: (k) => {
|
|
359
|
+
map.delete(k);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function defaultStorage() {
|
|
364
|
+
try {
|
|
365
|
+
const ls = globalThis.localStorage;
|
|
366
|
+
if (ls) {
|
|
367
|
+
const probe = `${CACHE_PREFIX}__probe__`;
|
|
368
|
+
ls.setItem(probe, "1");
|
|
369
|
+
ls.removeItem(probe);
|
|
370
|
+
return ls;
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
return createMemoryStorage();
|
|
375
|
+
}
|
|
376
|
+
function readCachedDefaultRow(storage, mandateKey) {
|
|
377
|
+
try {
|
|
378
|
+
const raw = storage.getItem(CACHE_PREFIX + mandateKey);
|
|
379
|
+
if (!raw) return null;
|
|
380
|
+
const parsed = JSON.parse(raw);
|
|
381
|
+
if (!isRecord2(parsed)) return null;
|
|
382
|
+
const holderId = parsed["holderId"];
|
|
383
|
+
const holderName = parsed["holderName"];
|
|
384
|
+
if (typeof holderId !== "string" || typeof holderName !== "string") {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
const description = parsed["holderDescription"];
|
|
388
|
+
const provenance = parsed["provenance"];
|
|
389
|
+
const at = parsed["at"];
|
|
390
|
+
return {
|
|
391
|
+
mandateKey,
|
|
392
|
+
holderId,
|
|
393
|
+
holderName,
|
|
394
|
+
holderDescription: typeof description === "string" ? description : null,
|
|
395
|
+
provenance: typeof provenance === "string" ? provenance : "system",
|
|
396
|
+
at: typeof at === "number" ? at : 0
|
|
397
|
+
};
|
|
398
|
+
} catch {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function writeCachedDefaultRow(storage, resolved) {
|
|
403
|
+
try {
|
|
404
|
+
storage.setItem(CACHE_PREFIX + resolved.mandateKey, JSON.stringify(resolved));
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function defaultRowFromResolution(resolved) {
|
|
409
|
+
return {
|
|
410
|
+
id: mandateAgentId(resolved.mandateKey),
|
|
411
|
+
name: resolved.holderName,
|
|
412
|
+
description: resolved.holderDescription,
|
|
413
|
+
category: null,
|
|
414
|
+
tags: [],
|
|
415
|
+
agentType: "builtin",
|
|
416
|
+
modelId: null,
|
|
417
|
+
isActive: true,
|
|
418
|
+
isArchived: false,
|
|
419
|
+
isFavorite: false,
|
|
420
|
+
createdBy: null,
|
|
421
|
+
organizationId: null,
|
|
422
|
+
taskId: null,
|
|
423
|
+
sourceAgentId: resolved.holderId,
|
|
424
|
+
createdAt: null,
|
|
425
|
+
updatedAt: null,
|
|
426
|
+
isOwner: null,
|
|
427
|
+
accessLevel: null,
|
|
428
|
+
sharedByEmail: null,
|
|
429
|
+
mandateKey: resolved.mandateKey
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function detectDefaultRowDrift(cached, live) {
|
|
433
|
+
if (!cached) return null;
|
|
434
|
+
if (cached.holderId !== live.holderId) {
|
|
435
|
+
return `The default agent for "${live.mandateKey}" changed: this screen was showing "${cached.holderName}", and the platform now resolves it to "${live.holderName}". The list below is correct; anything that cached the old name is not.`;
|
|
436
|
+
}
|
|
437
|
+
if (cached.holderName !== live.holderName) {
|
|
438
|
+
return `The default agent for "${live.mandateKey}" was renamed: "${cached.holderName}" is now "${live.holderName}".`;
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
async function resolveDefaultRow(args) {
|
|
443
|
+
const { mandateKey, transport, client, storage, lookupRow } = args;
|
|
444
|
+
const cached = readCachedDefaultRow(storage, mandateKey);
|
|
445
|
+
const verdict = await askTheServer(transport, mandateKey);
|
|
446
|
+
if (verdict.holderType !== "agent") {
|
|
447
|
+
throw new MandateDefaultRowError({
|
|
448
|
+
mandateKey,
|
|
449
|
+
message: `mandate "${mandateKey}": the ${verdict.provenance} rung names a ${verdict.holderType} Holder, and an agent picker can only offer an agent`,
|
|
450
|
+
remedy: `rebind the ${verdict.provenance} rung to an agent, or drop defaultMandateKey from this picker`
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
const holderId = verdict.definitionAgentId ?? verdict.agentId;
|
|
454
|
+
if (!holderId) {
|
|
455
|
+
throw new MandateDefaultRowError({
|
|
456
|
+
mandateKey,
|
|
457
|
+
message: `mandate "${mandateKey}": the server resolved it without naming an agent`,
|
|
458
|
+
remedy: `bind the ${verdict.provenance} rung to an agent`
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
let holder = lookupRow(holderId);
|
|
462
|
+
if (!holder) {
|
|
463
|
+
holder = await readSingleAgentRow(client, holderId) ?? void 0;
|
|
464
|
+
}
|
|
465
|
+
if (!holder || !holder.name) {
|
|
466
|
+
throw new MandateDefaultRowError({
|
|
467
|
+
mandateKey,
|
|
468
|
+
message: `mandate "${mandateKey}": its Holder resolved, but nothing this caller can read could name that agent`,
|
|
469
|
+
remedy: "grant this user access to the Holder, or make it a platform agent \u2014 the picker will not print a placeholder name in its place"
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
const resolved = {
|
|
473
|
+
mandateKey,
|
|
474
|
+
holderId,
|
|
475
|
+
holderName: holder.name,
|
|
476
|
+
holderDescription: holder.description,
|
|
477
|
+
provenance: verdict.provenance,
|
|
478
|
+
at: Date.now()
|
|
479
|
+
};
|
|
480
|
+
const drift = detectDefaultRowDrift(cached, resolved);
|
|
481
|
+
writeCachedDefaultRow(storage, resolved);
|
|
482
|
+
return { resolved, row: defaultRowFromResolution(resolved), drift };
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// catalog/global-state.ts
|
|
486
|
+
var STATE_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.agents.catalog");
|
|
487
|
+
function getCatalogGlobalState() {
|
|
488
|
+
const holder = globalThis;
|
|
489
|
+
let state = holder[STATE_SLOT];
|
|
490
|
+
if (!state) {
|
|
491
|
+
state = {
|
|
492
|
+
catalogs: /* @__PURE__ */ new Map(),
|
|
493
|
+
listInFlight: /* @__PURE__ */ new Map(),
|
|
494
|
+
listFetchedAt: /* @__PURE__ */ new Map(),
|
|
495
|
+
defaultRows: /* @__PURE__ */ new Map()
|
|
496
|
+
};
|
|
497
|
+
holder[STATE_SLOT] = state;
|
|
498
|
+
}
|
|
499
|
+
return state;
|
|
500
|
+
}
|
|
501
|
+
function _resetCatalogGlobalState() {
|
|
502
|
+
const state = getCatalogGlobalState();
|
|
503
|
+
state.catalogs.clear();
|
|
504
|
+
state.listInFlight.clear();
|
|
505
|
+
state.listFetchedAt.clear();
|
|
506
|
+
state.defaultRows.clear();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// catalog/schema.ts
|
|
510
|
+
var BAD_UUID = "00000000-0000-0000-0000-000000000000";
|
|
511
|
+
var SELF_TEST_MISSING_RPC = "agx_this_function_does_not_exist_probe";
|
|
512
|
+
var DEMANDED_RPCS = {
|
|
513
|
+
agx_get_list_full: {},
|
|
514
|
+
agx_search: { p_query: "__probe__", p_deep: false, p_limit: 1, p_offset: 0 },
|
|
515
|
+
agx_resolve_agent_address: { p_ids: [BAD_UUID] }
|
|
516
|
+
};
|
|
517
|
+
function isMissingFunctionError(error) {
|
|
518
|
+
if (!error || typeof error !== "object") return false;
|
|
519
|
+
const code = error.code;
|
|
520
|
+
return code === "PGRST202" || code === "42883";
|
|
521
|
+
}
|
|
522
|
+
async function assertAgentCatalogSchema(client, options = {}) {
|
|
523
|
+
const {
|
|
524
|
+
selfTest = false,
|
|
525
|
+
throwOnViolation = true,
|
|
526
|
+
probeWrite = true
|
|
527
|
+
} = options;
|
|
528
|
+
const names = Object.keys(DEMANDED_RPCS);
|
|
529
|
+
if (selfTest) names.push(SELF_TEST_MISSING_RPC);
|
|
530
|
+
const missing = [];
|
|
531
|
+
const unreachable = [];
|
|
532
|
+
const answered = [];
|
|
533
|
+
for (const fn of names) {
|
|
534
|
+
const args = DEMANDED_RPCS[fn] ?? {};
|
|
535
|
+
try {
|
|
536
|
+
const { error } = await client.rpc(fn, args);
|
|
537
|
+
if (error == null) answered.push(fn);
|
|
538
|
+
else if (isMissingFunctionError(error)) missing.push(fn);
|
|
539
|
+
else answered.push(fn);
|
|
540
|
+
} catch (e) {
|
|
541
|
+
unreachable.push({ fn, error: e });
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (selfTest) {
|
|
545
|
+
const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);
|
|
546
|
+
const idx = missing.indexOf(SELF_TEST_MISSING_RPC);
|
|
547
|
+
if (idx >= 0) missing.splice(idx, 1);
|
|
548
|
+
const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);
|
|
549
|
+
if (answeredIdx >= 0) answered.splice(answeredIdx, 1);
|
|
550
|
+
if (!selfTestMissing) {
|
|
551
|
+
throw new Error(
|
|
552
|
+
`assertAgentCatalogSchema self-test FAILED: the fabricated function "${SELF_TEST_MISSING_RPC}" did not come back as missing. This probe cannot currently fail, so its green result proves nothing \u2014 the client is swallowing or faking errors.`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
let favoriteWritable = null;
|
|
557
|
+
if (probeWrite) {
|
|
558
|
+
try {
|
|
559
|
+
const { error } = await client.schema("agent").from("definition").update({ is_favorite: false }).eq("id", BAD_UUID);
|
|
560
|
+
favoriteWritable = !isPermissionRefusal(error);
|
|
561
|
+
} catch (e) {
|
|
562
|
+
unreachable.push({ fn: "agent.definition.is_favorite", error: e });
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (unreachable.length > 0) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`assertAgentCatalogSchema could not complete: ${unreachable.length} probe call(s) failed to reach the database (${unreachable.map((u) => u.fn).join(", ")}). This is NOT a schema verdict \u2014 fix connectivity and re-run.`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
const ok = missing.length === 0 && favoriteWritable !== false;
|
|
571
|
+
const report = {
|
|
572
|
+
ok,
|
|
573
|
+
missing,
|
|
574
|
+
unreachable,
|
|
575
|
+
answered,
|
|
576
|
+
favoriteWritable
|
|
577
|
+
};
|
|
578
|
+
if (!ok && throwOnViolation) {
|
|
579
|
+
const parts = [];
|
|
580
|
+
if (missing.length > 0) {
|
|
581
|
+
parts.push(
|
|
582
|
+
`cannot answer ${missing.length} demanded function(s): ${missing.join(", ")}`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
if (favoriteWritable === false) {
|
|
586
|
+
parts.push("refuses a write to agent.definition.is_favorite");
|
|
587
|
+
}
|
|
588
|
+
throw new Error(
|
|
589
|
+
`DEMANDED SCHEMA VIOLATION: the database this client points at ${parts.join("; and ")}. @ai-matrx/agents/catalog cannot render a correct picker against it \u2014 point the client at Matrx Main, or apply the agx_* migrations.`
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
return report;
|
|
593
|
+
}
|
|
594
|
+
function isPermissionRefusal(error) {
|
|
595
|
+
if (!error) return false;
|
|
596
|
+
const code = error.code;
|
|
597
|
+
return code === "42501" || code === "42P01" || code === "PGRST205";
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// catalog/store.ts
|
|
601
|
+
var LIST_TTL_MS = 15 * 60 * 1e3;
|
|
602
|
+
var LIST_STALE_MS = 4 * 60 * 60 * 1e3;
|
|
603
|
+
function createDefaultErrorSink() {
|
|
604
|
+
let announced = false;
|
|
605
|
+
return (event) => {
|
|
606
|
+
if (!announced) {
|
|
607
|
+
announced = true;
|
|
608
|
+
console.error(
|
|
609
|
+
"[@ai-matrx/agents/catalog] no errorSink is bound, so failures are only reaching the console. Pass `errorSink` to createAgentCatalog to route them into your diagnostics surface."
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
console.error(`[@ai-matrx/agents/catalog] ${event.code}: ${event.message}`, {
|
|
613
|
+
...event.context ?? {}
|
|
614
|
+
});
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
function errorMessage(e) {
|
|
618
|
+
return e instanceof Error ? e.message : String(e);
|
|
619
|
+
}
|
|
620
|
+
function createAgentCatalog(config) {
|
|
621
|
+
if (!config || typeof config !== "object") {
|
|
622
|
+
throw new AgentCatalogConfigError({
|
|
623
|
+
code: "missing_config",
|
|
624
|
+
message: "createAgentCatalog was called without a config object",
|
|
625
|
+
remedy: "pass { client, identity }"
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (!config.client || typeof config.client.rpc !== "function") {
|
|
629
|
+
throw new AgentCatalogConfigError({
|
|
630
|
+
code: "missing_client",
|
|
631
|
+
message: "createAgentCatalog needs a Supabase client \u2014 it IS the catalogue read",
|
|
632
|
+
remedy: "pass `client` (a supabase-js client, or anything with rpc() and schema().from())"
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
if (typeof config.client.schema !== "function") {
|
|
636
|
+
throw new AgentCatalogConfigError({
|
|
637
|
+
code: "client_cannot_write",
|
|
638
|
+
message: "the client passed to createAgentCatalog has no schema() \u2014 the favorite write has nowhere to go",
|
|
639
|
+
remedy: "pass a full supabase-js client"
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (!config.identity || typeof config.identity.requireUserId !== "function") {
|
|
643
|
+
throw new AgentCatalogConfigError({
|
|
644
|
+
code: "missing_identity",
|
|
645
|
+
message: "createAgentCatalog needs to know who is asking",
|
|
646
|
+
remedy: "pass `identity: { requireUserId() }` \u2014 never a silent anonymous read"
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
const catalogId = config.catalogId ?? "default";
|
|
650
|
+
const client = config.client;
|
|
651
|
+
const identity = config.identity;
|
|
652
|
+
const errorSink = config.errorSink ?? createDefaultErrorSink();
|
|
653
|
+
const notifier = config.notifier;
|
|
654
|
+
const storage = config.storage ?? defaultStorage();
|
|
655
|
+
const transport = config.transport;
|
|
656
|
+
const labels = {
|
|
657
|
+
...DEFAULT_AGENT_CATALOG_LABELS,
|
|
658
|
+
...config.labels ?? {}
|
|
659
|
+
};
|
|
660
|
+
const globalState = getCatalogGlobalState();
|
|
661
|
+
if (globalState.catalogs.has(catalogId)) {
|
|
662
|
+
errorSink({
|
|
663
|
+
code: "catalog_replaced",
|
|
664
|
+
message: `a second agent catalog was created under id "${catalogId}" and has REPLACED the first. Two catalogs with one id share a freshness stamp and an in-flight promise; give each one its own \`catalogId\`.`
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
let state = {
|
|
668
|
+
rows: [],
|
|
669
|
+
byId: {},
|
|
670
|
+
status: "idle",
|
|
671
|
+
error: null,
|
|
672
|
+
consumers: {},
|
|
673
|
+
defaultRows: {}
|
|
674
|
+
};
|
|
675
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
676
|
+
function publish(next) {
|
|
677
|
+
state = next;
|
|
678
|
+
for (const listener of listeners) listener();
|
|
679
|
+
}
|
|
680
|
+
function mergeRows(incoming) {
|
|
681
|
+
if (incoming.length === 0) return;
|
|
682
|
+
const byId = { ...state.byId };
|
|
683
|
+
for (const row of incoming) byId[row.id] = row;
|
|
684
|
+
publish({ ...state, byId, rows: Object.values(byId) });
|
|
685
|
+
}
|
|
686
|
+
function replaceRows(incoming) {
|
|
687
|
+
const byId = {};
|
|
688
|
+
for (const row of incoming) byId[row.id] = row;
|
|
689
|
+
publish({ ...state, byId, rows: Object.values(byId) });
|
|
690
|
+
}
|
|
691
|
+
let anonymousReported = false;
|
|
692
|
+
function getUserIdOrNull() {
|
|
693
|
+
try {
|
|
694
|
+
return identity.requireUserId();
|
|
695
|
+
} catch (e) {
|
|
696
|
+
if (!anonymousReported) {
|
|
697
|
+
anonymousReported = true;
|
|
698
|
+
errorSink({
|
|
699
|
+
code: "identity_unavailable",
|
|
700
|
+
message: "identity.requireUserId() threw, so the picker is treating this session as signed out and opening on the public catalogue. Favoriting is unavailable until a session exists.",
|
|
701
|
+
context: { detail: errorMessage(e) }
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function isFresh() {
|
|
708
|
+
const at = globalState.listFetchedAt.get(catalogId);
|
|
709
|
+
if (at === void 0) return false;
|
|
710
|
+
return Date.now() - at < LIST_TTL_MS;
|
|
711
|
+
}
|
|
712
|
+
function isStale() {
|
|
713
|
+
const at = globalState.listFetchedAt.get(catalogId);
|
|
714
|
+
if (at === void 0) return true;
|
|
715
|
+
return Date.now() - at > LIST_STALE_MS;
|
|
716
|
+
}
|
|
717
|
+
async function load() {
|
|
718
|
+
publish({ ...state, status: "loading", error: null });
|
|
719
|
+
try {
|
|
720
|
+
const rows = await readAgentCatalogRows(client);
|
|
721
|
+
replaceRows(rows);
|
|
722
|
+
publish({ ...state, status: "succeeded", error: null });
|
|
723
|
+
globalState.listFetchedAt.set(catalogId, Date.now());
|
|
724
|
+
} catch (e) {
|
|
725
|
+
const message = errorMessage(e);
|
|
726
|
+
publish({ ...state, status: "failed", error: message });
|
|
727
|
+
errorSink({
|
|
728
|
+
code: "list_read_failed",
|
|
729
|
+
message: `the agent catalogue could not be read: ${message}`,
|
|
730
|
+
context: { catalogId }
|
|
731
|
+
});
|
|
732
|
+
throw e;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
async function ensureLoaded(options) {
|
|
736
|
+
const force = options?.force ?? false;
|
|
737
|
+
if (!force && isFresh()) return;
|
|
738
|
+
const existing = globalState.listInFlight.get(catalogId);
|
|
739
|
+
if (existing) return existing;
|
|
740
|
+
const run = load().finally(() => {
|
|
741
|
+
if (globalState.listInFlight.get(catalogId) === run) {
|
|
742
|
+
globalState.listInFlight.delete(catalogId);
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
globalState.listInFlight.set(catalogId, run);
|
|
746
|
+
return run;
|
|
747
|
+
}
|
|
748
|
+
function getConsumer(consumerId) {
|
|
749
|
+
return state.consumers[consumerId] ?? DEFAULT_AGENT_CONSUMER_STATE;
|
|
750
|
+
}
|
|
751
|
+
function writeConsumer(consumerId, next) {
|
|
752
|
+
publish({
|
|
753
|
+
...state,
|
|
754
|
+
consumers: { ...state.consumers, [consumerId]: next }
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
function registerConsumer(consumerId, initial) {
|
|
758
|
+
if (state.consumers[consumerId]) return;
|
|
759
|
+
writeConsumer(consumerId, {
|
|
760
|
+
...DEFAULT_AGENT_CONSUMER_STATE,
|
|
761
|
+
...initial ?? {}
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
function unregisterConsumer(consumerId) {
|
|
765
|
+
if (!state.consumers[consumerId]) return;
|
|
766
|
+
const consumers = { ...state.consumers };
|
|
767
|
+
delete consumers[consumerId];
|
|
768
|
+
publish({ ...state, consumers });
|
|
769
|
+
}
|
|
770
|
+
function setConsumerFilter(consumerId, patch) {
|
|
771
|
+
const current = state.consumers[consumerId] ?? {
|
|
772
|
+
...DEFAULT_AGENT_CONSUMER_STATE
|
|
773
|
+
};
|
|
774
|
+
writeConsumer(consumerId, {
|
|
775
|
+
...current,
|
|
776
|
+
...patch,
|
|
777
|
+
listPage: 1,
|
|
778
|
+
sharedPage: 1
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
function setConsumerPage(consumerId, which, page) {
|
|
782
|
+
const current = state.consumers[consumerId];
|
|
783
|
+
if (!current) return;
|
|
784
|
+
writeConsumer(
|
|
785
|
+
consumerId,
|
|
786
|
+
which === "list" ? { ...current, listPage: page } : { ...current, sharedPage: page }
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
function setConsumerServerSearch(consumerId, args) {
|
|
790
|
+
const current = state.consumers[consumerId] ?? {
|
|
791
|
+
...DEFAULT_AGENT_CONSUMER_STATE
|
|
792
|
+
};
|
|
793
|
+
const next = { ...current };
|
|
794
|
+
if (args.matchedIds !== void 0) next.serverMatchedIds = args.matchedIds;
|
|
795
|
+
if (args.isSearching !== void 0) next.isServerSearching = args.isSearching;
|
|
796
|
+
if (next.serverMatchedIds === current.serverMatchedIds && next.isServerSearching === current.isServerSearching) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
writeConsumer(consumerId, next);
|
|
800
|
+
}
|
|
801
|
+
function resetConsumerFilters(consumerId) {
|
|
802
|
+
if (!state.consumers[consumerId]) return;
|
|
803
|
+
writeConsumer(consumerId, { ...DEFAULT_AGENT_CONSUMER_STATE });
|
|
804
|
+
}
|
|
805
|
+
async function searchServer(query, deep = false) {
|
|
806
|
+
const result = await searchAgentsOnServer(client, { query, deep });
|
|
807
|
+
mergeRows(result.rows);
|
|
808
|
+
return result.ids;
|
|
809
|
+
}
|
|
810
|
+
async function setFavorite(agentId, isFavorite) {
|
|
811
|
+
const existing = state.byId[agentId];
|
|
812
|
+
if (!existing) {
|
|
813
|
+
errorSink({
|
|
814
|
+
code: "favorite_unknown_agent",
|
|
815
|
+
message: `cannot favorite ${agentId}: it is not in this catalogue`
|
|
816
|
+
});
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
mergeRows([{ ...existing, isFavorite }]);
|
|
820
|
+
try {
|
|
821
|
+
await writeAgentFavorite(client, agentId, isFavorite);
|
|
822
|
+
} catch (e) {
|
|
823
|
+
mergeRows([existing]);
|
|
824
|
+
errorSink({
|
|
825
|
+
code: "favorite_write_failed",
|
|
826
|
+
message: `the favorite could not be saved: ${errorMessage(e)}`,
|
|
827
|
+
context: { agentId, isFavorite }
|
|
828
|
+
});
|
|
829
|
+
notifier?.({
|
|
830
|
+
level: "error",
|
|
831
|
+
title: "Favorite not saved",
|
|
832
|
+
message: "The star was put back because the change could not be saved. Check your connection and try again."
|
|
833
|
+
});
|
|
834
|
+
throw e;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function writeDefaultRow(mandateKey, next) {
|
|
838
|
+
publish({
|
|
839
|
+
...state,
|
|
840
|
+
defaultRows: { ...state.defaultRows, [mandateKey]: next }
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
const defaultRowsInFlight = /* @__PURE__ */ new Set();
|
|
844
|
+
function ensureDefaultRow(mandateKey) {
|
|
845
|
+
if (!mandateKey) return;
|
|
846
|
+
if (state.defaultRows[mandateKey] || defaultRowsInFlight.has(mandateKey)) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (!transport) {
|
|
850
|
+
throw new AgentCatalogConfigError({
|
|
851
|
+
code: "missing_transport",
|
|
852
|
+
message: `a picker asked for the default row of mandate "${mandateKey}", but this catalog has no transport`,
|
|
853
|
+
remedy: "pass `transport` (createMatrxTransport from @ai-matrx/agents/matrx) to createAgentCatalog \u2014 clients never walk the mandate ladder themselves, they ask the server"
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
defaultRowsInFlight.add(mandateKey);
|
|
857
|
+
writeDefaultRow(mandateKey, {
|
|
858
|
+
mandateKey,
|
|
859
|
+
row: null,
|
|
860
|
+
resolved: null,
|
|
861
|
+
loading: true,
|
|
862
|
+
drift: null,
|
|
863
|
+
error: null
|
|
864
|
+
});
|
|
865
|
+
void (async () => {
|
|
866
|
+
try {
|
|
867
|
+
const outcome = await resolveDefaultRow({
|
|
868
|
+
mandateKey,
|
|
869
|
+
transport,
|
|
870
|
+
client,
|
|
871
|
+
storage,
|
|
872
|
+
errorSink,
|
|
873
|
+
lookupRow: (id) => state.byId[id]
|
|
874
|
+
});
|
|
875
|
+
getCatalogGlobalState().defaultRows.set(
|
|
876
|
+
`${catalogId}::${mandateKey}`,
|
|
877
|
+
outcome.resolved
|
|
878
|
+
);
|
|
879
|
+
writeDefaultRow(mandateKey, {
|
|
880
|
+
mandateKey,
|
|
881
|
+
row: outcome.row,
|
|
882
|
+
resolved: outcome.resolved,
|
|
883
|
+
loading: false,
|
|
884
|
+
drift: outcome.drift,
|
|
885
|
+
error: null
|
|
886
|
+
});
|
|
887
|
+
if (outcome.drift) {
|
|
888
|
+
errorSink({
|
|
889
|
+
code: "default_row_drift",
|
|
890
|
+
message: outcome.drift,
|
|
891
|
+
context: { mandateKey, holderId: outcome.resolved.holderId }
|
|
892
|
+
});
|
|
893
|
+
notifier?.({
|
|
894
|
+
level: "warning",
|
|
895
|
+
title: "The default agent changed",
|
|
896
|
+
message: outcome.drift
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
} catch (e) {
|
|
900
|
+
const message = e instanceof MandateDefaultRowError ? e.message : errorMessage(e);
|
|
901
|
+
writeDefaultRow(mandateKey, {
|
|
902
|
+
mandateKey,
|
|
903
|
+
row: null,
|
|
904
|
+
resolved: null,
|
|
905
|
+
loading: false,
|
|
906
|
+
drift: null,
|
|
907
|
+
error: message
|
|
908
|
+
});
|
|
909
|
+
errorSink({
|
|
910
|
+
code: "default_row_unresolved",
|
|
911
|
+
message,
|
|
912
|
+
context: { mandateKey }
|
|
913
|
+
});
|
|
914
|
+
} finally {
|
|
915
|
+
defaultRowsInFlight.delete(mandateKey);
|
|
916
|
+
}
|
|
917
|
+
})();
|
|
918
|
+
}
|
|
919
|
+
function getDefaultRow(mandateKey) {
|
|
920
|
+
return state.defaultRows[mandateKey];
|
|
921
|
+
}
|
|
922
|
+
function dismissDefaultRowDrift(mandateKey) {
|
|
923
|
+
const current = state.defaultRows[mandateKey];
|
|
924
|
+
if (!current || !current.drift) return;
|
|
925
|
+
writeDefaultRow(mandateKey, { ...current, drift: null });
|
|
926
|
+
}
|
|
927
|
+
const catalog = {
|
|
928
|
+
catalogId,
|
|
929
|
+
labels,
|
|
930
|
+
errorSink,
|
|
931
|
+
notifier,
|
|
932
|
+
canResolveMandates: transport !== void 0,
|
|
933
|
+
getState: () => state,
|
|
934
|
+
subscribe: (listener) => {
|
|
935
|
+
listeners.add(listener);
|
|
936
|
+
return () => {
|
|
937
|
+
listeners.delete(listener);
|
|
938
|
+
};
|
|
939
|
+
},
|
|
940
|
+
getAgent: (agentId) => state.byId[agentId],
|
|
941
|
+
getUserIdOrNull,
|
|
942
|
+
ensureLoaded,
|
|
943
|
+
isFresh,
|
|
944
|
+
isStale,
|
|
945
|
+
getConsumer,
|
|
946
|
+
registerConsumer,
|
|
947
|
+
unregisterConsumer,
|
|
948
|
+
setConsumerFilter,
|
|
949
|
+
setConsumerPage,
|
|
950
|
+
setConsumerServerSearch,
|
|
951
|
+
resetConsumerFilters,
|
|
952
|
+
searchServer,
|
|
953
|
+
setFavorite,
|
|
954
|
+
ensureDefaultRow,
|
|
955
|
+
getDefaultRow,
|
|
956
|
+
dismissDefaultRowDrift,
|
|
957
|
+
assertSchema: (options) => assertAgentCatalogSchema(client, options)
|
|
958
|
+
};
|
|
959
|
+
globalState.catalogs.set(catalogId, catalog);
|
|
960
|
+
return catalog;
|
|
961
|
+
}
|
|
962
|
+
function getRegisteredAgentCatalog(catalogId = "default") {
|
|
963
|
+
const found = getCatalogGlobalState().catalogs.get(catalogId);
|
|
964
|
+
return found;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// catalog/labels.ts
|
|
968
|
+
function agentListEmptyLabel(tab, labels) {
|
|
969
|
+
switch (tab) {
|
|
970
|
+
case "system":
|
|
971
|
+
return labels.emptySystem;
|
|
972
|
+
case "shared":
|
|
973
|
+
return labels.emptyShared;
|
|
974
|
+
default:
|
|
975
|
+
return labels.emptyDefault;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function shouldDefaultAgentListToPublicTab(args) {
|
|
979
|
+
if (!args.userId) return true;
|
|
980
|
+
if (!args.agentsLoaded) return false;
|
|
981
|
+
return args.ownedCount === 0;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// catalog/score.ts
|
|
985
|
+
function computeAgentSearchScore(agent, query) {
|
|
986
|
+
const q = query.trim().toLowerCase();
|
|
987
|
+
if (!q) return 0;
|
|
988
|
+
let score = 0;
|
|
989
|
+
const name = (agent.name ?? "").toLowerCase();
|
|
990
|
+
const desc = (agent.description ?? "").toLowerCase();
|
|
991
|
+
if (name === q) score += 1e4;
|
|
992
|
+
else if (name.startsWith(q)) score += 5e3;
|
|
993
|
+
else if (matchesWholeWord(name, q)) score += 3e3;
|
|
994
|
+
else if (name.includes(q)) score += 2e3;
|
|
995
|
+
if (desc === q) score += 1e3;
|
|
996
|
+
else if (desc.includes(q)) score += 500;
|
|
997
|
+
if (agent.category?.toLowerCase().includes(q)) score += 300;
|
|
998
|
+
if (agent.tags?.some((t) => t.toLowerCase().includes(q))) score += 300;
|
|
999
|
+
if (agent.modelId?.toLowerCase().includes(q)) score += 100;
|
|
1000
|
+
if (agent.agentType?.toLowerCase().includes(q)) score += 100;
|
|
1001
|
+
if (agent.outputFormat?.toLowerCase().includes(q)) score += 100;
|
|
1002
|
+
const id = agent.id.toLowerCase();
|
|
1003
|
+
if (id === q) score += 1e5;
|
|
1004
|
+
else if (id.includes(q)) score += 5e3;
|
|
1005
|
+
if (agent.sharedByEmail?.toLowerCase().includes(q)) score += 200;
|
|
1006
|
+
if (score === 0 && q.includes(" ")) {
|
|
1007
|
+
const terms = q.split(/\s+/).filter(Boolean);
|
|
1008
|
+
let hits = 0;
|
|
1009
|
+
let termScore = 0;
|
|
1010
|
+
for (const term of terms) {
|
|
1011
|
+
const inName = name.includes(term);
|
|
1012
|
+
const matched = inName || desc.includes(term) || (agent.category?.toLowerCase().includes(term) ?? false) || (agent.tags?.some((t) => t.toLowerCase().includes(term)) ?? false);
|
|
1013
|
+
if (matched) {
|
|
1014
|
+
hits += 1;
|
|
1015
|
+
termScore += inName ? 400 : 100;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (hits === terms.length) score += termScore;
|
|
1019
|
+
}
|
|
1020
|
+
return score;
|
|
1021
|
+
}
|
|
1022
|
+
function matchesWholeWord(haystack, q) {
|
|
1023
|
+
const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1024
|
+
return new RegExp(`\\b${escaped}\\b`).test(haystack);
|
|
1025
|
+
}
|
|
1026
|
+
function agentMatchesSearch(agent, query) {
|
|
1027
|
+
return computeAgentSearchScore(agent, query) > 0;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// catalog/selectors.ts
|
|
1031
|
+
var AGENT_CARDS_LIMIT_DESKTOP = 8;
|
|
1032
|
+
var AGENT_CARDS_LIMIT_MOBILE = 4;
|
|
1033
|
+
var AGENT_LIST_ITEMS_PER_PAGE = 20;
|
|
1034
|
+
function memoize1(fn) {
|
|
1035
|
+
let lastA;
|
|
1036
|
+
let last;
|
|
1037
|
+
let has = false;
|
|
1038
|
+
return (a) => {
|
|
1039
|
+
if (!has || lastA !== a) {
|
|
1040
|
+
last = fn(a);
|
|
1041
|
+
lastA = a;
|
|
1042
|
+
has = true;
|
|
1043
|
+
}
|
|
1044
|
+
return last;
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function memoize2(fn) {
|
|
1048
|
+
let lastA;
|
|
1049
|
+
let lastB;
|
|
1050
|
+
let last;
|
|
1051
|
+
let has = false;
|
|
1052
|
+
return (a, b) => {
|
|
1053
|
+
if (!has || lastA !== a || lastB !== b) {
|
|
1054
|
+
last = fn(a, b);
|
|
1055
|
+
lastA = a;
|
|
1056
|
+
lastB = b;
|
|
1057
|
+
has = true;
|
|
1058
|
+
}
|
|
1059
|
+
return last;
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function memoize3(fn) {
|
|
1063
|
+
let lastA;
|
|
1064
|
+
let lastB;
|
|
1065
|
+
let lastC;
|
|
1066
|
+
let last;
|
|
1067
|
+
let has = false;
|
|
1068
|
+
return (a, b, c) => {
|
|
1069
|
+
if (!has || lastA !== a || lastB !== b || lastC !== c) {
|
|
1070
|
+
last = fn(a, b, c);
|
|
1071
|
+
lastA = a;
|
|
1072
|
+
lastB = b;
|
|
1073
|
+
lastC = c;
|
|
1074
|
+
has = true;
|
|
1075
|
+
}
|
|
1076
|
+
return last;
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function applyAgentSortComparator(a, b, sortBy) {
|
|
1080
|
+
switch (sortBy) {
|
|
1081
|
+
case "name-asc":
|
|
1082
|
+
return (a.name ?? "").localeCompare(b.name ?? "");
|
|
1083
|
+
case "name-desc":
|
|
1084
|
+
return (b.name ?? "").localeCompare(a.name ?? "");
|
|
1085
|
+
case "created-desc":
|
|
1086
|
+
return +new Date(b.createdAt ?? 0) - +new Date(a.createdAt ?? 0);
|
|
1087
|
+
case "category-asc":
|
|
1088
|
+
return (a.category ?? "").localeCompare(b.category ?? "");
|
|
1089
|
+
case "updated-desc":
|
|
1090
|
+
default:
|
|
1091
|
+
return +new Date(b.updatedAt ?? 0) - +new Date(a.updatedAt ?? 0);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
var selectAllAgentCategories = memoize1(
|
|
1095
|
+
(agents) => {
|
|
1096
|
+
const cats = /* @__PURE__ */ new Set();
|
|
1097
|
+
for (const a of agents) {
|
|
1098
|
+
if (a.agentType === "user" && a.category) cats.add(a.category);
|
|
1099
|
+
}
|
|
1100
|
+
return Array.from(cats).sort();
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
var selectAllSystemAgentCategories = memoize1(
|
|
1104
|
+
(agents) => {
|
|
1105
|
+
const cats = /* @__PURE__ */ new Set();
|
|
1106
|
+
for (const a of agents) {
|
|
1107
|
+
if (a.agentType === "builtin" && a.category) cats.add(a.category);
|
|
1108
|
+
}
|
|
1109
|
+
return Array.from(cats).sort();
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
var selectAllAgentTags = memoize1(
|
|
1113
|
+
(agents) => {
|
|
1114
|
+
const tags = /* @__PURE__ */ new Set();
|
|
1115
|
+
for (const a of agents) {
|
|
1116
|
+
if (a.agentType === "user") a.tags?.forEach((t) => tags.add(t));
|
|
1117
|
+
}
|
|
1118
|
+
return Array.from(tags).sort();
|
|
1119
|
+
}
|
|
1120
|
+
);
|
|
1121
|
+
var selectAllSystemAgentTags = memoize1(
|
|
1122
|
+
(agents) => {
|
|
1123
|
+
const tags = /* @__PURE__ */ new Set();
|
|
1124
|
+
for (const a of agents) {
|
|
1125
|
+
if (a.agentType === "builtin") a.tags?.forEach((t) => tags.add(t));
|
|
1126
|
+
}
|
|
1127
|
+
return Array.from(tags).sort();
|
|
1128
|
+
}
|
|
1129
|
+
);
|
|
1130
|
+
var selectUserTypeAgents = memoize1(
|
|
1131
|
+
(agents) => agents.filter((a) => a.agentType === "user")
|
|
1132
|
+
);
|
|
1133
|
+
var selectBuiltinTypeAgents = memoize1(
|
|
1134
|
+
(agents) => agents.filter((a) => a.agentType === "builtin")
|
|
1135
|
+
);
|
|
1136
|
+
function sortFilteredAgents(filtered, consumer) {
|
|
1137
|
+
const { searchTerm, sortBy, favFilter, favoritesFirst } = consumer;
|
|
1138
|
+
if (searchTerm) {
|
|
1139
|
+
const scores = /* @__PURE__ */ new Map();
|
|
1140
|
+
filtered.forEach((a) => {
|
|
1141
|
+
scores.set(a.id, computeAgentSearchScore(a, searchTerm));
|
|
1142
|
+
});
|
|
1143
|
+
const serverRank = /* @__PURE__ */ new Map();
|
|
1144
|
+
consumer.serverMatchedIds.forEach((id, i) => serverRank.set(id, i));
|
|
1145
|
+
return [...filtered].sort((a, b) => {
|
|
1146
|
+
const sa = scores.get(a.id) ?? 0;
|
|
1147
|
+
const sb = scores.get(b.id) ?? 0;
|
|
1148
|
+
if (sb !== sa) return sb - sa;
|
|
1149
|
+
if (sa === 0) {
|
|
1150
|
+
const ra = serverRank.get(a.id);
|
|
1151
|
+
const rb = serverRank.get(b.id);
|
|
1152
|
+
if (ra !== void 0 && rb !== void 0 && ra !== rb) return ra - rb;
|
|
1153
|
+
}
|
|
1154
|
+
return applyAgentSortComparator(a, b, sortBy);
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
return [...filtered].sort((a, b) => {
|
|
1158
|
+
if (favoritesFirst && favFilter === "all") {
|
|
1159
|
+
const aFav = a.isFavorite ? 1 : 0;
|
|
1160
|
+
const bFav = b.isFavorite ? 1 : 0;
|
|
1161
|
+
if (bFav !== aFav) return bFav - aFav;
|
|
1162
|
+
}
|
|
1163
|
+
return applyAgentSortComparator(a, b, sortBy);
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
function filterUserTypeAgents(agents, consumer) {
|
|
1167
|
+
const {
|
|
1168
|
+
searchTerm,
|
|
1169
|
+
includedCats,
|
|
1170
|
+
includedTags,
|
|
1171
|
+
favFilter,
|
|
1172
|
+
archFilter,
|
|
1173
|
+
accessFilter,
|
|
1174
|
+
tab
|
|
1175
|
+
} = consumer;
|
|
1176
|
+
const serverMatched = new Set(consumer.serverMatchedIds);
|
|
1177
|
+
const filtered = agents.filter((agent) => {
|
|
1178
|
+
if (tab === "mine" && agent.isOwner !== true) return false;
|
|
1179
|
+
if (tab === "shared" && !(agent.isOwner === false && agent.accessLevel != null))
|
|
1180
|
+
return false;
|
|
1181
|
+
if (archFilter === "active" && agent.isArchived) return false;
|
|
1182
|
+
if (archFilter === "archived" && !agent.isArchived) return false;
|
|
1183
|
+
if (favFilter === "yes" && !agent.isFavorite) return false;
|
|
1184
|
+
if (favFilter === "no" && agent.isFavorite) return false;
|
|
1185
|
+
if (accessFilter === "owned" && agent.isOwner !== true) return false;
|
|
1186
|
+
if (accessFilter === "shared" && agent.isOwner !== false) return false;
|
|
1187
|
+
if (accessFilter === "editable" && agent.accessLevel !== "owner" && agent.accessLevel !== "admin" && agent.accessLevel !== "editor")
|
|
1188
|
+
return false;
|
|
1189
|
+
if (includedCats.length > 0) {
|
|
1190
|
+
const category = agent.category;
|
|
1191
|
+
if (!category) {
|
|
1192
|
+
if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;
|
|
1193
|
+
} else if (!includedCats.includes(category)) {
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
if (includedTags.length > 0) {
|
|
1198
|
+
const isUntagged = !agent.tags?.length;
|
|
1199
|
+
if (isUntagged) {
|
|
1200
|
+
if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;
|
|
1201
|
+
} else if (!agent.tags?.some((t) => includedTags.includes(t))) {
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (searchTerm && !agentMatchesSearch(agent, searchTerm) && !serverMatched.has(agent.id))
|
|
1206
|
+
return false;
|
|
1207
|
+
return true;
|
|
1208
|
+
});
|
|
1209
|
+
return sortFilteredAgents(filtered, consumer);
|
|
1210
|
+
}
|
|
1211
|
+
function filterBuiltinTypeAgents(agents, consumer) {
|
|
1212
|
+
const { searchTerm, favFilter, includedCats, includedTags } = consumer;
|
|
1213
|
+
const serverMatched = new Set(consumer.serverMatchedIds);
|
|
1214
|
+
const filtered = agents.filter((agent) => {
|
|
1215
|
+
if (favFilter === "yes" && !agent.isFavorite) return false;
|
|
1216
|
+
if (favFilter === "no" && agent.isFavorite) return false;
|
|
1217
|
+
if (includedCats.length > 0) {
|
|
1218
|
+
const category = agent.category;
|
|
1219
|
+
if (!category) {
|
|
1220
|
+
if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;
|
|
1221
|
+
} else if (!includedCats.includes(category)) {
|
|
1222
|
+
return false;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (includedTags.length > 0) {
|
|
1226
|
+
const isUntagged = !agent.tags?.length;
|
|
1227
|
+
if (isUntagged) {
|
|
1228
|
+
if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;
|
|
1229
|
+
} else if (!agent.tags?.some((t) => includedTags.includes(t))) {
|
|
1230
|
+
return false;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (searchTerm && !agentMatchesSearch(agent, searchTerm) && !serverMatched.has(agent.id))
|
|
1234
|
+
return false;
|
|
1235
|
+
return true;
|
|
1236
|
+
});
|
|
1237
|
+
return sortFilteredAgents(filtered, consumer);
|
|
1238
|
+
}
|
|
1239
|
+
var makeSelectFilteredOwnedAgents = () => memoize2(
|
|
1240
|
+
(agents, consumer) => filterUserTypeAgents(selectUserTypeAgents(agents), {
|
|
1241
|
+
...consumer,
|
|
1242
|
+
tab: "mine"
|
|
1243
|
+
})
|
|
1244
|
+
);
|
|
1245
|
+
var makeSelectFilteredSharedAgents = () => memoize2(
|
|
1246
|
+
(agents, consumer) => filterUserTypeAgents(selectUserTypeAgents(agents), {
|
|
1247
|
+
...consumer,
|
|
1248
|
+
tab: "shared"
|
|
1249
|
+
})
|
|
1250
|
+
);
|
|
1251
|
+
var makeSelectFilteredAgents = (includeSystemInAll = false) => memoize2(
|
|
1252
|
+
(agents, consumer) => {
|
|
1253
|
+
const userAgents = selectUserTypeAgents(agents);
|
|
1254
|
+
const builtinAgents = selectBuiltinTypeAgents(agents);
|
|
1255
|
+
if (consumer.tab === "system") {
|
|
1256
|
+
return filterBuiltinTypeAgents(builtinAgents, consumer);
|
|
1257
|
+
}
|
|
1258
|
+
if (includeSystemInAll && consumer.tab === "all") {
|
|
1259
|
+
return [
|
|
1260
|
+
...filterUserTypeAgents(userAgents, consumer),
|
|
1261
|
+
...filterBuiltinTypeAgents(builtinAgents, consumer)
|
|
1262
|
+
];
|
|
1263
|
+
}
|
|
1264
|
+
return filterUserTypeAgents(userAgents, consumer);
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
var makeSelectFilteredBuiltinAgents = () => memoize2(
|
|
1268
|
+
(agents, consumer) => filterBuiltinTypeAgents(selectBuiltinTypeAgents(agents), consumer)
|
|
1269
|
+
);
|
|
1270
|
+
function pageAfterCards(filtered, limit, page) {
|
|
1271
|
+
const afterCards = filtered.slice(limit);
|
|
1272
|
+
const pageEnd = page * AGENT_LIST_ITEMS_PER_PAGE;
|
|
1273
|
+
const items = afterCards.slice(0, pageEnd);
|
|
1274
|
+
return {
|
|
1275
|
+
items,
|
|
1276
|
+
hasMore: items.length < afterCards.length,
|
|
1277
|
+
totalAfterCards: afterCards.length
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
var makeSelectOwnedAgentCards = (isMobile) => {
|
|
1281
|
+
const selectFiltered = makeSelectFilteredOwnedAgents();
|
|
1282
|
+
const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;
|
|
1283
|
+
return memoize2(
|
|
1284
|
+
(agents, consumer) => selectFiltered(agents, consumer).slice(0, limit)
|
|
1285
|
+
);
|
|
1286
|
+
};
|
|
1287
|
+
var makeSelectOwnedAgentListItems = (isMobile) => {
|
|
1288
|
+
const selectFiltered = makeSelectFilteredOwnedAgents();
|
|
1289
|
+
const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;
|
|
1290
|
+
return memoize2(
|
|
1291
|
+
(agents, consumer) => pageAfterCards(selectFiltered(agents, consumer), limit, consumer.listPage)
|
|
1292
|
+
);
|
|
1293
|
+
};
|
|
1294
|
+
var makeSelectSharedAgentCards = (isMobile) => {
|
|
1295
|
+
const selectFiltered = makeSelectFilteredSharedAgents();
|
|
1296
|
+
const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;
|
|
1297
|
+
return memoize2(
|
|
1298
|
+
(agents, consumer) => selectFiltered(agents, consumer).slice(0, limit)
|
|
1299
|
+
);
|
|
1300
|
+
};
|
|
1301
|
+
var makeSelectSharedAgentListItems = (isMobile) => {
|
|
1302
|
+
const selectFiltered = makeSelectFilteredSharedAgents();
|
|
1303
|
+
const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;
|
|
1304
|
+
return memoize2(
|
|
1305
|
+
(agents, consumer) => pageAfterCards(
|
|
1306
|
+
selectFiltered(agents, consumer),
|
|
1307
|
+
limit,
|
|
1308
|
+
consumer.sharedPage
|
|
1309
|
+
)
|
|
1310
|
+
);
|
|
1311
|
+
};
|
|
1312
|
+
var makeSelectFilteredAgentsCount = () => {
|
|
1313
|
+
const selectFiltered = makeSelectFilteredAgents();
|
|
1314
|
+
return memoize2(
|
|
1315
|
+
(agents, consumer) => selectFiltered(agents, consumer).length
|
|
1316
|
+
);
|
|
1317
|
+
};
|
|
1318
|
+
var makeSelectFilteredBuiltinAgentsCount = () => {
|
|
1319
|
+
const selectFiltered = makeSelectFilteredBuiltinAgents();
|
|
1320
|
+
return memoize2(
|
|
1321
|
+
(agents, consumer) => selectFiltered(agents, consumer).length
|
|
1322
|
+
);
|
|
1323
|
+
};
|
|
1324
|
+
function agentConsumerHasActiveFilters(consumer, defaults) {
|
|
1325
|
+
return consumer.tab !== defaults.tab || consumer.sortBy !== defaults.sortBy || consumer.searchTerm !== "" || consumer.includedCats.length > 0 || consumer.includedTags.length > 0 || consumer.favFilter !== defaults.favFilter || consumer.archFilter !== defaults.archFilter || consumer.accessFilter !== defaults.accessFilter || consumer.favoritesFirst !== defaults.favoritesFirst;
|
|
1326
|
+
}
|
|
1327
|
+
var selectTotalUserAgentsCount = memoize1(
|
|
1328
|
+
(agents) => selectUserTypeAgents(agents).length
|
|
1329
|
+
);
|
|
1330
|
+
var selectTotalOwnedAgentsCount = memoize1(
|
|
1331
|
+
(agents) => selectUserTypeAgents(agents).filter((a) => a.isOwner === true).length
|
|
1332
|
+
);
|
|
1333
|
+
var selectTotalSharedAgentsCount = memoize1(
|
|
1334
|
+
(agents) => selectUserTypeAgents(agents).filter(
|
|
1335
|
+
(a) => a.isOwner === false && a.accessLevel != null
|
|
1336
|
+
).length
|
|
1337
|
+
);
|
|
1338
|
+
var selectTotalBuiltinAgentsCount = memoize1(
|
|
1339
|
+
(agents) => selectBuiltinTypeAgents(agents).length
|
|
1340
|
+
);
|
|
1341
|
+
var selectTotalFavoriteAgentsCount = memoize1(
|
|
1342
|
+
(agents) => selectUserTypeAgents(agents).filter((a) => a.isFavorite).length
|
|
1343
|
+
);
|
|
1344
|
+
//# sourceMappingURL=index.cjs.map
|