@athenaintel/react 0.32.0 → 0.35.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.
Files changed (134) hide show
  1. package/README.md +99 -9
  2. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  3. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  4. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +2 -3
  5. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  6. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -4
  7. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  8. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  9. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  10. package/dist/agent-runtime/src/messages.cjs +57 -2
  11. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  12. package/dist/agent-runtime/src/messages.js +57 -2
  13. package/dist/agent-runtime/src/messages.js.map +1 -1
  14. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +24 -3
  15. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  16. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +24 -3
  17. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  18. package/dist/agent-runtime/src/statewire-transport.cjs +4 -13
  19. package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
  20. package/dist/agent-runtime/src/statewire-transport.js +5 -14
  21. package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
  22. package/dist/agent-runtime/src/tool-metadata.cjs +1 -1
  23. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  24. package/dist/agent-runtime/src/tool-metadata.js +1 -1
  25. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  26. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  27. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  28. package/dist/assets/AthenaAssetEmbed.cjs +3 -1
  29. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  30. package/dist/assets/AthenaAssetEmbed.d.ts +7 -0
  31. package/dist/assets/AthenaAssetEmbed.js +4 -2
  32. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  33. package/dist/assets/use-asset-embed.cjs +71 -71
  34. package/dist/assets/use-asset-embed.cjs.map +1 -1
  35. package/dist/assets/use-asset-embed.d.ts +20 -7
  36. package/dist/assets/use-asset-embed.js +72 -72
  37. package/dist/assets/use-asset-embed.js.map +1 -1
  38. package/dist/catalog/agent-model-options.cjs +122 -0
  39. package/dist/catalog/agent-model-options.cjs.map +1 -0
  40. package/dist/catalog/agent-model-options.d.ts +115 -0
  41. package/dist/catalog/agent-model-options.js +122 -0
  42. package/dist/catalog/agent-model-options.js.map +1 -0
  43. package/dist/catalog/chat-pickers.cjs +184 -4
  44. package/dist/catalog/chat-pickers.cjs.map +1 -1
  45. package/dist/catalog/chat-pickers.d.ts +27 -3
  46. package/dist/catalog/chat-pickers.js +187 -7
  47. package/dist/catalog/chat-pickers.js.map +1 -1
  48. package/dist/catalog/runtime-catalog.cjs +117 -3
  49. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  50. package/dist/catalog/runtime-catalog.d.ts +104 -0
  51. package/dist/catalog/runtime-catalog.js +119 -5
  52. package/dist/catalog/runtime-catalog.js.map +1 -1
  53. package/dist/chat/AthenaChat.cjs.map +1 -1
  54. package/dist/chat/AthenaChat.d.ts +8 -7
  55. package/dist/chat/AthenaChat.js.map +1 -1
  56. package/dist/chat/super-grouping/SuperGroupingCard.cjs +30 -3
  57. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  58. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +12 -9
  59. package/dist/chat/super-grouping/SuperGroupingCard.js +31 -4
  60. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  61. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  62. package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +8 -8
  63. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  64. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  65. package/dist/chat/super-grouping/activity-timeline.d.ts +4 -4
  66. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  67. package/dist/chat/super-grouping/index.d.ts +6 -5
  68. package/dist/chat/super-grouping/toolkit-map.cjs +3 -1
  69. package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
  70. package/dist/chat/super-grouping/toolkit-map.js +3 -1
  71. package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
  72. package/dist/chat-ui/index.cjs +1 -0
  73. package/dist/chat-ui/index.cjs.map +1 -1
  74. package/dist/chat-ui/index.d.ts +1 -1
  75. package/dist/chat-ui/index.js +2 -1
  76. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +33 -2
  77. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  78. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +14 -0
  79. package/dist/chat-ui/mentions/suggestions/data/api-client.js +33 -2
  80. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  81. package/dist/index.cjs +1 -0
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.ts +3 -2
  84. package/dist/index.js +2 -1
  85. package/dist/lib/use-athena-rest-query.cjs +4 -0
  86. package/dist/lib/use-athena-rest-query.cjs.map +1 -1
  87. package/dist/lib/use-athena-rest-query.d.ts +6 -0
  88. package/dist/lib/use-athena-rest-query.js +4 -0
  89. package/dist/lib/use-athena-rest-query.js.map +1 -1
  90. package/dist/provider/AthenaProvider.cjs +29 -8
  91. package/dist/provider/AthenaProvider.cjs.map +1 -1
  92. package/dist/provider/AthenaProvider.d.ts +14 -4
  93. package/dist/provider/AthenaProvider.js +31 -10
  94. package/dist/provider/AthenaProvider.js.map +1 -1
  95. package/dist/provider/agent-selection-context.cjs +6 -0
  96. package/dist/provider/agent-selection-context.cjs.map +1 -0
  97. package/dist/provider/agent-selection-context.d.ts +14 -0
  98. package/dist/provider/agent-selection-context.js +6 -0
  99. package/dist/provider/agent-selection-context.js.map +1 -0
  100. package/dist/react/package.json.cjs +1 -1
  101. package/dist/react/package.json.js +1 -1
  102. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +125 -0
  103. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -0
  104. package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +54 -0
  105. package/dist/runtime/StatewireThreadConfigLaneSync.js +125 -0
  106. package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -0
  107. package/dist/runtime/statewire-model-lane.cjs +0 -12
  108. package/dist/runtime/statewire-model-lane.cjs.map +1 -1
  109. package/dist/runtime/statewire-model-lane.d.ts +3 -1
  110. package/dist/runtime/statewire-model-lane.js +0 -12
  111. package/dist/runtime/statewire-model-lane.js.map +1 -1
  112. package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
  113. package/dist/runtime/statewire-server-lane-context.d.ts +2 -2
  114. package/dist/runtime/statewire-server-lane-context.js.map +1 -1
  115. package/dist/runtime/statewire-thread-config-lane.cjs +84 -0
  116. package/dist/runtime/statewire-thread-config-lane.cjs.map +1 -0
  117. package/dist/runtime/statewire-thread-config-lane.d.ts +94 -0
  118. package/dist/runtime/statewire-thread-config-lane.js +84 -0
  119. package/dist/runtime/statewire-thread-config-lane.js.map +1 -0
  120. package/dist/runtime/useAthenaStatewireRuntime.cjs +2 -2
  121. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  122. package/dist/runtime/useAthenaStatewireRuntime.js +2 -2
  123. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  124. package/dist/threads/use-athena-thread-model.cjs +11 -3
  125. package/dist/threads/use-athena-thread-model.cjs.map +1 -1
  126. package/dist/threads/use-athena-thread-model.d.ts +5 -0
  127. package/dist/threads/use-athena-thread-model.js +12 -4
  128. package/dist/threads/use-athena-thread-model.js.map +1 -1
  129. package/package.json +3 -3
  130. package/dist/runtime/StatewireModelLaneSync.cjs +0 -96
  131. package/dist/runtime/StatewireModelLaneSync.cjs.map +0 -1
  132. package/dist/runtime/StatewireModelLaneSync.d.ts +0 -45
  133. package/dist/runtime/StatewireModelLaneSync.js +0 -96
  134. package/dist/runtime/StatewireModelLaneSync.js.map +0 -1
@@ -1,3 +1,6 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import { type MentionAuthContext } from '../chat-ui/mentions/suggestions/data/api-client';
3
+ import { type AgentModelSource, type AthenaAgentModelOption } from './agent-model-options';
1
4
  /**
2
5
  * The workspace's runtime catalog for a chat's model and agent pickers: the models the signed-in
3
6
  * person may run (the workspace's allow or deny list, admin-only models for admins), and the
@@ -96,5 +99,106 @@ export declare function credentialFingerprint({ credential }: {
96
99
  }): string;
97
100
  /** The models the signed-in person may pick (`normalizeModelCatalog`). */
98
101
  export declare function useAthenaModelCatalog(): import("@tanstack/react-query").UseQueryResult<AthenaModelOption[], Error>;
102
+ /** The model catalog's query on a given client (one client for every read a hook makes). */
103
+ declare function useModelCatalogQuery({ auth, principal, queryClient, }: {
104
+ auth: MentionAuthContext;
105
+ principal: string;
106
+ queryClient: QueryClient;
107
+ }): import("@tanstack/react-query").UseQueryResult<AthenaModelOption[], Error>;
99
108
  /** The published collab agents the signed-in person can see (`normalizeAgentCatalog`). */
100
109
  export declare function useAthenaAgentCatalog(): import("@tanstack/react-query").UseQueryResult<AthenaAgentOption[], Error>;
110
+ export declare const ATHENA_AGENT_MODELS_QUERY = "\n query AthenaAgentModels($assetId: String!) {\n getAssetById(assetId: $assetId, withMetadata: true) { athenaMetadata }\n }\n";
111
+ /** What reading the agent's published models found: its models, or that this person cannot know them. */
112
+ export type AgentModelRead = {
113
+ readable: true;
114
+ source: AgentModelSource | null;
115
+ } | {
116
+ readable: false;
117
+ };
118
+ /**
119
+ * Where `useAthenaAgentModelOptions` stands:
120
+ *
121
+ * - `idle`: no agent given;
122
+ * - `loading`: the agent (or the model catalog that names its models) is being read;
123
+ * - `ready`: the agent's published models are known;
124
+ * - `unavailable`: this person cannot know them: no VIEW on the agent, no such
125
+ * agent, or one never published (or whose published definition names no
126
+ * model). Not an error: `allowAnyModel` stays `true`, so a picker keeps the
127
+ * workspace's models;
128
+ * - `error`: the read failed (network, server); `allowAnyModel` stays `true`.
129
+ */
130
+ export type AthenaAgentModelOptionsStatus = 'idle' | 'loading' | 'ready' | 'unavailable' | 'error';
131
+ export interface AthenaAgentModelOptions {
132
+ status: AthenaAgentModelOptionsStatus;
133
+ /** The agent's model choices (see {@link AthenaAgentModelOption}); empty unless `ready`. */
134
+ options: readonly AthenaAgentModelOption[];
135
+ /**
136
+ * The model the thread runs while it pins none: the channel's override, else
137
+ * the agent's own model. `null` unless `ready`.
138
+ */
139
+ defaultModel: string | null;
140
+ /**
141
+ * Whether people may pick any workspace model with this agent: the agent's
142
+ * "Allow any workspace model" switch (`allowAnyModel` in its published
143
+ * definition). Only an explicit `false` restricts a picker to `options`;
144
+ * absent, `null` or `true` (every agent saved before the switch) allow any,
145
+ * and so does an agent this person cannot read. `true` unless `ready`.
146
+ */
147
+ allowAnyModel: boolean;
148
+ }
149
+ /**
150
+ * A selected collab agent's own model choices, and whether the agent restricts
151
+ * a picker to them (`allowAnyModel: false`, the agent's "Allow any workspace
152
+ * model" switch turned off). Restriction is opt-in per agent: with
153
+ * `allowAnyModel` true (the default) a picker keeps the workspace's models and
154
+ * can still show `defaultModel` as the agent's own; `ChatModelPicker` does
155
+ * both.
156
+ *
157
+ * `agent` is the agent's asset id or its `collab_agent:<id>` ref (`null`:
158
+ * none, `idle`). `channel` is the collab channel the chat runs on: its model
159
+ * override is the default there. The rules are in `agent-model-options.ts`.
160
+ *
161
+ * The agent is read through `getAssetById(withMetadata: true)`, the
162
+ * permission-checked asset read (VIEW on the agent), with the provider's
163
+ * credentials: a person without VIEW gets `unavailable` with no options. The
164
+ * model the thread pins comes from `useAthenaThreadModel()` (inside
165
+ * `<AthenaProvider>`; none outside one): a pinned model outside the agent's
166
+ * list is an option with `pinnedOutside`.
167
+ *
168
+ * Picking the `isDefault` option means "no model": hand the provider
169
+ * `model={undefined}` so the agent's (or channel's) default runs, and a session
170
+ * pinning another model is unpinned.
171
+ *
172
+ * While shown, the agent is read again every
173
+ * {@link AGENT_MODELS_REFRESH_MS}: an author publishing new models elsewhere
174
+ * invalidates nothing here.
175
+ */
176
+ export declare function useAthenaAgentModelOptions({ agent, channel, }: {
177
+ agent: string | null | undefined;
178
+ channel?: string | null;
179
+ }): AthenaAgentModelOptions;
180
+ /** How often an agent's published models are read again while a hook shows them. */
181
+ export declare const AGENT_MODELS_REFRESH_MS: number;
182
+ /**
183
+ * The re-read cadence of an agent model read: every
184
+ * {@link AGENT_MODELS_REFRESH_MS} while it answers, never for a denial (asking
185
+ * again answers the same).
186
+ */
187
+ export declare function agentModelsRefetchInterval({ data, }: {
188
+ data: AgentModelRead | undefined;
189
+ }): number | false;
190
+ /**
191
+ * {@link useAthenaAgentModelOptions} plus the catalog label of any model id,
192
+ * from the same query client and catalog read (a picker needs both; reading
193
+ * the catalog again through its own client would fetch it twice). Internal.
194
+ */
195
+ export declare function useAgentModelChoices({ agent, channel, }: {
196
+ agent: string | null | undefined;
197
+ channel: string | null;
198
+ }): {
199
+ choices: AthenaAgentModelOptions;
200
+ modelLabel: (model: string) => string;
201
+ /** The workspace model catalog, read through the same client as the agent. */
202
+ catalog: ReturnType<typeof useModelCatalogQuery>;
203
+ };
204
+ export {};
@@ -1,8 +1,10 @@
1
1
  import { useQuery, QueryClientContext, QueryClient } from "@tanstack/react-query";
2
- import { useMemo, useContext, useState } from "react";
2
+ import { useMemo, useContext, useState, useCallback } from "react";
3
3
  import { AthenaAuthContext } from "../auth/AthenaAuthContext.js";
4
- import { fetchGraphQL } from "../chat-ui/mentions/suggestions/data/api-client.js";
4
+ import { fetchGraphQL, AthenaGraphQLError } from "../chat-ui/mentions/suggestions/data/api-client.js";
5
5
  import { useAthenaConfig } from "../provider/AthenaContext.js";
6
+ import { useOptionalAthenaThreadModel } from "../threads/use-athena-thread-model.js";
7
+ import { agentAssetIdOf, publishedAgentModelSource, buildAgentModelOptions } from "./agent-model-options.js";
6
8
  const MODEL_PROVIDER_LABELS = {
7
9
  ANTHROPIC: "Anthropic",
8
10
  OPENAI: "OpenAI",
@@ -134,9 +136,17 @@ function useCatalogQueryClient() {
134
136
  return host ?? own;
135
137
  }
136
138
  function useAthenaModelCatalog() {
137
- const auth = useCatalogAuth();
138
- const principal = useCatalogPrincipal();
139
- const queryClient = useCatalogQueryClient();
139
+ return useModelCatalogQuery({
140
+ auth: useCatalogAuth(),
141
+ principal: useCatalogPrincipal(),
142
+ queryClient: useCatalogQueryClient()
143
+ });
144
+ }
145
+ function useModelCatalogQuery({
146
+ auth,
147
+ principal,
148
+ queryClient
149
+ }) {
140
150
  return useQuery(
141
151
  {
142
152
  queryKey: ["athena-sdk", "catalog", "models", auth.backendUrl, principal],
@@ -166,16 +176,120 @@ function useAthenaAgentCatalog() {
166
176
  queryClient
167
177
  );
168
178
  }
179
+ const ATHENA_AGENT_MODELS_QUERY = `
180
+ query AthenaAgentModels($assetId: String!) {
181
+ getAssetById(assetId: $assetId, withMetadata: true) { athenaMetadata }
182
+ }
183
+ `;
184
+ const AGENT_READ_DENIAL_CODES = /* @__PURE__ */ new Set([
185
+ "UNAUTHORIZED",
186
+ "FORBIDDEN",
187
+ "WORKSPACE_MISMATCH"
188
+ ]);
189
+ const NO_AGENT_MODEL_OPTIONS = {
190
+ idle: { status: "idle", options: [], defaultModel: null, allowAnyModel: true },
191
+ loading: { status: "loading", options: [], defaultModel: null, allowAnyModel: true },
192
+ unavailable: { status: "unavailable", options: [], defaultModel: null, allowAnyModel: true },
193
+ error: { status: "error", options: [], defaultModel: null, allowAnyModel: true }
194
+ };
195
+ function isAgentReadDenial(error) {
196
+ return error instanceof AthenaGraphQLError && error.code !== null && AGENT_READ_DENIAL_CODES.has(error.code);
197
+ }
198
+ function useAthenaAgentModelOptions({
199
+ agent,
200
+ channel = null
201
+ }) {
202
+ return useAgentModelChoices({ agent, channel }).choices;
203
+ }
204
+ const AGENT_MODELS_REFRESH_MS = 60 * 1e3;
205
+ function agentModelsRefetchInterval({
206
+ data
207
+ }) {
208
+ return data !== void 0 && !data.readable ? false : AGENT_MODELS_REFRESH_MS;
209
+ }
210
+ function useAgentModelChoices({
211
+ agent,
212
+ channel
213
+ }) {
214
+ const assetId = agentAssetIdOf(agent);
215
+ const auth = useCatalogAuth();
216
+ const principal = useCatalogPrincipal();
217
+ const queryClient = useCatalogQueryClient();
218
+ const read = useQuery(
219
+ {
220
+ queryKey: ["athena-sdk", "catalog", "agent-models", auth.backendUrl, principal, assetId],
221
+ queryFn: async () => {
222
+ try {
223
+ const data = await fetchGraphQL(
224
+ auth,
225
+ ATHENA_AGENT_MODELS_QUERY,
226
+ { assetId }
227
+ );
228
+ if (data.getAssetById === null) return { readable: false };
229
+ return {
230
+ readable: true,
231
+ source: publishedAgentModelSource(data.getAssetById.athenaMetadata)
232
+ };
233
+ } catch (error) {
234
+ if (isAgentReadDenial(error)) return { readable: false };
235
+ throw error;
236
+ }
237
+ },
238
+ enabled: assetId !== null,
239
+ staleTime: AGENT_MODELS_REFRESH_MS,
240
+ refetchInterval: (query) => agentModelsRefetchInterval({ data: query.state.data })
241
+ },
242
+ queryClient
243
+ );
244
+ const catalog = useModelCatalogQuery({ auth, principal, queryClient });
245
+ const threadModel = useOptionalAthenaThreadModel();
246
+ const pinnedModel = threadModel !== null && threadModel.ready && threadModel.configured ? threadModel.model : null;
247
+ const trimmedChannel = (channel == null ? void 0 : channel.trim()) || null;
248
+ const models = catalog.data;
249
+ const catalogPending = catalog.isPending;
250
+ const { isPending: readPending, data: readData } = read;
251
+ const modelLabel = useCallback(
252
+ (model) => {
253
+ var _a;
254
+ return ((_a = models == null ? void 0 : models.find((option) => option.id === model)) == null ? void 0 : _a.label) ?? model;
255
+ },
256
+ [models]
257
+ );
258
+ const choices = useMemo(() => {
259
+ if (assetId === null) return NO_AGENT_MODEL_OPTIONS.idle;
260
+ if (readData === void 0) {
261
+ return readPending ? NO_AGENT_MODEL_OPTIONS.loading : NO_AGENT_MODEL_OPTIONS.error;
262
+ }
263
+ if (!readData.readable || readData.source === null) return NO_AGENT_MODEL_OPTIONS.unavailable;
264
+ if (catalogPending) return NO_AGENT_MODEL_OPTIONS.loading;
265
+ return {
266
+ status: "ready",
267
+ ...buildAgentModelOptions({
268
+ source: readData.source,
269
+ channel: trimmedChannel,
270
+ pinnedModel,
271
+ modelLabel
272
+ }),
273
+ allowAnyModel: readData.source.allowAnyModel
274
+ };
275
+ }, [assetId, readPending, readData, catalogPending, modelLabel, trimmedChannel, pinnedModel]);
276
+ return useMemo(() => ({ choices, modelLabel, catalog }), [choices, modelLabel, catalog]);
277
+ }
169
278
  export {
279
+ AGENT_MODELS_REFRESH_MS,
170
280
  ATHENA_AGENT_CATALOG_QUERY,
281
+ ATHENA_AGENT_MODELS_QUERY,
171
282
  ATHENA_MODEL_CATALOG_QUERY,
172
283
  MODEL_PROVIDER_LABELS,
284
+ agentModelsRefetchInterval,
173
285
  credentialFingerprint,
174
286
  groupModelsByProvider,
175
287
  normalizeAgentCatalog,
176
288
  normalizeModelCatalog,
177
289
  resolveCatalogModelId,
290
+ useAgentModelChoices,
178
291
  useAthenaAgentCatalog,
292
+ useAthenaAgentModelOptions,
179
293
  useAthenaModelCatalog
180
294
  };
181
295
  //# sourceMappingURL=runtime-catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-catalog.js","sources":["../../src/catalog/runtime-catalog.ts"],"sourcesContent":["import { QueryClient, QueryClientContext, useQuery } from '@tanstack/react-query';\nimport { useContext, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport { fetchGraphQL, type MentionAuthContext } from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useAthenaConfig } from '../provider/AthenaContext';\n\n/**\n * The workspace's runtime catalog for a chat's model and agent pickers: the models the signed-in\n * person may run (the workspace's allow or deny list, admin-only models for admins), and the\n * published collab agents they can see. The rules are the Chrome extension's, which every host now\n * reads from here.\n */\n\nexport type AthenaModelStatus = 'ACTIVE' | 'LEGACY' | 'RECOMMENDED';\n\nexport interface AthenaModelOption {\n id: string;\n label: string;\n description: string | null;\n /** Upper-case provider key, e.g. `ANTHROPIC`, `OPENAI`. */\n provider: string;\n status: AthenaModelStatus;\n sortOrder: number;\n familyId: string;\n familyName: string;\n isFamilyDefault: boolean;\n isFeatured: boolean;\n variantOrder: number;\n}\n\nexport interface AthenaAgentOption {\n /** The collab agent's asset id; pass `collab_agent:<id>` as the provider's `agent`. */\n id: string;\n name: string;\n}\n\n/** The provider labels a model picker groups by. */\nexport const MODEL_PROVIDER_LABELS: Readonly<Record<string, string>> = {\n ANTHROPIC: 'Anthropic',\n OPENAI: 'OpenAI',\n GOOGLE: 'Google',\n XAI: 'xAI',\n META: 'Meta',\n MISTRAL: 'Mistral',\n DEEPSEEK: 'DeepSeek',\n QWEN: 'Qwen',\n MOONSHOT: 'Moonshot',\n MINIMAX: 'MiniMax',\n ZAI: 'Z.ai',\n};\n\nexport const ATHENA_MODEL_CATALOG_QUERY = `\n query AthenaModelCatalog {\n getCurrentUserWithWorkspace { user { isAdmin } }\n settings { workspace { approvedLargeLlms blacklistedLlms } }\n availableModels {\n id name provider status description adminOnly sortOrder\n familyId familyName isFamilyDefault isFeatured variantOrder\n }\n }\n`;\n\nexport const ATHENA_AGENT_CATALOG_QUERY = `\n query AthenaAgentCatalog {\n getAllAssets(filterByAthenaOriginalType: [\"collab_agent\"]) { id title }\n }\n`;\n\nexport interface AthenaModelCatalogResponse {\n getCurrentUserWithWorkspace: { user: { isAdmin: boolean } };\n settings: { workspace: { approvedLargeLlms: string[]; blacklistedLlms: string[] } };\n availableModels: Array<{\n id: string;\n name: string;\n provider: string;\n status: AthenaModelStatus;\n description: string | null;\n adminOnly: boolean;\n sortOrder: number;\n familyId: string;\n familyName: string;\n isFamilyDefault: boolean;\n isFeatured: boolean;\n variantOrder: number;\n }>;\n}\n\n/**\n * The models the person may pick, in catalog order. A workspace with an allow list offers only\n * those; otherwise everything except its deny list. Admin-only models are offered to admins only.\n */\nexport function normalizeModelCatalog({\n response,\n}: {\n response: AthenaModelCatalogResponse;\n}): AthenaModelOption[] {\n const isAdmin = response.getCurrentUserWithWorkspace.user.isAdmin;\n const approved = new Set(response.settings.workspace.approvedLargeLlms);\n const denied = new Set(response.settings.workspace.blacklistedLlms);\n const hasAllowlist = approved.size > 0;\n return response.availableModels\n .filter(\n (model) =>\n (!model.adminOnly || isAdmin) && (hasAllowlist ? approved.has(model.id) : !denied.has(model.id)),\n )\n .map(\n (model): AthenaModelOption => ({\n id: model.id,\n label: model.name,\n description: model.description,\n provider: model.provider,\n status: model.status,\n sortOrder: model.sortOrder,\n familyId: model.familyId,\n familyName: model.familyName,\n isFamilyDefault: model.isFamilyDefault,\n isFeatured: model.isFeatured,\n variantOrder: model.variantOrder,\n }),\n )\n .sort(\n (left, right) =>\n left.sortOrder - right.sortOrder ||\n left.variantOrder - right.variantOrder ||\n left.label.localeCompare(right.label),\n );\n}\n\n/** The published collab agents, named and sorted; assets with a blank id are dropped. */\nexport function normalizeAgentCatalog({\n assets,\n}: {\n assets: ReadonlyArray<{ id: string; title: string | null }>;\n}): AthenaAgentOption[] {\n return assets\n .filter((asset) => asset.id.trim().length > 0)\n .map((asset) => ({ id: asset.id, name: asset.title?.trim() || 'Untitled agent' }))\n .sort((left, right) => left.name.localeCompare(right.name));\n}\n\n/**\n * The model a picker shows as chosen: the stored choice while the catalog offers it, else the\n * default (unless retired), else a recommended family default, else any live model. While the\n * catalog is empty (loading, or unreachable) the stored choice or the default stands.\n */\nexport function resolveCatalogModelId({\n stored,\n defaultModelId,\n models,\n}: {\n stored: string | null;\n defaultModelId: string;\n models: readonly AthenaModelOption[];\n}): string {\n if (stored && models.some((model) => model.id === stored)) return stored;\n return (\n (\n models.find((model) => model.id === defaultModelId && model.status !== 'LEGACY') ??\n models.find((model) => model.status === 'RECOMMENDED' && model.isFamilyDefault) ??\n models.find((model) => model.status !== 'LEGACY' && model.isFamilyDefault) ??\n models.find((model) => model.status !== 'LEGACY') ??\n models[0]\n )?.id ?? (stored || defaultModelId)\n );\n}\n\n/** Models grouped under their provider's label, in catalog order. */\nexport function groupModelsByProvider({\n models,\n}: {\n models: readonly AthenaModelOption[];\n}): Array<{ provider: string; models: AthenaModelOption[] }> {\n const groups = new Map<string, AthenaModelOption[]>();\n for (const model of models) {\n const label = MODEL_PROVIDER_LABELS[model.provider] ?? model.provider;\n groups.set(label, [...(groups.get(label) ?? []), model]);\n }\n return Array.from(groups, ([provider, grouped]) => ({ provider, models: grouped }));\n}\n\n/** The provider's credentials as the SDK's GraphQL client takes them. */\nfunction useCatalogAuth(): MentionAuthContext {\n const config = useAthenaConfig();\n return useMemo<MentionAuthContext>(\n () => ({\n backendUrl: config.backendUrl,\n appUrl: config.appUrl,\n apiKey: config.apiKey,\n credentials: 'include',\n get accessToken() {\n return config.token ?? undefined;\n },\n getAccessToken: async () => (await config.getToken?.()) ?? undefined,\n renewAccessToken: async () => (await config.getToken?.({ force: true })) ?? undefined,\n }),\n [config],\n );\n}\n\n/**\n * A short fingerprint (two FNV-1a rounds, 64 bits) of a credential: it tells accounts apart in an\n * in-memory cache key without the credential itself, or anything it could be recovered from,\n * entering the key.\n */\nexport function credentialFingerprint({ credential }: { credential: string }): string {\n const round = (seed: number) => {\n let hash = seed;\n for (let index = 0; index < credential.length; index += 1) {\n hash ^= credential.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, '0');\n };\n return `${round(0x811c9dc5)}${round(0x01000193)}`;\n}\n\n/**\n * Who is asking, for the cache key: the catalog differs per account (admin-only models, the\n * workspace's lists, the agents shared with them), and a host can switch accounts while keeping its\n * query client. The signed-in user's id when the SDK knows it, else a fingerprint of the credential\n * in use. Never the credential itself.\n */\nfunction useCatalogPrincipal(): string {\n const config = useAthenaConfig();\n const userId = useContext(AthenaAuthContext)?.user?.userId;\n if (userId) return `user:${userId}`;\n if (config.apiKey) return `key:${credentialFingerprint({ credential: config.apiKey })}`;\n if (config.token) return `token:${credentialFingerprint({ credential: config.token })}`;\n return 'session';\n}\n\n/**\n * The host's QueryClient when there is one (the thread list provides one), else one of the\n * pickers' own, so the catalog hooks work with or without the thread list.\n */\nfunction useCatalogQueryClient(): QueryClient {\n const host = useContext(QueryClientContext);\n const [own] = useState(() => new QueryClient());\n return host ?? own;\n}\n\n/** The models the signed-in person may pick (`normalizeModelCatalog`). */\nexport function useAthenaModelCatalog() {\n const auth = useCatalogAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n return useQuery(\n {\n queryKey: ['athena-sdk', 'catalog', 'models', auth.backendUrl, principal],\n queryFn: async () =>\n normalizeModelCatalog({\n response: await fetchGraphQL<AthenaModelCatalogResponse>(auth, ATHENA_MODEL_CATALOG_QUERY),\n }),\n staleTime: 5 * 60 * 1000,\n },\n queryClient,\n );\n}\n\n/** The published collab agents the signed-in person can see (`normalizeAgentCatalog`). */\nexport function useAthenaAgentCatalog() {\n const auth = useCatalogAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n return useQuery(\n {\n queryKey: ['athena-sdk', 'catalog', 'agents', auth.backendUrl, principal],\n queryFn: async () =>\n normalizeAgentCatalog({\n assets:\n (\n await fetchGraphQL<{ getAllAssets: Array<{ id: string; title: string | null }> }>(\n auth,\n ATHENA_AGENT_CATALOG_QUERY,\n )\n ).getAllAssets ?? [],\n }),\n staleTime: 60 * 1000,\n },\n queryClient,\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-catalog.js","sources":["../../src/catalog/runtime-catalog.ts"],"sourcesContent":["import { QueryClient, QueryClientContext, useQuery } from '@tanstack/react-query';\nimport { useCallback, useContext, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n AthenaGraphQLError,\n fetchGraphQL,\n type MentionAuthContext,\n} from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport { useOptionalAthenaThreadModel } from '../threads/use-athena-thread-model';\nimport {\n type AgentModelSource,\n type AthenaAgentModelOption,\n agentAssetIdOf,\n buildAgentModelOptions,\n publishedAgentModelSource,\n} from './agent-model-options';\n\n/**\n * The workspace's runtime catalog for a chat's model and agent pickers: the models the signed-in\n * person may run (the workspace's allow or deny list, admin-only models for admins), and the\n * published collab agents they can see. The rules are the Chrome extension's, which every host now\n * reads from here.\n */\n\nexport type AthenaModelStatus = 'ACTIVE' | 'LEGACY' | 'RECOMMENDED';\n\nexport interface AthenaModelOption {\n id: string;\n label: string;\n description: string | null;\n /** Upper-case provider key, e.g. `ANTHROPIC`, `OPENAI`. */\n provider: string;\n status: AthenaModelStatus;\n sortOrder: number;\n familyId: string;\n familyName: string;\n isFamilyDefault: boolean;\n isFeatured: boolean;\n variantOrder: number;\n}\n\nexport interface AthenaAgentOption {\n /** The collab agent's asset id; pass `collab_agent:<id>` as the provider's `agent`. */\n id: string;\n name: string;\n}\n\n/** The provider labels a model picker groups by. */\nexport const MODEL_PROVIDER_LABELS: Readonly<Record<string, string>> = {\n ANTHROPIC: 'Anthropic',\n OPENAI: 'OpenAI',\n GOOGLE: 'Google',\n XAI: 'xAI',\n META: 'Meta',\n MISTRAL: 'Mistral',\n DEEPSEEK: 'DeepSeek',\n QWEN: 'Qwen',\n MOONSHOT: 'Moonshot',\n MINIMAX: 'MiniMax',\n ZAI: 'Z.ai',\n};\n\nexport const ATHENA_MODEL_CATALOG_QUERY = `\n query AthenaModelCatalog {\n getCurrentUserWithWorkspace { user { isAdmin } }\n settings { workspace { approvedLargeLlms blacklistedLlms } }\n availableModels {\n id name provider status description adminOnly sortOrder\n familyId familyName isFamilyDefault isFeatured variantOrder\n }\n }\n`;\n\nexport const ATHENA_AGENT_CATALOG_QUERY = `\n query AthenaAgentCatalog {\n getAllAssets(filterByAthenaOriginalType: [\"collab_agent\"]) { id title }\n }\n`;\n\nexport interface AthenaModelCatalogResponse {\n getCurrentUserWithWorkspace: { user: { isAdmin: boolean } };\n settings: { workspace: { approvedLargeLlms: string[]; blacklistedLlms: string[] } };\n availableModels: Array<{\n id: string;\n name: string;\n provider: string;\n status: AthenaModelStatus;\n description: string | null;\n adminOnly: boolean;\n sortOrder: number;\n familyId: string;\n familyName: string;\n isFamilyDefault: boolean;\n isFeatured: boolean;\n variantOrder: number;\n }>;\n}\n\n/**\n * The models the person may pick, in catalog order. A workspace with an allow list offers only\n * those; otherwise everything except its deny list. Admin-only models are offered to admins only.\n */\nexport function normalizeModelCatalog({\n response,\n}: {\n response: AthenaModelCatalogResponse;\n}): AthenaModelOption[] {\n const isAdmin = response.getCurrentUserWithWorkspace.user.isAdmin;\n const approved = new Set(response.settings.workspace.approvedLargeLlms);\n const denied = new Set(response.settings.workspace.blacklistedLlms);\n const hasAllowlist = approved.size > 0;\n return response.availableModels\n .filter(\n (model) =>\n (!model.adminOnly || isAdmin) && (hasAllowlist ? approved.has(model.id) : !denied.has(model.id)),\n )\n .map(\n (model): AthenaModelOption => ({\n id: model.id,\n label: model.name,\n description: model.description,\n provider: model.provider,\n status: model.status,\n sortOrder: model.sortOrder,\n familyId: model.familyId,\n familyName: model.familyName,\n isFamilyDefault: model.isFamilyDefault,\n isFeatured: model.isFeatured,\n variantOrder: model.variantOrder,\n }),\n )\n .sort(\n (left, right) =>\n left.sortOrder - right.sortOrder ||\n left.variantOrder - right.variantOrder ||\n left.label.localeCompare(right.label),\n );\n}\n\n/** The published collab agents, named and sorted; assets with a blank id are dropped. */\nexport function normalizeAgentCatalog({\n assets,\n}: {\n assets: ReadonlyArray<{ id: string; title: string | null }>;\n}): AthenaAgentOption[] {\n return assets\n .filter((asset) => asset.id.trim().length > 0)\n .map((asset) => ({ id: asset.id, name: asset.title?.trim() || 'Untitled agent' }))\n .sort((left, right) => left.name.localeCompare(right.name));\n}\n\n/**\n * The model a picker shows as chosen: the stored choice while the catalog offers it, else the\n * default (unless retired), else a recommended family default, else any live model. While the\n * catalog is empty (loading, or unreachable) the stored choice or the default stands.\n */\nexport function resolveCatalogModelId({\n stored,\n defaultModelId,\n models,\n}: {\n stored: string | null;\n defaultModelId: string;\n models: readonly AthenaModelOption[];\n}): string {\n if (stored && models.some((model) => model.id === stored)) return stored;\n return (\n (\n models.find((model) => model.id === defaultModelId && model.status !== 'LEGACY') ??\n models.find((model) => model.status === 'RECOMMENDED' && model.isFamilyDefault) ??\n models.find((model) => model.status !== 'LEGACY' && model.isFamilyDefault) ??\n models.find((model) => model.status !== 'LEGACY') ??\n models[0]\n )?.id ?? (stored || defaultModelId)\n );\n}\n\n/** Models grouped under their provider's label, in catalog order. */\nexport function groupModelsByProvider({\n models,\n}: {\n models: readonly AthenaModelOption[];\n}): Array<{ provider: string; models: AthenaModelOption[] }> {\n const groups = new Map<string, AthenaModelOption[]>();\n for (const model of models) {\n const label = MODEL_PROVIDER_LABELS[model.provider] ?? model.provider;\n groups.set(label, [...(groups.get(label) ?? []), model]);\n }\n return Array.from(groups, ([provider, grouped]) => ({ provider, models: grouped }));\n}\n\n/** The provider's credentials as the SDK's GraphQL client takes them. */\nfunction useCatalogAuth(): MentionAuthContext {\n const config = useAthenaConfig();\n return useMemo<MentionAuthContext>(\n () => ({\n backendUrl: config.backendUrl,\n appUrl: config.appUrl,\n apiKey: config.apiKey,\n credentials: 'include',\n get accessToken() {\n return config.token ?? undefined;\n },\n getAccessToken: async () => (await config.getToken?.()) ?? undefined,\n renewAccessToken: async () => (await config.getToken?.({ force: true })) ?? undefined,\n }),\n [config],\n );\n}\n\n/**\n * A short fingerprint (two FNV-1a rounds, 64 bits) of a credential: it tells accounts apart in an\n * in-memory cache key without the credential itself, or anything it could be recovered from,\n * entering the key.\n */\nexport function credentialFingerprint({ credential }: { credential: string }): string {\n const round = (seed: number) => {\n let hash = seed;\n for (let index = 0; index < credential.length; index += 1) {\n hash ^= credential.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, '0');\n };\n return `${round(0x811c9dc5)}${round(0x01000193)}`;\n}\n\n/**\n * Who is asking, for the cache key: the catalog differs per account (admin-only models, the\n * workspace's lists, the agents shared with them), and a host can switch accounts while keeping its\n * query client. The signed-in user's id when the SDK knows it, else a fingerprint of the credential\n * in use. Never the credential itself.\n */\nfunction useCatalogPrincipal(): string {\n const config = useAthenaConfig();\n const userId = useContext(AthenaAuthContext)?.user?.userId;\n if (userId) return `user:${userId}`;\n if (config.apiKey) return `key:${credentialFingerprint({ credential: config.apiKey })}`;\n if (config.token) return `token:${credentialFingerprint({ credential: config.token })}`;\n return 'session';\n}\n\n/**\n * The host's QueryClient when there is one (the thread list provides one), else one of the\n * pickers' own, so the catalog hooks work with or without the thread list.\n */\nfunction useCatalogQueryClient(): QueryClient {\n const host = useContext(QueryClientContext);\n const [own] = useState(() => new QueryClient());\n return host ?? own;\n}\n\n/** The models the signed-in person may pick (`normalizeModelCatalog`). */\nexport function useAthenaModelCatalog() {\n return useModelCatalogQuery({\n auth: useCatalogAuth(),\n principal: useCatalogPrincipal(),\n queryClient: useCatalogQueryClient(),\n });\n}\n\n/** The model catalog's query on a given client (one client for every read a hook makes). */\nfunction useModelCatalogQuery({\n auth,\n principal,\n queryClient,\n}: {\n auth: MentionAuthContext;\n principal: string;\n queryClient: QueryClient;\n}) {\n return useQuery(\n {\n queryKey: ['athena-sdk', 'catalog', 'models', auth.backendUrl, principal],\n queryFn: async () =>\n normalizeModelCatalog({\n response: await fetchGraphQL<AthenaModelCatalogResponse>(auth, ATHENA_MODEL_CATALOG_QUERY),\n }),\n staleTime: 5 * 60 * 1000,\n },\n queryClient,\n );\n}\n\n/** The published collab agents the signed-in person can see (`normalizeAgentCatalog`). */\nexport function useAthenaAgentCatalog() {\n const auth = useCatalogAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n return useQuery(\n {\n queryKey: ['athena-sdk', 'catalog', 'agents', auth.backendUrl, principal],\n queryFn: async () =>\n normalizeAgentCatalog({\n assets:\n (\n await fetchGraphQL<{ getAllAssets: Array<{ id: string; title: string | null }> }>(\n auth,\n ATHENA_AGENT_CATALOG_QUERY,\n )\n ).getAllAssets ?? [],\n }),\n staleTime: 60 * 1000,\n },\n queryClient,\n );\n}\n\nexport const ATHENA_AGENT_MODELS_QUERY = `\n query AthenaAgentModels($assetId: String!) {\n getAssetById(assetId: $assetId, withMetadata: true) { athenaMetadata }\n }\n`;\n\n/**\n * The `getAssetById` error codes that mean \"this person may not read the\n * agent\": no VIEW on it (`UNAUTHORIZED`, `FORBIDDEN`), or it lives in another\n * workspace (`WORKSPACE_MISMATCH`). Asking again answers the same.\n */\nconst AGENT_READ_DENIAL_CODES: ReadonlySet<string> = new Set([\n 'UNAUTHORIZED',\n 'FORBIDDEN',\n 'WORKSPACE_MISMATCH',\n]);\n\n/** What reading the agent's published models found: its models, or that this person cannot know them. */\nexport type AgentModelRead = { readable: true; source: AgentModelSource | null } | { readable: false };\n\n/**\n * Where `useAthenaAgentModelOptions` stands:\n *\n * - `idle`: no agent given;\n * - `loading`: the agent (or the model catalog that names its models) is being read;\n * - `ready`: the agent's published models are known;\n * - `unavailable`: this person cannot know them: no VIEW on the agent, no such\n * agent, or one never published (or whose published definition names no\n * model). Not an error: `allowAnyModel` stays `true`, so a picker keeps the\n * workspace's models;\n * - `error`: the read failed (network, server); `allowAnyModel` stays `true`.\n */\nexport type AthenaAgentModelOptionsStatus = 'idle' | 'loading' | 'ready' | 'unavailable' | 'error';\n\nexport interface AthenaAgentModelOptions {\n status: AthenaAgentModelOptionsStatus;\n /** The agent's model choices (see {@link AthenaAgentModelOption}); empty unless `ready`. */\n options: readonly AthenaAgentModelOption[];\n /**\n * The model the thread runs while it pins none: the channel's override, else\n * the agent's own model. `null` unless `ready`.\n */\n defaultModel: string | null;\n /**\n * Whether people may pick any workspace model with this agent: the agent's\n * \"Allow any workspace model\" switch (`allowAnyModel` in its published\n * definition). Only an explicit `false` restricts a picker to `options`;\n * absent, `null` or `true` (every agent saved before the switch) allow any,\n * and so does an agent this person cannot read. `true` unless `ready`.\n */\n allowAnyModel: boolean;\n}\n\nconst NO_AGENT_MODEL_OPTIONS: Readonly<\n Record<Exclude<AthenaAgentModelOptionsStatus, 'ready'>, AthenaAgentModelOptions>\n> = {\n idle: { status: 'idle', options: [], defaultModel: null, allowAnyModel: true },\n loading: { status: 'loading', options: [], defaultModel: null, allowAnyModel: true },\n unavailable: { status: 'unavailable', options: [], defaultModel: null, allowAnyModel: true },\n error: { status: 'error', options: [], defaultModel: null, allowAnyModel: true },\n};\n\n/** Whether a failed read is a denial: an answer, not a failure (nothing to retry or report). */\nfunction isAgentReadDenial(error: unknown): boolean {\n return (\n error instanceof AthenaGraphQLError &&\n error.code !== null &&\n AGENT_READ_DENIAL_CODES.has(error.code)\n );\n}\n\n/**\n * A selected collab agent's own model choices, and whether the agent restricts\n * a picker to them (`allowAnyModel: false`, the agent's \"Allow any workspace\n * model\" switch turned off). Restriction is opt-in per agent: with\n * `allowAnyModel` true (the default) a picker keeps the workspace's models and\n * can still show `defaultModel` as the agent's own; `ChatModelPicker` does\n * both.\n *\n * `agent` is the agent's asset id or its `collab_agent:<id>` ref (`null`:\n * none, `idle`). `channel` is the collab channel the chat runs on: its model\n * override is the default there. The rules are in `agent-model-options.ts`.\n *\n * The agent is read through `getAssetById(withMetadata: true)`, the\n * permission-checked asset read (VIEW on the agent), with the provider's\n * credentials: a person without VIEW gets `unavailable` with no options. The\n * model the thread pins comes from `useAthenaThreadModel()` (inside\n * `<AthenaProvider>`; none outside one): a pinned model outside the agent's\n * list is an option with `pinnedOutside`.\n *\n * Picking the `isDefault` option means \"no model\": hand the provider\n * `model={undefined}` so the agent's (or channel's) default runs, and a session\n * pinning another model is unpinned.\n *\n * While shown, the agent is read again every\n * {@link AGENT_MODELS_REFRESH_MS}: an author publishing new models elsewhere\n * invalidates nothing here.\n */\nexport function useAthenaAgentModelOptions({\n agent,\n channel = null,\n}: {\n agent: string | null | undefined;\n channel?: string | null;\n}): AthenaAgentModelOptions {\n return useAgentModelChoices({ agent, channel }).choices;\n}\n\n/** How often an agent's published models are read again while a hook shows them. */\nexport const AGENT_MODELS_REFRESH_MS = 60 * 1000;\n\n/**\n * The re-read cadence of an agent model read: every\n * {@link AGENT_MODELS_REFRESH_MS} while it answers, never for a denial (asking\n * again answers the same).\n */\nexport function agentModelsRefetchInterval({\n data,\n}: {\n data: AgentModelRead | undefined;\n}): number | false {\n return data !== undefined && !data.readable ? false : AGENT_MODELS_REFRESH_MS;\n}\n\n/**\n * {@link useAthenaAgentModelOptions} plus the catalog label of any model id,\n * from the same query client and catalog read (a picker needs both; reading\n * the catalog again through its own client would fetch it twice). Internal.\n */\nexport function useAgentModelChoices({\n agent,\n channel,\n}: {\n agent: string | null | undefined;\n channel: string | null;\n}): {\n choices: AthenaAgentModelOptions;\n modelLabel: (model: string) => string;\n /** The workspace model catalog, read through the same client as the agent. */\n catalog: ReturnType<typeof useModelCatalogQuery>;\n} {\n const assetId = agentAssetIdOf(agent);\n const auth = useCatalogAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n const read = useQuery(\n {\n queryKey: ['athena-sdk', 'catalog', 'agent-models', auth.backendUrl, principal, assetId],\n queryFn: async (): Promise<AgentModelRead> => {\n try {\n const data = await fetchGraphQL<{ getAssetById: { athenaMetadata: unknown } | null }>(\n auth,\n ATHENA_AGENT_MODELS_QUERY,\n { assetId },\n );\n if (data.getAssetById === null) return { readable: false };\n return {\n readable: true,\n source: publishedAgentModelSource(data.getAssetById.athenaMetadata),\n };\n } catch (error) {\n if (isAgentReadDenial(error)) return { readable: false };\n throw error;\n }\n },\n enabled: assetId !== null,\n staleTime: AGENT_MODELS_REFRESH_MS,\n refetchInterval: (query) => agentModelsRefetchInterval({ data: query.state.data }),\n },\n queryClient,\n );\n const catalog = useModelCatalogQuery({ auth, principal, queryClient });\n const threadModel = useOptionalAthenaThreadModel();\n const pinnedModel =\n threadModel !== null && threadModel.ready && threadModel.configured ? threadModel.model : null;\n const trimmedChannel = channel?.trim() || null;\n const models = catalog.data;\n const catalogPending = catalog.isPending;\n const { isPending: readPending, data: readData } = read;\n const modelLabel = useCallback(\n (model: string) => models?.find((option) => option.id === model)?.label ?? model,\n [models],\n );\n const choices = useMemo((): AthenaAgentModelOptions => {\n if (assetId === null) return NO_AGENT_MODEL_OPTIONS.idle;\n // A failed re-read keeps the last answer; only a first read that failed is an error.\n if (readData === undefined) {\n return readPending ? NO_AGENT_MODEL_OPTIONS.loading : NO_AGENT_MODEL_OPTIONS.error;\n }\n if (!readData.readable || readData.source === null) return NO_AGENT_MODEL_OPTIONS.unavailable;\n // The catalog names the models: wait for it, unless it failed (ids then name them).\n if (catalogPending) return NO_AGENT_MODEL_OPTIONS.loading;\n return {\n status: 'ready',\n ...buildAgentModelOptions({\n source: readData.source,\n channel: trimmedChannel,\n pinnedModel,\n modelLabel,\n }),\n allowAnyModel: readData.source.allowAnyModel,\n };\n }, [assetId, readPending, readData, catalogPending, modelLabel, trimmedChannel, pinnedModel]);\n return useMemo(() => ({ choices, modelLabel, catalog }), [choices, modelLabel, catalog]);\n}\n"],"names":[],"mappings":"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"}