@ai-matrx/agents 0.15.0 → 0.16.18

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/README.md +8 -4
  3. package/dist/catalog/index.cjs +82 -50
  4. package/dist/catalog/index.cjs.map +1 -1
  5. package/dist/catalog/index.d.cts +21 -10
  6. package/dist/catalog/index.d.ts +21 -10
  7. package/dist/catalog/index.js +82 -50
  8. package/dist/catalog/index.js.map +1 -1
  9. package/dist/catalog/native/index.cjs +2 -3
  10. package/dist/catalog/native/index.cjs.map +1 -1
  11. package/dist/catalog/native/index.d.cts +4 -5
  12. package/dist/catalog/native/index.d.ts +4 -5
  13. package/dist/catalog/native/index.js +2 -3
  14. package/dist/catalog/native/index.js.map +1 -1
  15. package/dist/catalog/react/index.cjs +10 -10
  16. package/dist/catalog/react/index.cjs.map +1 -1
  17. package/dist/catalog/react/index.d.cts +11 -11
  18. package/dist/catalog/react/index.d.ts +11 -11
  19. package/dist/catalog/react/index.js +10 -10
  20. package/dist/catalog/react/index.js.map +1 -1
  21. package/dist/content-transfer/index.cjs.map +1 -1
  22. package/dist/content-transfer/index.js.map +1 -1
  23. package/dist/content-transfer/react/index.cjs.map +1 -1
  24. package/dist/content-transfer/react/index.js.map +1 -1
  25. package/dist/mandates/index.cjs +2 -2
  26. package/dist/mandates/index.cjs.map +1 -1
  27. package/dist/mandates/index.d.cts +4 -4
  28. package/dist/mandates/index.d.ts +4 -4
  29. package/dist/mandates/index.js +2 -2
  30. package/dist/mandates/index.js.map +1 -1
  31. package/dist/{orchestra-BDXdut6Y.d.cts → orchestra-PbGGooqJ.d.cts} +50 -25
  32. package/dist/{orchestra-BDXdut6Y.d.ts → orchestra-PbGGooqJ.d.ts} +50 -25
  33. package/mandates/snapshots/keys.0.15.1.json +625 -0
  34. package/mandates/snapshots/keys.0.16.1.json +625 -0
  35. package/mandates/snapshots/keys.0.16.10.json +625 -0
  36. package/mandates/snapshots/keys.0.16.11.json +625 -0
  37. package/mandates/snapshots/keys.0.16.12.json +625 -0
  38. package/mandates/snapshots/keys.0.16.13.json +625 -0
  39. package/mandates/snapshots/keys.0.16.14.json +625 -0
  40. package/mandates/snapshots/keys.0.16.15.json +625 -0
  41. package/mandates/snapshots/keys.0.16.16.json +625 -0
  42. package/mandates/snapshots/keys.0.16.17.json +625 -0
  43. package/mandates/snapshots/keys.0.16.18.json +625 -0
  44. package/mandates/snapshots/keys.0.16.2.json +625 -0
  45. package/mandates/snapshots/keys.0.16.3.json +625 -0
  46. package/mandates/snapshots/keys.0.16.4.json +625 -0
  47. package/mandates/snapshots/keys.0.16.5.json +625 -0
  48. package/mandates/snapshots/keys.0.16.6.json +625 -0
  49. package/mandates/snapshots/keys.0.16.7.json +625 -0
  50. package/mandates/snapshots/keys.0.16.8.json +625 -0
  51. package/mandates/snapshots/keys.0.16.9.json +625 -0
  52. package/package.json +4 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,165 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.18
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.18 -- apps/shared/matrx-agents`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.16.17
10
+
11
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
12
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.17 -- apps/shared/matrx-agents`).
13
+ No source changes intended and no consumer action required.
14
+
15
+ ## 0.16.16
16
+
17
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
18
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.16 -- apps/shared/matrx-agents`).
19
+ No source changes intended and no consumer action required.
20
+
21
+ ## 0.16.15
22
+
23
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
24
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.15 -- apps/shared/matrx-agents`).
25
+ No source changes intended and no consumer action required.
26
+
27
+ ## 0.16.14
28
+
29
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
30
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.14 -- apps/shared/matrx-agents`).
31
+ No source changes intended and no consumer action required.
32
+
33
+ ## 0.16.13
34
+
35
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
36
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.13 -- apps/shared/matrx-agents`).
37
+ No source changes intended and no consumer action required.
38
+
39
+ ## 0.16.12
40
+
41
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
42
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.12 -- apps/shared/matrx-agents`).
43
+ No source changes intended and no consumer action required.
44
+
45
+ ## 0.16.11
46
+
47
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
48
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.11 -- apps/shared/matrx-agents`).
49
+ No source changes intended and no consumer action required.
50
+
51
+ ## 0.16.10
52
+
53
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
54
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.10 -- apps/shared/matrx-agents`).
55
+ No source changes intended and no consumer action required.
56
+
57
+ ## 0.16.9
58
+
59
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
60
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.9 -- apps/shared/matrx-agents`).
61
+ No source changes intended and no consumer action required.
62
+
63
+ ## 0.16.8
64
+
65
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
66
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.8 -- apps/shared/matrx-agents`).
67
+ No source changes intended and no consumer action required.
68
+
69
+ ## 0.16.7
70
+
71
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
72
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.7 -- apps/shared/matrx-agents`).
73
+ No source changes intended and no consumer action required.
74
+
75
+ ## 0.16.6
76
+
77
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
78
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.6 -- apps/shared/matrx-agents`).
79
+ No source changes intended and no consumer action required.
80
+
81
+ ## 0.16.5
82
+
83
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
84
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.5 -- apps/shared/matrx-agents`).
85
+ No source changes intended and no consumer action required.
86
+
87
+ ## 0.16.4
88
+
89
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
90
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.4 -- apps/shared/matrx-agents`).
91
+ No source changes intended and no consumer action required.
92
+
93
+ ## 0.16.3
94
+
95
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
96
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.3 -- apps/shared/matrx-agents`).
97
+ No source changes intended and no consumer action required.
98
+
99
+ ## 0.16.2
100
+
101
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
102
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.2 -- apps/shared/matrx-agents`).
103
+ No source changes intended and no consumer action required.
104
+
105
+ ## 0.16.1
106
+
107
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
108
+ `git diff npm/matrx-agents/v0.15.1..npm/matrx-agents/v0.16.1 -- apps/shared/matrx-agents`).
109
+ No source changes intended and no consumer action required.
110
+
111
+ ## 0.16.0
112
+
113
+ ### Changed (breaking)
114
+
115
+ - **Agent stars live in `platform.user_entity_state`.** A star is per-person
116
+ state; the catalog no longer reads or writes the retired
117
+ `agent.definition.is_favorite` column (a flag on the OWNER's row, which made a
118
+ shared agent unstarrable and let the classic grid, the picker, Pinned Agents,
119
+ the /agents list and the Knowledge hub disagree). Every list load and every
120
+ server-search hit overlays the caller's stars from ONE `ues_get_bulk('agent',
121
+ ids)`; `setFavorite` writes `ues_set`. Both go through the platform's one
122
+ `ues_*` chokepoint, `@ai-matrx/associations/core` (new dependency). A failed
123
+ star read never blocks the catalogue: it reports `favorite_read_failed` and
124
+ renders every star unset.
125
+ - `AgentCatalogClient` is `rpc()` only — `schema().from().update()` and the
126
+ `AgentCatalogTableQuery` port are gone (the column write was their only use).
127
+ - `FavoriteAgentButton` (web and native) no longer refuses non-owned rows:
128
+ "Shared — cannot favorite" existed only because of the owner-row column.
129
+ - `assertAgentCatalogSchema` demands `ues_get_bulk` and no longer probes a
130
+ column write; `favoriteWritable` and `probeWrite` are removed.
131
+ - A mandate default row whose Holder is being fetched by an in-flight list read
132
+ waits for that read instead of issuing a second single-row read.
133
+
134
+ ### Added
135
+
136
+ - `AgentCatalogConfig.favorites` (`AgentCatalogFavorites`) — optional; pass the
137
+ host's existing favorites service so there is exactly one instance. Default:
138
+ `createAssociationsStore({ dataSource: client, identity, errorSink }).favorites`.
139
+
140
+ ### Consumer action
141
+
142
+ - None required: a host passing a supabase-js client keeps working. A host that
143
+ already holds `@ai-matrx/associations`' favorites service (matrx-frontend's
144
+ `favoritesService`) should pass it as `favorites`. Remove any host code that
145
+ reads `favoriteWritable` or passes `probeWrite`.
146
+
147
+ ## 0.15.1
148
+
149
+ ### Added
150
+
151
+ - `AgentListPanel` `fill` — fill the parent instead of the fixed 680 × 528
152
+ footprint, for a resizable host (a window).
153
+
154
+ ### Changed
155
+
156
+ - The picker's list column flexes (`min-w-[340px] flex-1`); the peek column
157
+ stays 340px. In the dropdown's fixed 680px popover this is the same layout.
158
+
159
+ ### Consumer action
160
+
161
+ - None.
162
+
3
163
  ## 0.15.0
4
164
 
5
165
  ### Added
package/README.md CHANGED
@@ -175,7 +175,8 @@ import { AgentCatalogProvider, AgentListDropdown } from "@ai-matrx/agents/catalo
175
175
 
176
176
  You get, on every surface and in every app: the complete catalogue read (owned
177
177
  + shared + org-shared + platform agents), Mine / Shared / All / Public tabs
178
- with live counts, sort, favourites (with the write), category and tag filters,
178
+ with live counts, sort, favourites (the caller's own stars, read and written in
179
+ `platform.user_entity_state`), category and tag filters,
179
180
  local relevance scoring plus server-side search, the current agent pinned on
180
181
  top, per-row origin badges, a hover detail panel, a mobile drawer, and a footer
181
182
  count. `AgentListInlinePicker` is the same core without the popover shell.
@@ -197,20 +198,23 @@ the picker shows a persistent banner and calls your `notifier`.
197
198
  **Ports.** `client` and `identity` are required and throw when absent. Every
198
199
  other port ships a working default: `errorSink` (tagged console), `notifier`
199
200
  (the banner is the primary channel), `storage` (localStorage, else memory),
201
+ `favorites` (the `@ai-matrx/associations` `ues_*` chokepoint built on your
202
+ client — pass your own instance if you hold one),
200
203
  `labels`, `navigate` (`window.location.assign`), `LinkComponent` (a plain
201
204
  `<a>`), `renderModelRef` (plain text) and `openPeek` (absent → the affordance
202
205
  is hidden, never dead).
203
206
 
204
207
  `assertAgentCatalogSchema(client)` proves at boot that the database can answer
205
- `agx_get_list_full`, `agx_search`, `agx_resolve_agent_address` and the
206
- favourite write.
208
+ `agx_get_list_full`, `agx_search`, `agx_resolve_agent_address` and
209
+ `ues_get_bulk` (the star read).
207
210
 
208
211
  ## Runtime support
209
212
 
210
213
  The package targets modern browsers, browser-based desktop shells,
211
214
  extensions, Next.js client or server modules, and Node 20+. Its one runtime
212
215
  dependencies are `@ai-matrx/data` (the shared net-resilience + credentials
213
- layer) and `@ai-matrx/design-system` (the picker's primitives); `react >= 18`
216
+ layer), `@ai-matrx/design-system` (the picker's primitives) and
217
+ `@ai-matrx/associations` (the per-user star chokepoint); `react >= 18`
214
218
  is an optional peer needed only by `./react` and `./catalog/react`. No entry
215
219
  point performs work at import time.
216
220
 
@@ -186,6 +186,9 @@ var DEFAULT_AGENT_CATALOG_LABELS = {
186
186
  hoverHint: "Hover an agent to preview its details, or click to select."
187
187
  };
188
188
 
189
+ // catalog/store.ts
190
+ var import_core = require("@ai-matrx/associations/core");
191
+
189
192
  // catalog/data.ts
190
193
  var import_db = require("@ai-matrx/data/db");
191
194
 
@@ -235,7 +238,9 @@ function toAgentSummary(raw) {
235
238
  modelId: str(raw["model_id"]),
236
239
  isActive: bool(raw["is_active"]),
237
240
  isArchived: bool(raw["is_archived"]),
238
- isFavorite: bool(raw["is_favorite"]),
241
+ // Stars are per-person (platform.user_entity_state) and are overlaid by
242
+ // `overlayAgentFavorites` — a list row never carries the caller's star.
243
+ isFavorite: false,
239
244
  createdBy: str(raw["created_by"]),
240
245
  organizationId: str(raw["organization_id"]),
241
246
  taskId: str(raw["task_id"]),
@@ -344,12 +349,40 @@ async function readSingleAgentRow(client, agentId) {
344
349
  }
345
350
  return null;
346
351
  }
347
- async function writeAgentFavorite(client, agentId, isFavorite2) {
348
- const { error } = await client.schema("agent").from("definition").update({ is_favorite: isFavorite2 }).eq("id", agentId);
349
- if (error) {
352
+ var AGENT_FAVORITE_ENTITY_TYPE = "agent";
353
+ async function overlayAgentFavorites(favorites, rows, onError) {
354
+ if (rows.length === 0) return rows;
355
+ let starred = null;
356
+ try {
357
+ const result = await favorites.getBulk(
358
+ AGENT_FAVORITE_ENTITY_TYPE,
359
+ rows.map((r) => r.id)
360
+ );
361
+ if (result.ok) {
362
+ starred = new Set(
363
+ result.data.items.filter((s) => s.isFavorite).map((s) => s.entityId)
364
+ );
365
+ } else {
366
+ onError(result.error.message);
367
+ }
368
+ } catch (e) {
369
+ onError(e instanceof Error ? e.message : String(e));
370
+ }
371
+ return rows.map((r) => {
372
+ const isFavorite2 = starred?.has(r.id) ?? false;
373
+ return r.isFavorite === isFavorite2 ? r : { ...r, isFavorite: isFavorite2 };
374
+ });
375
+ }
376
+ async function writeAgentFavorite(favorites, agentId, isFavorite2) {
377
+ const result = await favorites.setFavorite(
378
+ AGENT_FAVORITE_ENTITY_TYPE,
379
+ agentId,
380
+ isFavorite2
381
+ );
382
+ if (!result.ok) {
350
383
  throw new AgentCatalogReadError(
351
- "agent.definition.is_favorite",
352
- pgDetail(error)
384
+ "user_entity_state (ues_set)",
385
+ result.error.code ? `${result.error.message} (${result.error.code})` : result.error.message
353
386
  );
354
387
  }
355
388
  }
@@ -563,7 +596,7 @@ async function resolveDefaultRow(args) {
563
596
  remedy: `bind the ${verdict.provenance} rung to an agent`
564
597
  });
565
598
  }
566
- let holder = lookupRow(holderId);
599
+ let holder = await lookupRow(holderId);
567
600
  if (!holder) {
568
601
  holder = await readSingleAgentRow(client, holderId) ?? void 0;
569
602
  }
@@ -617,7 +650,9 @@ var SELF_TEST_MISSING_RPC = "agx_this_function_does_not_exist_probe";
617
650
  var DEMANDED_RPCS = {
618
651
  agx_get_list_full: {},
619
652
  agx_search: { p_query: "__probe__", p_deep: false, p_limit: 1, p_offset: 0 },
620
- agx_resolve_agent_address: { p_ids: [BAD_UUID] }
653
+ agx_resolve_agent_address: { p_ids: [BAD_UUID] },
654
+ // The caller's stars. Read-only, and an impossible id touches no row.
655
+ ues_get_bulk: { p_entity_type: "agent", p_entity_ids: [BAD_UUID] }
621
656
  };
622
657
  function isMissingFunctionError(error) {
623
658
  if (!error || typeof error !== "object") return false;
@@ -625,11 +660,7 @@ function isMissingFunctionError(error) {
625
660
  return code === "PGRST202" || code === "42883";
626
661
  }
627
662
  async function assertAgentCatalogSchema(client, options = {}) {
628
- const {
629
- selfTest = false,
630
- throwOnViolation = true,
631
- probeWrite = true
632
- } = options;
663
+ const { selfTest = false, throwOnViolation = true } = options;
633
664
  const names = Object.keys(DEMANDED_RPCS);
634
665
  if (selfTest) names.push(SELF_TEST_MISSING_RPC);
635
666
  const missing = [];
@@ -662,41 +693,22 @@ async function assertAgentCatalogSchema(client, options = {}) {
662
693
  );
663
694
  }
664
695
  }
665
- let favoriteWritable = null;
666
- if (probeWrite) {
667
- try {
668
- const { error } = await client.schema("agent").from("definition").update({ is_favorite: false }).eq("id", BAD_UUID);
669
- favoriteWritable = !isPermissionRefusal(error);
670
- } catch (e) {
671
- unreachable.push({ fn: "agent.definition.is_favorite", error: e });
672
- }
673
- }
674
696
  if (unreachable.length > 0) {
675
697
  throw new Error(
676
698
  `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.`
677
699
  );
678
700
  }
679
- const ok = missing.length === 0 && favoriteWritable !== false;
701
+ const ok = missing.length === 0;
680
702
  const report = {
681
703
  ok,
682
704
  missing,
683
705
  unreachable,
684
706
  answered,
685
- favoriteWritable,
686
707
  orchestraColumn
687
708
  };
688
709
  if (!ok && throwOnViolation) {
689
- const parts = [];
690
- if (missing.length > 0) {
691
- parts.push(
692
- `cannot answer ${missing.length} demanded function(s): ${missing.join(", ")}`
693
- );
694
- }
695
- if (favoriteWritable === false) {
696
- parts.push("refuses a write to agent.definition.is_favorite");
697
- }
698
710
  throw new Error(
699
- `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.`
711
+ `DEMANDED SCHEMA VIOLATION: the database this client points at cannot answer ${missing.length} demanded function(s): ${missing.join(", ")}. @ai-matrx/agents/catalog cannot render a correct picker against it \u2014 point the client at Matrx Main, or apply the agx_* migrations.`
700
712
  );
701
713
  }
702
714
  return report;
@@ -707,11 +719,6 @@ function readsOrchestraColumn(data) {
707
719
  (row) => typeof row === "object" && row !== null && Object.prototype.hasOwnProperty.call(row, "orchestra")
708
720
  );
709
721
  }
710
- function isPermissionRefusal(error) {
711
- if (!error) return false;
712
- const code = error.code;
713
- return code === "42501" || code === "42P01" || code === "PGRST205";
714
- }
715
722
 
716
723
  // catalog/store.ts
717
724
  var LIST_TTL_MS = 15 * 60 * 1e3;
@@ -748,13 +755,6 @@ function createAgentCatalog(config) {
748
755
  remedy: "pass `client` (a supabase-js client, or anything with rpc() and schema().from())"
749
756
  });
750
757
  }
751
- if (typeof config.client.schema !== "function") {
752
- throw new AgentCatalogConfigError({
753
- code: "client_cannot_write",
754
- message: "the client passed to createAgentCatalog has no schema() \u2014 the favorite write has nowhere to go",
755
- remedy: "pass a full supabase-js client"
756
- });
757
- }
758
758
  if (!config.identity || typeof config.identity.requireUserId !== "function") {
759
759
  throw new AgentCatalogConfigError({
760
760
  code: "missing_identity",
@@ -781,6 +781,21 @@ function createAgentCatalog(config) {
781
781
  const notifier = config.notifier;
782
782
  const storage = config.storage ?? defaultStorage();
783
783
  const transport = config.transport;
784
+ const favorites = config.favorites ?? (0, import_core.createAssociationsStore)({
785
+ // The catalog's client IS a supabase-js client; the associations
786
+ // data-source port is the same `rpc(fn, args)` shape, typed over its
787
+ // own demanded-RPC names.
788
+ dataSource: client,
789
+ identity,
790
+ errorSink
791
+ }).favorites;
792
+ function reportFavoriteReadFailure(message) {
793
+ errorSink({
794
+ code: "favorite_read_failed",
795
+ message: `your starred agents could not be read (${message}); every star is shown unset until the next catalogue load`,
796
+ context: { catalogId }
797
+ });
798
+ }
784
799
  const labels = {
785
800
  ...DEFAULT_AGENT_CATALOG_LABELS,
786
801
  ...config.labels ?? {}
@@ -845,7 +860,11 @@ function createAgentCatalog(config) {
845
860
  async function load() {
846
861
  publish({ ...state, status: "loading", error: null });
847
862
  try {
848
- const rows = await readAgentCatalogRows(client);
863
+ const rows = await overlayAgentFavorites(
864
+ favorites,
865
+ await readAgentCatalogRows(client),
866
+ reportFavoriteReadFailure
867
+ );
849
868
  replaceRows(rows);
850
869
  publish({ ...state, status: "succeeded", error: null });
851
870
  globalState.listFetchedAt.set(catalogId, Date.now());
@@ -928,7 +947,13 @@ function createAgentCatalog(config) {
928
947
  }
929
948
  async function searchServer(query, deep = false) {
930
949
  const result = await searchAgentsOnServer(client, { query, deep });
931
- mergeRows(result.rows);
950
+ mergeRows(
951
+ await overlayAgentFavorites(
952
+ favorites,
953
+ result.rows,
954
+ reportFavoriteReadFailure
955
+ )
956
+ );
932
957
  return result.ids;
933
958
  }
934
959
  async function setFavorite(agentId, isFavorite2) {
@@ -942,7 +967,7 @@ function createAgentCatalog(config) {
942
967
  }
943
968
  mergeRows([{ ...existing, isFavorite: isFavorite2 }]);
944
969
  try {
945
- await writeAgentFavorite(client, agentId, isFavorite2);
970
+ await writeAgentFavorite(favorites, agentId, isFavorite2);
946
971
  } catch (e) {
947
972
  mergeRows([existing]);
948
973
  errorSink({
@@ -994,7 +1019,14 @@ function createAgentCatalog(config) {
994
1019
  client,
995
1020
  storage,
996
1021
  errorSink,
997
- lookupRow: (id) => state.byId[id]
1022
+ lookupRow: async (id) => {
1023
+ const hit = state.byId[id];
1024
+ if (hit) return hit;
1025
+ const inFlight = globalState.listInFlight.get(catalogId);
1026
+ if (!inFlight) return void 0;
1027
+ await inFlight.catch(() => void 0);
1028
+ return state.byId[id];
1029
+ }
998
1030
  });
999
1031
  getCatalogGlobalState().defaultRows.set(
1000
1032
  `${catalogId}::${mandateKey}`,