@ai-matrx/agents 0.8.0 → 0.9.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 +243 -0
- package/dist/catalog/index.cjs +101 -15
- package/dist/catalog/index.cjs.map +1 -1
- package/dist/catalog/index.d.cts +86 -616
- package/dist/catalog/index.d.ts +86 -616
- package/dist/catalog/index.js +101 -15
- package/dist/catalog/index.js.map +1 -1
- package/dist/catalog/native/index.cjs +2838 -0
- package/dist/catalog/native/index.cjs.map +1 -0
- package/dist/catalog/native/index.d.cts +660 -0
- package/dist/catalog/native/index.d.ts +660 -0
- package/dist/catalog/native/index.js +2834 -0
- package/dist/catalog/native/index.js.map +1 -0
- package/dist/catalog/react/index.cjs +524 -415
- package/dist/catalog/react/index.cjs.map +1 -1
- package/dist/catalog/react/index.d.cts +69 -26
- package/dist/catalog/react/index.d.ts +69 -26
- package/dist/catalog/react/index.js +408 -299
- package/dist/catalog/react/index.js.map +1 -1
- package/dist/orchestra-CID-rsu8.d.cts +643 -0
- package/dist/orchestra-CID-rsu8.d.ts +643 -0
- package/package.json +22 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,248 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1 — 2026-09-08
|
|
4
|
+
|
|
5
|
+
**TWO SCREENS TOLD THE SAME USER TWO DIFFERENT TRUTHS. BOTH ARE FIXED HERE, IN
|
|
6
|
+
THE PACKAGE, AT THE CLASS.**
|
|
7
|
+
|
|
8
|
+
Independent final verification of the picker unification (2026-09-08, same
|
|
9
|
+
account signed in on both surfaces) found the tab strip, the counts, the
|
|
10
|
+
Mine/Shared/All order, the five sort options, the tri-state favourites control,
|
|
11
|
+
the 42 categories, the 871 tags and four tag-only searches identical between
|
|
12
|
+
`aimatrx.com/chat/new` and `workflows.aimatrx.com`. Two things were not.
|
|
13
|
+
|
|
14
|
+
### Consumer action: none
|
|
15
|
+
|
|
16
|
+
No export was removed, renamed or re-signed. Three symbols were ADDED —
|
|
17
|
+
`compareAgentIds`, `agentMatchesArchiveFilter`, `selectAgentTabCounts` — and the
|
|
18
|
+
web `AgentRow` gained a `data-testid` matching the native row's `testID`.
|
|
19
|
+
Every host adopts this by taking `latest`; there is nothing to change.
|
|
20
|
+
|
|
21
|
+
### Behavioural deltas (both deliberate, both were defects)
|
|
22
|
+
|
|
23
|
+
**F1 — every sort is now a TOTAL order, ending on `id` ASC.**
|
|
24
|
+
|
|
25
|
+
The Public tab diverged at index 10. 17 rows tied on
|
|
26
|
+
`updated_at = 2026-09-08T06:52:46.430326+00:00`, and the two hosts fetch the
|
|
27
|
+
same RPC through different transports:
|
|
28
|
+
|
|
29
|
+
| host | request | order of tied rows |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| matrx-frontend | `POST /rpc/agx_get_list_full` (one shot) | the RPC's own |
|
|
32
|
+
| workflow-studio | `…?order=id.asc&offset=0&limit=1000` (`readAllRows`) | id ASC |
|
|
33
|
+
|
|
34
|
+
Neither client was wrong about the ROWS. The sort was not total: each
|
|
35
|
+
comparator branch returned `0` for tied rows, so `Array.prototype.sort` left
|
|
36
|
+
them wherever the transport had put them. `sortFilteredAgents` and
|
|
37
|
+
`applyAgentSortComparator` now end on the same final key the database itself
|
|
38
|
+
ends on — `public.agx_get_list` is
|
|
39
|
+
`ORDER BY is_favorite DESC, updated_at DESC, id` — giving:
|
|
40
|
+
|
|
41
|
+
searching: score DESC -> server rank ASC -> sort key -> id ASC
|
|
42
|
+
not searching: favourites first (when asked) -> sort key -> id ASC
|
|
43
|
+
|
|
44
|
+
Comparison is a codepoint `<`/`>`, never `localeCompare`: Postgres orders
|
|
45
|
+
`uuid` by its raw bytes and a collator is free to fold case or ignore the
|
|
46
|
+
dashes, which would diverge from the server on exactly these ties. A sort key
|
|
47
|
+
that yields `NaN` (an unparseable timestamp) now collapses to the id key
|
|
48
|
+
instead of defeating it.
|
|
49
|
+
|
|
50
|
+
*What the frontend used to do on ties: whatever order the RPC page came back
|
|
51
|
+
in.* That was never a decision — it was the absence of one, and it happened to
|
|
52
|
+
look stable only until a second host fetched the same rows a different way. The
|
|
53
|
+
order is now DEFINED, is the server's own, and is a function of the rows alone.
|
|
54
|
+
|
|
55
|
+
**F5 — a tab badge counts exactly what the tab renders.**
|
|
56
|
+
|
|
57
|
+
The Mine badge said 416 while the list rendered 412 rows and the footer said
|
|
58
|
+
"412 agents": 4 owned and 2 shared ARCHIVED agents were counted by the badge
|
|
59
|
+
and (correctly) hidden by the list. One screen, three numbers, one of them
|
|
60
|
+
untrue about agents the user cannot see or reach from there. This is "a screen
|
|
61
|
+
never lies", so it is a fix and not a knob.
|
|
62
|
+
|
|
63
|
+
`selectAgentTabCounts(rows, archFilter)` is the new consumer-aware badge
|
|
64
|
+
source used by `useAgentListCore`, and the four plain aggregate counts
|
|
65
|
+
(`selectTotalUserAgentsCount`, `…Owned…`, `…Shared…`, `…Favorite…`) now honour
|
|
66
|
+
the same archive rule the list uses. Flip the archive filter and the badges
|
|
67
|
+
follow the list into the archive. `selectTotalBuiltinAgentsCount` is
|
|
68
|
+
deliberately unchanged: `filterBuiltinTypeAgents` applies no archive filter
|
|
69
|
+
(a builtin belongs to the platform and is never the user's to archive), so it
|
|
70
|
+
already counted exactly what it rendered.
|
|
71
|
+
|
|
72
|
+
### The proof
|
|
73
|
+
|
|
74
|
+
`catalog/__tests__/parity.test.ts`'s 66-row fixture had NO ties, which is why
|
|
75
|
+
293 green cases never saw F1. The new fixture does:
|
|
76
|
+
`catalog/__tests__/total-order-fixture.json` — 42 rows, every one on that exact
|
|
77
|
+
live `updated_at`, 26 of them also tied on `created_at`, with name and category
|
|
78
|
+
tie groups on top, ids deliberately uncorrelated with emission order.
|
|
79
|
+
|
|
80
|
+
`total-order-expected.json` is generated **from the RULE** by
|
|
81
|
+
`scripts/generate-total-order-fixture.mjs` — favourites -> key -> id ASC,
|
|
82
|
+
written out independently and importing nothing from `catalog/selectors.ts`.
|
|
83
|
+
Regenerating it by running the shipped comparator would have made the test a
|
|
84
|
+
mirror of the code; it measures the specification instead.
|
|
85
|
+
|
|
86
|
+
720 cases (tab x sort x favouritesFirst x archive x favourite x access) are
|
|
87
|
+
asserted three times over — kernel (`catalog/__tests__/total-order.test.ts`),
|
|
88
|
+
web shell (`catalog/react/total-order.test.tsx`) and native shell
|
|
89
|
+
(`catalog/native/__tests__/total-order.test.tsx`) — each reading the RENDERED
|
|
90
|
+
row ids, not the selector's return value.
|
|
91
|
+
|
|
92
|
+
Falsifiability, on every leg:
|
|
93
|
+
|
|
94
|
+
- the same rows are fed in four different input orders (identity, two seeded
|
|
95
|
+
shuffles, reversed) and the answer must be byte-identical — this is the live
|
|
96
|
+
defect, reproduced as a test;
|
|
97
|
+
- both shells mount the picker twice with the row array reversed and compare
|
|
98
|
+
screen to screen;
|
|
99
|
+
- deleting the id tiebreaker turns 4 of the 10 kernel tests red (verified
|
|
100
|
+
before shipping), and a key-only sort of the same fixture is asserted to
|
|
101
|
+
disagree with itself under reversal;
|
|
102
|
+
- the F5 legs assert the OLD counting rule produces a DIFFERENT number on this
|
|
103
|
+
fixture, so "badge == rows" cannot pass vacuously.
|
|
104
|
+
|
|
105
|
+
`parity.test.ts`'s count assertion now states the F5 delta explicitly — the
|
|
106
|
+
recorded matrx-frontend number minus the archived rows the list hides — rather
|
|
107
|
+
than reproducing a screen that lies. Its 293-case ordering matrix and the
|
|
108
|
+
native shell's 293-case matrix are UNCHANGED and still green: the old fixture
|
|
109
|
+
had no ties, so F1 moved nothing that was already defined.
|
|
110
|
+
|
|
111
|
+
## 0.9.0 — 2026-09-08
|
|
112
|
+
|
|
113
|
+
**THE ONE PICKER NOW RENDERS ON REACT NATIVE — `@ai-matrx/agents/catalog/native`.**
|
|
114
|
+
|
|
115
|
+
Matrx Mobile (Expo 54 / RN 0.81) was the last client still hand-rolling its
|
|
116
|
+
agent list. Its sheet showed four HARDCODED agents plus a Supabase read of a
|
|
117
|
+
`prompts` table that **does not exist in the platform database** — a read whose
|
|
118
|
+
PostgREST error was swallowed into an empty array, so the list silently never
|
|
119
|
+
had anything but the four constants. Three of those four constants named the
|
|
120
|
+
WRONG agent: the ids behind "General Chat", "Deep Research" and "Code Helper"
|
|
121
|
+
resolve in `agent.definition` to *Agent Ledger*, *Knowledge Search Test* and
|
|
122
|
+
*Balanced News Analysis*. A label lying on screen, with nothing anywhere that
|
|
123
|
+
could notice — the same class the mandate default row was built to end.
|
|
124
|
+
|
|
125
|
+
React Native could not adopt the picker before this release for two concrete
|
|
126
|
+
reasons, and both are fixed here rather than worked around in the app.
|
|
127
|
+
|
|
128
|
+
### Consumer action (C28)
|
|
129
|
+
|
|
130
|
+
**Web hosts: none.** `@ai-matrx/agents/catalog` and `/catalog/react` keep every
|
|
131
|
+
export, every name and every behaviour. The provider, the store subscription
|
|
132
|
+
and the two list hooks moved to `catalog/shared/*` so both platforms run one
|
|
133
|
+
implementation; `catalog/react` re-exports all of them unchanged, and the
|
|
134
|
+
`"use client"` banner is still stamped on the react build and still absent from
|
|
135
|
+
the pure ones (the tarball canary now judges eight artefacts instead of four).
|
|
136
|
+
|
|
137
|
+
**React Native hosts:**
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
141
|
+
import { createAgentCatalog } from "@ai-matrx/agents/catalog";
|
|
142
|
+
import { AgentCatalogProvider, AgentListSheet } from "@ai-matrx/agents/catalog/native";
|
|
143
|
+
|
|
144
|
+
const catalog = createAgentCatalog({
|
|
145
|
+
client: supabase,
|
|
146
|
+
identity: { requireUserId: () => requireUserId() },
|
|
147
|
+
storage: AsyncStorage, // NEW — the async storage seam
|
|
148
|
+
transport, // only when a picker passes defaultMandateKey
|
|
149
|
+
errorSink: reportToDiagnostics,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
<AgentCatalogProvider catalog={catalog} navigate={(href) => router.push(href)}>
|
|
153
|
+
<AgentListSheet consumerId="chat" onSelect={setAgentId} activeAgentId={agentId} />
|
|
154
|
+
</AgentCatalogProvider>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- `react-native` and `react-native-svg` are OPTIONAL peers. Install
|
|
158
|
+
`react-native-svg` (`npx expo install react-native-svg`) for the real glyphs;
|
|
159
|
+
without it the icons fall back to text glyphs and **say so once** through the
|
|
160
|
+
`errorSink`, with the remedy. Nothing goes blank and nothing goes quiet.
|
|
161
|
+
- Bind `navigate` if your rows should be able to open an agent. Unbound, the
|
|
162
|
+
default is a no-op that REPORTS through the `errorSink` — never a control
|
|
163
|
+
that silently does nothing.
|
|
164
|
+
- `@ai-matrx/agents/catalog/styles.css` is a WEB artefact; the native entry
|
|
165
|
+
needs no stylesheet.
|
|
166
|
+
|
|
167
|
+
### What is new
|
|
168
|
+
|
|
169
|
+
- **`@ai-matrx/agents/catalog/native`** — the picker in React Native
|
|
170
|
+
primitives over the SAME headless kernel and the SAME hooks:
|
|
171
|
+
`AgentCatalogProvider`, `AgentListSheet` (the body of a bottom sheet — the
|
|
172
|
+
host keeps its own sheet chrome, so no gesture library is forced on anyone),
|
|
173
|
+
`AgentListInlinePicker`, and every part beneath them (`AgentListContent`,
|
|
174
|
+
`AgentListTabs`, `AgentFilterBar`, `AgentRow`, `AgentDetailCard`,
|
|
175
|
+
`AgentSubView`, `FavoriteAgentButton`, the five primitives, `AgentIcon`).
|
|
176
|
+
The shells take the web shells' prop surface name for name: `onSelect`,
|
|
177
|
+
`activeAgentId`, `consumerId`, `initialTab`, `includeSystemInAll`,
|
|
178
|
+
`visibleTabs`, `systemTabLabel`, `showPinnedAgent`, `excludeAgentIds`,
|
|
179
|
+
`defaultMandateKey`, `compact`.
|
|
180
|
+
- **The async storage seam** — `AgentCatalogAsyncStorage` /
|
|
181
|
+
`AgentCatalogStorageLike`, plus `readCachedDefaultRowAsync` and
|
|
182
|
+
`writeCachedDefaultRowAsync`. `createAgentCatalog({ storage })` now accepts an
|
|
183
|
+
`AsyncStorage`-shaped store verbatim. React Native has no `localStorage`, so
|
|
184
|
+
before this a native host could only hand the catalog a store that answered
|
|
185
|
+
`null` synchronously (a lie) or lose the default row's first paint entirely.
|
|
186
|
+
**The web path is unchanged**: `AgentCatalogStorage` is still synchronous,
|
|
187
|
+
`readCachedDefaultRow`/`writeCachedDefaultRow` still have their synchronous
|
|
188
|
+
signatures, `defaultStorage()` still prefers `localStorage`, and the async
|
|
189
|
+
helpers over a synchronous store produce byte-identical cache payloads
|
|
190
|
+
(proven in `catalog/__tests__/storage-seam.test.ts`).
|
|
191
|
+
- **`AgentCatalogNativeTheme`** (C26 on a platform with no CSS) — the native
|
|
192
|
+
twin of the `--matrx-agent-*` sheet: every token ships a DEFAULT VALUE so the
|
|
193
|
+
picker renders correctly unthemed, and a host re-brands by passing `theme` to
|
|
194
|
+
the provider. `DEFAULT_AGENT_CATALOG_NATIVE_THEME` (dark) and
|
|
195
|
+
`LIGHT_AGENT_CATALOG_NATIVE_THEME` ship; `resolveAgentCatalogNativeTheme`
|
|
196
|
+
merges an override and keeps every value it omits. No native component
|
|
197
|
+
contains a colour literal.
|
|
198
|
+
- **`catalog/shared/icon-paths.ts`** — the glyph geometry, once. The web icons
|
|
199
|
+
now read it too, so a shape can never differ between the two platforms; the
|
|
200
|
+
native entry draws the same paths through `react-native-svg` (C19: still no
|
|
201
|
+
icon-library dependency, on either platform).
|
|
202
|
+
- **`AgentListTabCounts` moved** to `catalog/shared/useAgentListCore` beside the
|
|
203
|
+
code that computes it. `catalog/react/AgentListTabs` re-exports it unchanged.
|
|
204
|
+
|
|
205
|
+
### Behavioural deltas on native, recorded rather than hidden
|
|
206
|
+
|
|
207
|
+
1. **No hover preview.** The web picker's side panel opens on hover; a touch
|
|
208
|
+
screen has no hover, so the detail card is reached by the row's chevron —
|
|
209
|
+
the same three-view stack (`list → detail → sort/categories/tags`) the web
|
|
210
|
+
`AgentListInlinePicker` already used on mobile widths.
|
|
211
|
+
2. **No cmd-click link.** `AgentRow`'s anchor exists on the web so a person can
|
|
212
|
+
open an agent in a new tab. React Native has neither, so the row is an
|
|
213
|
+
ordinary `Pressable`; the `LinkComponent` port still exists and still ships
|
|
214
|
+
a working native default.
|
|
215
|
+
3. **`autoFocusSearch` defaults to `false`** (the web inline picker defaults to
|
|
216
|
+
`true`): a keyboard that opens with the sheet covers the list it was meant
|
|
217
|
+
to filter.
|
|
218
|
+
|
|
219
|
+
### Proof
|
|
220
|
+
|
|
221
|
+
- **The 293-case ordering matrix, re-measured through the RENDERED native
|
|
222
|
+
list** (`catalog/native/__tests__/parity.test.tsx`): every case's ids, in
|
|
223
|
+
order, read back out of the mounted native tree — not out of the selectors a
|
|
224
|
+
second time. Sharing a kernel is an architecture claim; this is the
|
|
225
|
+
measurement. It carries a falsifiability leg.
|
|
226
|
+
- **The tarball canary imports AND requires `./catalog/native`**, checks every
|
|
227
|
+
documented export, proves the theme override merges over the PACKED build,
|
|
228
|
+
proves the icon degradation announces exactly once with its remedy, and
|
|
229
|
+
compiles a native usage (including an `AsyncStorage`-shaped `storage`) against
|
|
230
|
+
the packed types under `exactOptionalPropertyTypes` + `noUncheckedIndexedAccess`.
|
|
231
|
+
- **The banner canary now judges eight artefacts**: the `"use client"` prologue
|
|
232
|
+
must be present on both `catalog/react` builds and ABSENT from all four
|
|
233
|
+
`catalog/index.*` and all four `catalog/native/index.*` files.
|
|
234
|
+
|
|
235
|
+
### Known limits, stated plainly
|
|
236
|
+
|
|
237
|
+
There is still **no React Native canary harness** in this workspace (campaign
|
|
238
|
+
decision C7 schedules it for Phase 2), and the real `react-native` package
|
|
239
|
+
cannot be loaded by vitest — it ships Flow-typed source only Metro parses. The
|
|
240
|
+
native tests therefore render against a minimal RN stand-in
|
|
241
|
+
(`catalog/native/__tests__/react-native.stub.tsx`) that maps RN primitives onto
|
|
242
|
+
DOM nodes. That proves rows, order, labels, counts, handlers and every
|
|
243
|
+
announced degradation. It does **not** prove pixel layout, gestures or Hermes —
|
|
244
|
+
those are proven by the consuming Expo app's own build and device smoke.
|
|
245
|
+
|
|
3
246
|
## 0.8.0 — 2026-09-08
|
|
4
247
|
|
|
5
248
|
**THE ORCHESTRA BADGE IS BACK, in every client at once.**
|
package/dist/catalog/index.cjs
CHANGED
|
@@ -34,10 +34,12 @@ __export(catalog_exports, {
|
|
|
34
34
|
_resetCatalogGlobalState: () => _resetCatalogGlobalState,
|
|
35
35
|
agentConsumerHasActiveFilters: () => agentConsumerHasActiveFilters,
|
|
36
36
|
agentListEmptyLabel: () => agentListEmptyLabel,
|
|
37
|
+
agentMatchesArchiveFilter: () => agentMatchesArchiveFilter,
|
|
37
38
|
agentMatchesSearch: () => agentMatchesSearch,
|
|
38
39
|
applyAgentSortComparator: () => applyAgentSortComparator,
|
|
39
40
|
asAgentId: () => asAgentId,
|
|
40
41
|
assertAgentCatalogSchema: () => assertAgentCatalogSchema,
|
|
42
|
+
compareAgentIds: () => compareAgentIds,
|
|
41
43
|
computeAgentSearchScore: () => computeAgentSearchScore,
|
|
42
44
|
createAgentCatalog: () => createAgentCatalog,
|
|
43
45
|
createMemoryStorage: () => createMemoryStorage,
|
|
@@ -69,9 +71,11 @@ __export(catalog_exports, {
|
|
|
69
71
|
parseMandateResolution: () => parseMandateResolution,
|
|
70
72
|
readAgentCatalogRows: () => readAgentCatalogRows,
|
|
71
73
|
readCachedDefaultRow: () => readCachedDefaultRow,
|
|
74
|
+
readCachedDefaultRowAsync: () => readCachedDefaultRowAsync,
|
|
72
75
|
readSingleAgentRow: () => readSingleAgentRow,
|
|
73
76
|
resolveDefaultRow: () => resolveDefaultRow,
|
|
74
77
|
searchAgentsOnServer: () => searchAgentsOnServer,
|
|
78
|
+
selectAgentTabCounts: () => selectAgentTabCounts,
|
|
75
79
|
selectAllAgentCategories: () => selectAllAgentCategories,
|
|
76
80
|
selectAllAgentTags: () => selectAllAgentTags,
|
|
77
81
|
selectAllSystemAgentCategories: () => selectAllSystemAgentCategories,
|
|
@@ -87,7 +91,8 @@ __export(catalog_exports, {
|
|
|
87
91
|
sortFilteredAgents: () => sortFilteredAgents,
|
|
88
92
|
toAgentSummary: () => toAgentSummary,
|
|
89
93
|
writeAgentFavorite: () => writeAgentFavorite,
|
|
90
|
-
writeCachedDefaultRow: () => writeCachedDefaultRow
|
|
94
|
+
writeCachedDefaultRow: () => writeCachedDefaultRow,
|
|
95
|
+
writeCachedDefaultRowAsync: () => writeCachedDefaultRowAsync
|
|
91
96
|
});
|
|
92
97
|
module.exports = __toCommonJS(catalog_exports);
|
|
93
98
|
|
|
@@ -312,8 +317,8 @@ async function readSingleAgentRow(client, agentId) {
|
|
|
312
317
|
}
|
|
313
318
|
return null;
|
|
314
319
|
}
|
|
315
|
-
async function writeAgentFavorite(client, agentId,
|
|
316
|
-
const { error } = await client.schema("agent").from("definition").update({ is_favorite:
|
|
320
|
+
async function writeAgentFavorite(client, agentId, isFavorite2) {
|
|
321
|
+
const { error } = await client.schema("agent").from("definition").update({ is_favorite: isFavorite2 }).eq("id", agentId);
|
|
317
322
|
if (error) {
|
|
318
323
|
throw new AgentCatalogReadError(
|
|
319
324
|
"agent.definition.is_favorite",
|
|
@@ -430,6 +435,51 @@ function writeCachedDefaultRow(storage, resolved) {
|
|
|
430
435
|
} catch {
|
|
431
436
|
}
|
|
432
437
|
}
|
|
438
|
+
function parseCachedDefaultRow(mandateKey, raw) {
|
|
439
|
+
try {
|
|
440
|
+
if (!raw) return null;
|
|
441
|
+
const parsed = JSON.parse(raw);
|
|
442
|
+
if (!isRecord2(parsed)) return null;
|
|
443
|
+
const holderId = parsed["holderId"];
|
|
444
|
+
const holderName = parsed["holderName"];
|
|
445
|
+
if (typeof holderId !== "string" || typeof holderName !== "string") {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const description = parsed["holderDescription"];
|
|
449
|
+
const provenance = parsed["provenance"];
|
|
450
|
+
const at = parsed["at"];
|
|
451
|
+
return {
|
|
452
|
+
mandateKey,
|
|
453
|
+
holderId,
|
|
454
|
+
holderName,
|
|
455
|
+
holderDescription: typeof description === "string" ? description : null,
|
|
456
|
+
provenance: typeof provenance === "string" ? provenance : "system",
|
|
457
|
+
at: typeof at === "number" ? at : 0
|
|
458
|
+
};
|
|
459
|
+
} catch {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async function readCachedDefaultRowAsync(storage, mandateKey) {
|
|
464
|
+
let raw;
|
|
465
|
+
try {
|
|
466
|
+
raw = await storage.getItem(
|
|
467
|
+
CACHE_PREFIX + mandateKey
|
|
468
|
+
);
|
|
469
|
+
} catch {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
return parseCachedDefaultRow(mandateKey, raw);
|
|
473
|
+
}
|
|
474
|
+
async function writeCachedDefaultRowAsync(storage, resolved) {
|
|
475
|
+
try {
|
|
476
|
+
await storage.setItem(
|
|
477
|
+
CACHE_PREFIX + resolved.mandateKey,
|
|
478
|
+
JSON.stringify(resolved)
|
|
479
|
+
);
|
|
480
|
+
} catch {
|
|
481
|
+
}
|
|
482
|
+
}
|
|
433
483
|
function defaultRowFromResolution(resolved) {
|
|
434
484
|
return {
|
|
435
485
|
id: mandateAgentId(resolved.mandateKey),
|
|
@@ -469,7 +519,7 @@ function detectDefaultRowDrift(cached, live) {
|
|
|
469
519
|
}
|
|
470
520
|
async function resolveDefaultRow(args) {
|
|
471
521
|
const { mandateKey, transport, client, storage, lookupRow } = args;
|
|
472
|
-
const cached =
|
|
522
|
+
const cached = await readCachedDefaultRowAsync(storage, mandateKey);
|
|
473
523
|
const verdict = await askTheServer(transport, mandateKey);
|
|
474
524
|
if (verdict.holderType !== "agent") {
|
|
475
525
|
throw new MandateDefaultRowError({
|
|
@@ -506,7 +556,7 @@ async function resolveDefaultRow(args) {
|
|
|
506
556
|
at: Date.now()
|
|
507
557
|
};
|
|
508
558
|
const drift = detectDefaultRowDrift(cached, resolved);
|
|
509
|
-
|
|
559
|
+
await writeCachedDefaultRowAsync(storage, resolved);
|
|
510
560
|
return { resolved, row: defaultRowFromResolution(resolved), drift };
|
|
511
561
|
}
|
|
512
562
|
|
|
@@ -846,7 +896,7 @@ function createAgentCatalog(config) {
|
|
|
846
896
|
mergeRows(result.rows);
|
|
847
897
|
return result.ids;
|
|
848
898
|
}
|
|
849
|
-
async function setFavorite(agentId,
|
|
899
|
+
async function setFavorite(agentId, isFavorite2) {
|
|
850
900
|
const existing = state.byId[agentId];
|
|
851
901
|
if (!existing) {
|
|
852
902
|
errorSink({
|
|
@@ -855,15 +905,15 @@ function createAgentCatalog(config) {
|
|
|
855
905
|
});
|
|
856
906
|
return;
|
|
857
907
|
}
|
|
858
|
-
mergeRows([{ ...existing, isFavorite }]);
|
|
908
|
+
mergeRows([{ ...existing, isFavorite: isFavorite2 }]);
|
|
859
909
|
try {
|
|
860
|
-
await writeAgentFavorite(client, agentId,
|
|
910
|
+
await writeAgentFavorite(client, agentId, isFavorite2);
|
|
861
911
|
} catch (e) {
|
|
862
912
|
mergeRows([existing]);
|
|
863
913
|
errorSink({
|
|
864
914
|
code: "favorite_write_failed",
|
|
865
915
|
message: `the favorite could not be saved: ${errorMessage(e)}`,
|
|
866
|
-
context: { agentId, isFavorite }
|
|
916
|
+
context: { agentId, isFavorite: isFavorite2 }
|
|
867
917
|
});
|
|
868
918
|
notifier?.({
|
|
869
919
|
level: "error",
|
|
@@ -1142,7 +1192,19 @@ function memoize3(fn) {
|
|
|
1142
1192
|
return last;
|
|
1143
1193
|
};
|
|
1144
1194
|
}
|
|
1195
|
+
function compareAgentIds(a, b) {
|
|
1196
|
+
const idA = a.id ?? "";
|
|
1197
|
+
const idB = b.id ?? "";
|
|
1198
|
+
if (idA < idB) return -1;
|
|
1199
|
+
if (idA > idB) return 1;
|
|
1200
|
+
return 0;
|
|
1201
|
+
}
|
|
1145
1202
|
function applyAgentSortComparator(a, b, sortBy) {
|
|
1203
|
+
const primary = compareAgentSortKey(a, b, sortBy);
|
|
1204
|
+
if (!Number.isFinite(primary) || primary === 0) return compareAgentIds(a, b);
|
|
1205
|
+
return primary;
|
|
1206
|
+
}
|
|
1207
|
+
function compareAgentSortKey(a, b, sortBy) {
|
|
1146
1208
|
switch (sortBy) {
|
|
1147
1209
|
case "name-asc":
|
|
1148
1210
|
return (a.name ?? "").localeCompare(b.name ?? "");
|
|
@@ -1390,21 +1452,45 @@ var makeSelectFilteredBuiltinAgentsCount = () => {
|
|
|
1390
1452
|
function agentConsumerHasActiveFilters(consumer, defaults) {
|
|
1391
1453
|
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;
|
|
1392
1454
|
}
|
|
1455
|
+
function agentMatchesArchiveFilter(agent, archFilter) {
|
|
1456
|
+
if (archFilter === "active") return !agent.isArchived;
|
|
1457
|
+
if (archFilter === "archived") return Boolean(agent.isArchived);
|
|
1458
|
+
return true;
|
|
1459
|
+
}
|
|
1460
|
+
function countUserRows(agents, archFilter, predicate) {
|
|
1461
|
+
let n = 0;
|
|
1462
|
+
for (const a of agents) {
|
|
1463
|
+
if (a.agentType !== "user") continue;
|
|
1464
|
+
if (!agentMatchesArchiveFilter(a, archFilter)) continue;
|
|
1465
|
+
if (predicate(a)) n += 1;
|
|
1466
|
+
}
|
|
1467
|
+
return n;
|
|
1468
|
+
}
|
|
1469
|
+
var isOwned = (a) => a.isOwner === true;
|
|
1470
|
+
var isShared = (a) => a.isOwner === false && a.accessLevel != null;
|
|
1471
|
+
var isAny = () => true;
|
|
1472
|
+
var isFavorite = (a) => Boolean(a.isFavorite);
|
|
1473
|
+
var selectAgentTabCounts = memoize2(
|
|
1474
|
+
(agents, archFilter) => ({
|
|
1475
|
+
mine: countUserRows(agents, archFilter, isOwned),
|
|
1476
|
+
shared: countUserRows(agents, archFilter, isShared),
|
|
1477
|
+
all: countUserRows(agents, archFilter, isAny),
|
|
1478
|
+
system: selectBuiltinTypeAgents(agents).length
|
|
1479
|
+
})
|
|
1480
|
+
);
|
|
1393
1481
|
var selectTotalUserAgentsCount = memoize1(
|
|
1394
|
-
(agents) =>
|
|
1482
|
+
(agents) => countUserRows(agents, "active", isAny)
|
|
1395
1483
|
);
|
|
1396
1484
|
var selectTotalOwnedAgentsCount = memoize1(
|
|
1397
|
-
(agents) =>
|
|
1485
|
+
(agents) => countUserRows(agents, "active", isOwned)
|
|
1398
1486
|
);
|
|
1399
1487
|
var selectTotalSharedAgentsCount = memoize1(
|
|
1400
|
-
(agents) =>
|
|
1401
|
-
(a) => a.isOwner === false && a.accessLevel != null
|
|
1402
|
-
).length
|
|
1488
|
+
(agents) => countUserRows(agents, "active", isShared)
|
|
1403
1489
|
);
|
|
1404
1490
|
var selectTotalBuiltinAgentsCount = memoize1(
|
|
1405
1491
|
(agents) => selectBuiltinTypeAgents(agents).length
|
|
1406
1492
|
);
|
|
1407
1493
|
var selectTotalFavoriteAgentsCount = memoize1(
|
|
1408
|
-
(agents) =>
|
|
1494
|
+
(agents) => countUserRows(agents, "active", isFavorite)
|
|
1409
1495
|
);
|
|
1410
1496
|
//# sourceMappingURL=index.cjs.map
|