@athenaintel/react 0.30.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.
- package/README.md +160 -9
- package/dist/agent-runtime/src/athena-asset-drag.cjs +44 -0
- package/dist/agent-runtime/src/athena-asset-drag.cjs.map +1 -0
- package/dist/agent-runtime/src/athena-asset-drag.js +44 -0
- package/dist/agent-runtime/src/athena-asset-drag.js.map +1 -0
- package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
- package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
- package/dist/agent-runtime/src/config-mutations.cjs +59 -0
- package/dist/agent-runtime/src/config-mutations.cjs.map +1 -0
- package/dist/agent-runtime/src/config-mutations.js +59 -0
- package/dist/agent-runtime/src/config-mutations.js.map +1 -0
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +2 -3
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -4
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +6 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.js +6 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/messages.cjs +57 -2
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.js +57 -2
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +72 -3
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js +73 -4
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/agent-runtime/src/statewire-transport.cjs +4 -13
- package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
- package/dist/agent-runtime/src/statewire-transport.js +5 -14
- package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +26 -7
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +26 -7
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-config.cjs +117 -1
- package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-config.js +118 -2
- package/dist/agent-runtime/src/use-deep-agent-config.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +9 -2
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +9 -0
- package/dist/assets/AthenaAssetEmbed.js +11 -4
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/asset-embed-messages.cjs +6 -0
- package/dist/assets/asset-embed-messages.cjs.map +1 -1
- package/dist/assets/asset-embed-messages.d.ts +7 -0
- package/dist/assets/asset-embed-messages.js +6 -0
- package/dist/assets/asset-embed-messages.js.map +1 -1
- package/dist/assets/use-asset-embed.cjs +71 -71
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +20 -7
- package/dist/assets/use-asset-embed.js +72 -72
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/catalog/agent-model-options.cjs +122 -0
- package/dist/catalog/agent-model-options.cjs.map +1 -0
- package/dist/catalog/agent-model-options.d.ts +115 -0
- package/dist/catalog/agent-model-options.js +122 -0
- package/dist/catalog/agent-model-options.js.map +1 -0
- package/dist/catalog/chat-pickers.cjs +184 -4
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +27 -3
- package/dist/catalog/chat-pickers.js +187 -7
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +117 -3
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +104 -0
- package/dist/catalog/runtime-catalog.js +119 -5
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/chat/AthenaChat.cjs +41 -26
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +8 -7
- package/dist/chat/AthenaChat.js +41 -26
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +61 -14
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +26 -12
- package/dist/chat/super-grouping/SuperGroupingCard.js +63 -16
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +80 -53
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +10 -10
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +81 -54
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +19 -4
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +24 -5
- package/dist/chat/super-grouping/activity-timeline.js +19 -4
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/index.cjs +2 -0
- package/dist/chat/super-grouping/index.cjs.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +7 -6
- package/dist/chat/super-grouping/index.js +3 -1
- package/dist/chat/super-grouping/toolkit-map.cjs +4 -1
- package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
- package/dist/chat/super-grouping/toolkit-map.js +4 -1
- package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +40 -4
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.js +40 -4
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/index.cjs +1 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +1 -1
- package/dist/chat-ui/index.js +2 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +29 -2
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.d.ts +2 -5
- package/dist/chat-ui/mentions/mention-chip.js +30 -3
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/mention-extension.cjs +1 -1
- package/dist/chat-ui/mentions/mention-extension.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-extension.js +1 -1
- package/dist/chat-ui/mentions/mention-extension.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +33 -2
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +14 -0
- package/dist/chat-ui/mentions/suggestions/data/api-client.js +33 -2
- package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs +61 -0
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -0
- package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +3 -0
- package/dist/chat-ui/mentions/use-account-workspace-id.js +61 -0
- package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -0
- package/dist/chat-ui/mentions/use-member-avatar.cjs +75 -0
- package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -0
- package/dist/chat-ui/mentions/use-member-avatar.d.ts +2 -0
- package/dist/chat-ui/mentions/use-member-avatar.js +75 -0
- package/dist/chat-ui/mentions/use-member-avatar.js.map +1 -0
- package/dist/collab/client.cjs +80 -19
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +22 -0
- package/dist/collab/client.js +80 -19
- package/dist/collab/client.js.map +1 -1
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +3 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/use-athena-rest-query.cjs +4 -0
- package/dist/lib/use-athena-rest-query.cjs.map +1 -1
- package/dist/lib/use-athena-rest-query.d.ts +6 -0
- package/dist/lib/use-athena-rest-query.js +4 -0
- package/dist/lib/use-athena-rest-query.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +57 -6
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +21 -5
- package/dist/provider/AthenaProvider.js +59 -8
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/agent-selection-context.cjs +6 -0
- package/dist/provider/agent-selection-context.cjs.map +1 -0
- package/dist/provider/agent-selection-context.d.ts +14 -0
- package/dist/provider/agent-selection-context.js +6 -0
- package/dist/provider/agent-selection-context.js.map +1 -0
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs +125 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +54 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.js +125 -0
- package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -0
- package/dist/runtime/statewire-lifecycle.cjs +5 -2
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.d.ts +5 -0
- package/dist/runtime/statewire-lifecycle.js +5 -2
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/statewire-model-lane.cjs +16 -0
- package/dist/runtime/statewire-model-lane.cjs.map +1 -0
- package/dist/runtime/statewire-model-lane.d.ts +66 -0
- package/dist/runtime/statewire-model-lane.js +16 -0
- package/dist/runtime/statewire-model-lane.js.map +1 -0
- package/dist/runtime/statewire-run-config.cjs +16 -2
- package/dist/runtime/statewire-run-config.cjs.map +1 -1
- package/dist/runtime/statewire-run-config.d.ts +10 -0
- package/dist/runtime/statewire-run-config.js +16 -2
- package/dist/runtime/statewire-run-config.js.map +1 -1
- package/dist/runtime/statewire-server-lane-context.cjs +24 -0
- package/dist/runtime/statewire-server-lane-context.cjs.map +1 -0
- package/dist/runtime/statewire-server-lane-context.d.ts +30 -0
- package/dist/runtime/statewire-server-lane-context.js +24 -0
- package/dist/runtime/statewire-server-lane-context.js.map +1 -0
- package/dist/runtime/statewire-thread-config-lane.cjs +84 -0
- package/dist/runtime/statewire-thread-config-lane.cjs.map +1 -0
- package/dist/runtime/statewire-thread-config-lane.d.ts +94 -0
- package/dist/runtime/statewire-thread-config-lane.js +84 -0
- package/dist/runtime/statewire-thread-config-lane.js.map +1 -0
- package/dist/runtime/useAthenaStatewireRuntime.cjs +38 -18
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +8 -1
- package/dist/runtime/useAthenaStatewireRuntime.js +39 -19
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/api.cjs +2 -1
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.d.ts +1 -0
- package/dist/threads/api.js +2 -1
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/use-athena-thread-model.cjs +22 -0
- package/dist/threads/use-athena-thread-model.cjs.map +1 -0
- package/dist/threads/use-athena-thread-model.d.ts +27 -0
- package/dist/threads/use-athena-thread-model.js +22 -0
- package/dist/threads/use-athena-thread-model.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-model-options.cjs","sources":["../../src/catalog/agent-model-options.ts"],"sourcesContent":["import { parseCollabAgentRef } from '../runtime/statewire-run-config';\n\n/**\n * A collab agent's own model choices, from its published definition: exactly\n * the models its author listed (the agent editor's Models section), the\n * default marked. The rules are Athena's own composer's (Olympus) and the\n * Jevin app's, so every host offers the same choices for one agent:\n *\n * - the options are the agent's labeled models, by the author's labels; an\n * automatic name (empty, the editor's old `{ id: 'default', label: 'Default' }`,\n * or one that only restates the model) shows the model's catalog label;\n * - a legacy agent with no labeled list offers its single `model`;\n * - the session channel's model override (`channelOverrides[channel].model`)\n * is that channel's default, added when the list lacks it;\n * - a model the thread pins that is none of the agent's models is shown as it\n * is (`pinnedOutside`), never replaced.\n *\n * Restricting a picker to these choices is opt-in per agent: only an agent\n * whose \"Allow any workspace model\" switch is off (`allowAnyModel: false`)\n * does; every other agent keeps the workspace's models.\n *\n * Pure, for `useAthenaAgentModelOptions` and the tests.\n */\n\n/** One model choice of a collab agent. */\nexport interface AthenaAgentModelOption {\n /** The model id a send carries (`model`). */\n model: string;\n /** The author's label, or the model's catalog label for an automatic name. */\n label: string;\n /** The model the thread runs while it pins none (the agent's own, or its channel's). */\n isDefault: boolean;\n /**\n * A model the thread's server config pins that is none of the agent's models\n * (pinned by another client, or by an older picker): shown, never replaced.\n */\n pinnedOutside: boolean;\n}\n\n/** One entry of the agent's labeled model list. */\nexport interface AgentLabeledModel {\n id: string;\n model: string;\n label: string;\n isDefault: boolean;\n}\n\n/** What an agent's published definition says about its models. */\nexport interface AgentModelSource {\n /** The model the definition runs (`config.model`); `null` when it names none. */\n model: string | null;\n /** The labeled list (`config.models`), complete rows only, in the author's order. */\n models: readonly AgentLabeledModel[];\n /** Per-channel model overrides (`channelOverrides[<channel>].model`), by channel id. */\n channelModels: Readonly<Record<string, string>>;\n /**\n * Whether people may pick any workspace model (`config.allowAnyModel`, the\n * agent editor's \"Allow any workspace model\" switch; see\n * {@link allowsAnyModel}). Only `false` restricts a picker to the agent's\n * own models.\n */\n allowAnyModel: boolean;\n}\n\n/**\n * Whether a config's `allowAnyModel` value lets people pick any model: only an\n * explicit `false` restricts; absent, `null`, `true` and any non-boolean allow\n * (agora's `collab_agent_allows_any_model`), so every agent saved before the\n * switch existed behaves as it always has.\n */\nexport function allowsAnyModel(value: unknown): boolean {\n return value !== false;\n}\n\n/** The display label of a model id; the id itself when the catalog does not know it. */\nexport type ModelLabelOf = (model: string) => string;\n\n/** The row the agent editor used to create for an agent with no stored entries. */\nconst LEGACY_DEFAULT_ENTRY_ID = 'default';\nconst LEGACY_DEFAULT_ENTRY_LABEL = 'Default';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst nonBlank = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() !== '' ? value.trim() : null;\n\n/**\n * The collab agent's asset id for an `agent` value: a `collab_agent:<id>` ref\n * (the provider's `agent` shape) or the bare asset id (the agent picker's\n * value). `null` for a blank value.\n */\nexport function agentAssetIdOf(agent: string | null | undefined): string | null {\n const trimmed = nonBlank(agent);\n if (trimmed === null) return null;\n return parseCollabAgentRef(trimmed) ?? (trimmed.includes(':') ? null : trimmed);\n}\n\n/** A stored `models` value: an array of rows, JSON-encoded or not; malformed rows dropped. */\nfunction labeledModelsOf(value: unknown): AgentLabeledModel[] {\n let rows: unknown = value;\n if (typeof rows === 'string') {\n try {\n rows = JSON.parse(rows);\n } catch {\n return [];\n }\n }\n if (!Array.isArray(rows)) return [];\n const entries: AgentLabeledModel[] = [];\n for (const row of rows) {\n if (!isRecord(row)) continue;\n const model = nonBlank(row.model);\n if (model === null) continue;\n entries.push({\n id: typeof row.id === 'string' && row.id !== '' ? row.id : model,\n model,\n label: nonBlank(row.label) ?? model,\n isDefault: row.isDefault === true,\n });\n }\n return entries;\n}\n\n/** A stored `channelOverrides` value's per-channel models. */\nfunction channelModelsOf(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n const out: Record<string, string> = {};\n for (const [channel, override] of Object.entries(value)) {\n const model = isRecord(override) ? nonBlank(override.model) : null;\n if (model !== null) out[channel] = model;\n }\n return out;\n}\n\n/** Whether the agent asset's `athena_metadata` points at a published version. */\nexport function isPublishedAgent(athenaMetadata: unknown): boolean {\n if (!isRecord(athenaMetadata)) return false;\n const versionId = athenaMetadata.published_version_id;\n return (\n (typeof versionId === 'string' && versionId !== '') ||\n (typeof versionId === 'number' && Number.isFinite(versionId))\n );\n}\n\n/**\n * The model source of the agent's PUBLISHED definition, which every SDK run\n * compiles, from the agent asset's `athena_metadata` (publish writes\n * `published_config` beside `published_version_id`). `null` for an agent\n * that was never published, or whose published definition names no model\n * (not even a channel's).\n */\nexport function publishedAgentModelSource(athenaMetadata: unknown): AgentModelSource | null {\n if (!isRecord(athenaMetadata) || !isPublishedAgent(athenaMetadata)) return null;\n const config = athenaMetadata.published_config;\n if (!isRecord(config)) return null;\n const source: AgentModelSource = {\n model: nonBlank(config.model),\n models: labeledModelsOf(config.models),\n channelModels: channelModelsOf(config.channelOverrides),\n // The editor stores the field name; agora also accepts its snake-case alias.\n allowAnyModel: allowsAnyModel(\n Object.hasOwn(config, 'allowAnyModel') ? config.allowAnyModel : config.allow_any_model,\n ),\n };\n const namesAModel =\n source.model !== null ||\n source.models.length > 0 ||\n Object.keys(source.channelModels).length > 0;\n return namesAModel ? source : null;\n}\n\n/**\n * Whether an entry's name is automatic: empty, the editor's old \"Default\", or\n * a name that only restates the entry's model (its id or catalog label).\n */\nexport function isAutomaticModelLabel({\n entry,\n modelLabel,\n}: {\n entry: Pick<AgentLabeledModel, 'id' | 'model' | 'label'>;\n modelLabel: ModelLabelOf;\n}): boolean {\n const label = entry.label.trim();\n if (label === '') return true;\n if (entry.id === LEGACY_DEFAULT_ENTRY_ID && label === LEGACY_DEFAULT_ENTRY_LABEL) return true;\n return label === entry.model || label === modelLabel(entry.model);\n}\n\n/**\n * The model a thread runs while it pins none: the channel's override, else the\n * definition's `model`, else its marked (or first) labeled entry.\n */\nexport function agentDefaultModel({\n source,\n channel,\n}: {\n source: AgentModelSource;\n channel: string | null;\n}): string | null {\n const marked = source.models.find((entry) => entry.isDefault) ?? source.models[0];\n return (channel ? source.channelModels[channel] : undefined) ?? source.model ?? marked?.model ?? null;\n}\n\n/**\n * The agent's model choices and its default, by the rules above. Options keep\n * the author's order, one per model (the first entry of a model names it); the\n * default is marked, and appended when the list lacks it; a pinned model\n * outside the list comes last.\n */\nexport function buildAgentModelOptions({\n source,\n channel,\n pinnedModel,\n modelLabel,\n}: {\n source: AgentModelSource;\n channel: string | null;\n /** The model the thread's server config pins; `null` while it pins none (or is unknown). */\n pinnedModel: string | null;\n modelLabel: ModelLabelOf;\n}): { options: AthenaAgentModelOption[]; defaultModel: string | null } {\n const options: AthenaAgentModelOption[] = [];\n const add = (model: string, label: string) => {\n if (options.some((option) => option.model === model)) return;\n options.push({ model, label, isDefault: false, pinnedOutside: false });\n };\n for (const entry of source.models) {\n add(\n entry.model,\n isAutomaticModelLabel({ entry, modelLabel }) ? modelLabel(entry.model) : entry.label.trim(),\n );\n }\n if (options.length === 0 && source.model !== null) add(source.model, modelLabel(source.model));\n\n const defaultModel = agentDefaultModel({ source, channel });\n if (defaultModel !== null) {\n add(defaultModel, modelLabel(defaultModel));\n for (const option of options) option.isDefault = option.model === defaultModel;\n }\n\n const pinned = nonBlank(pinnedModel);\n if (pinned !== null && !options.some((option) => option.model === pinned)) {\n options.push({ model: pinned, label: modelLabel(pinned), isDefault: false, pinnedOutside: true });\n }\n return { options, defaultModel };\n}\n"],"names":["parseCollabAgentRef"],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A collab agent's own model choices, from its published definition: exactly
|
|
3
|
+
* the models its author listed (the agent editor's Models section), the
|
|
4
|
+
* default marked. The rules are Athena's own composer's (Olympus) and the
|
|
5
|
+
* Jevin app's, so every host offers the same choices for one agent:
|
|
6
|
+
*
|
|
7
|
+
* - the options are the agent's labeled models, by the author's labels; an
|
|
8
|
+
* automatic name (empty, the editor's old `{ id: 'default', label: 'Default' }`,
|
|
9
|
+
* or one that only restates the model) shows the model's catalog label;
|
|
10
|
+
* - a legacy agent with no labeled list offers its single `model`;
|
|
11
|
+
* - the session channel's model override (`channelOverrides[channel].model`)
|
|
12
|
+
* is that channel's default, added when the list lacks it;
|
|
13
|
+
* - a model the thread pins that is none of the agent's models is shown as it
|
|
14
|
+
* is (`pinnedOutside`), never replaced.
|
|
15
|
+
*
|
|
16
|
+
* Restricting a picker to these choices is opt-in per agent: only an agent
|
|
17
|
+
* whose "Allow any workspace model" switch is off (`allowAnyModel: false`)
|
|
18
|
+
* does; every other agent keeps the workspace's models.
|
|
19
|
+
*
|
|
20
|
+
* Pure, for `useAthenaAgentModelOptions` and the tests.
|
|
21
|
+
*/
|
|
22
|
+
/** One model choice of a collab agent. */
|
|
23
|
+
export interface AthenaAgentModelOption {
|
|
24
|
+
/** The model id a send carries (`model`). */
|
|
25
|
+
model: string;
|
|
26
|
+
/** The author's label, or the model's catalog label for an automatic name. */
|
|
27
|
+
label: string;
|
|
28
|
+
/** The model the thread runs while it pins none (the agent's own, or its channel's). */
|
|
29
|
+
isDefault: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* A model the thread's server config pins that is none of the agent's models
|
|
32
|
+
* (pinned by another client, or by an older picker): shown, never replaced.
|
|
33
|
+
*/
|
|
34
|
+
pinnedOutside: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** One entry of the agent's labeled model list. */
|
|
37
|
+
export interface AgentLabeledModel {
|
|
38
|
+
id: string;
|
|
39
|
+
model: string;
|
|
40
|
+
label: string;
|
|
41
|
+
isDefault: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** What an agent's published definition says about its models. */
|
|
44
|
+
export interface AgentModelSource {
|
|
45
|
+
/** The model the definition runs (`config.model`); `null` when it names none. */
|
|
46
|
+
model: string | null;
|
|
47
|
+
/** The labeled list (`config.models`), complete rows only, in the author's order. */
|
|
48
|
+
models: readonly AgentLabeledModel[];
|
|
49
|
+
/** Per-channel model overrides (`channelOverrides[<channel>].model`), by channel id. */
|
|
50
|
+
channelModels: Readonly<Record<string, string>>;
|
|
51
|
+
/**
|
|
52
|
+
* Whether people may pick any workspace model (`config.allowAnyModel`, the
|
|
53
|
+
* agent editor's "Allow any workspace model" switch; see
|
|
54
|
+
* {@link allowsAnyModel}). Only `false` restricts a picker to the agent's
|
|
55
|
+
* own models.
|
|
56
|
+
*/
|
|
57
|
+
allowAnyModel: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether a config's `allowAnyModel` value lets people pick any model: only an
|
|
61
|
+
* explicit `false` restricts; absent, `null`, `true` and any non-boolean allow
|
|
62
|
+
* (agora's `collab_agent_allows_any_model`), so every agent saved before the
|
|
63
|
+
* switch existed behaves as it always has.
|
|
64
|
+
*/
|
|
65
|
+
export declare function allowsAnyModel(value: unknown): boolean;
|
|
66
|
+
/** The display label of a model id; the id itself when the catalog does not know it. */
|
|
67
|
+
export type ModelLabelOf = (model: string) => string;
|
|
68
|
+
/**
|
|
69
|
+
* The collab agent's asset id for an `agent` value: a `collab_agent:<id>` ref
|
|
70
|
+
* (the provider's `agent` shape) or the bare asset id (the agent picker's
|
|
71
|
+
* value). `null` for a blank value.
|
|
72
|
+
*/
|
|
73
|
+
export declare function agentAssetIdOf(agent: string | null | undefined): string | null;
|
|
74
|
+
/** Whether the agent asset's `athena_metadata` points at a published version. */
|
|
75
|
+
export declare function isPublishedAgent(athenaMetadata: unknown): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The model source of the agent's PUBLISHED definition, which every SDK run
|
|
78
|
+
* compiles, from the agent asset's `athena_metadata` (publish writes
|
|
79
|
+
* `published_config` beside `published_version_id`). `null` for an agent
|
|
80
|
+
* that was never published, or whose published definition names no model
|
|
81
|
+
* (not even a channel's).
|
|
82
|
+
*/
|
|
83
|
+
export declare function publishedAgentModelSource(athenaMetadata: unknown): AgentModelSource | null;
|
|
84
|
+
/**
|
|
85
|
+
* Whether an entry's name is automatic: empty, the editor's old "Default", or
|
|
86
|
+
* a name that only restates the entry's model (its id or catalog label).
|
|
87
|
+
*/
|
|
88
|
+
export declare function isAutomaticModelLabel({ entry, modelLabel, }: {
|
|
89
|
+
entry: Pick<AgentLabeledModel, 'id' | 'model' | 'label'>;
|
|
90
|
+
modelLabel: ModelLabelOf;
|
|
91
|
+
}): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* The model a thread runs while it pins none: the channel's override, else the
|
|
94
|
+
* definition's `model`, else its marked (or first) labeled entry.
|
|
95
|
+
*/
|
|
96
|
+
export declare function agentDefaultModel({ source, channel, }: {
|
|
97
|
+
source: AgentModelSource;
|
|
98
|
+
channel: string | null;
|
|
99
|
+
}): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* The agent's model choices and its default, by the rules above. Options keep
|
|
102
|
+
* the author's order, one per model (the first entry of a model names it); the
|
|
103
|
+
* default is marked, and appended when the list lacks it; a pinned model
|
|
104
|
+
* outside the list comes last.
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildAgentModelOptions({ source, channel, pinnedModel, modelLabel, }: {
|
|
107
|
+
source: AgentModelSource;
|
|
108
|
+
channel: string | null;
|
|
109
|
+
/** The model the thread's server config pins; `null` while it pins none (or is unknown). */
|
|
110
|
+
pinnedModel: string | null;
|
|
111
|
+
modelLabel: ModelLabelOf;
|
|
112
|
+
}): {
|
|
113
|
+
options: AthenaAgentModelOption[];
|
|
114
|
+
defaultModel: string | null;
|
|
115
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { parseCollabAgentRef } from "../runtime/statewire-run-config.js";
|
|
2
|
+
function allowsAnyModel(value) {
|
|
3
|
+
return value !== false;
|
|
4
|
+
}
|
|
5
|
+
const LEGACY_DEFAULT_ENTRY_ID = "default";
|
|
6
|
+
const LEGACY_DEFAULT_ENTRY_LABEL = "Default";
|
|
7
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
const nonBlank = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
9
|
+
function agentAssetIdOf(agent) {
|
|
10
|
+
const trimmed = nonBlank(agent);
|
|
11
|
+
if (trimmed === null) return null;
|
|
12
|
+
return parseCollabAgentRef(trimmed) ?? (trimmed.includes(":") ? null : trimmed);
|
|
13
|
+
}
|
|
14
|
+
function labeledModelsOf(value) {
|
|
15
|
+
let rows = value;
|
|
16
|
+
if (typeof rows === "string") {
|
|
17
|
+
try {
|
|
18
|
+
rows = JSON.parse(rows);
|
|
19
|
+
} catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(rows)) return [];
|
|
24
|
+
const entries = [];
|
|
25
|
+
for (const row of rows) {
|
|
26
|
+
if (!isRecord(row)) continue;
|
|
27
|
+
const model = nonBlank(row.model);
|
|
28
|
+
if (model === null) continue;
|
|
29
|
+
entries.push({
|
|
30
|
+
id: typeof row.id === "string" && row.id !== "" ? row.id : model,
|
|
31
|
+
model,
|
|
32
|
+
label: nonBlank(row.label) ?? model,
|
|
33
|
+
isDefault: row.isDefault === true
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return entries;
|
|
37
|
+
}
|
|
38
|
+
function channelModelsOf(value) {
|
|
39
|
+
if (!isRecord(value)) return {};
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const [channel, override] of Object.entries(value)) {
|
|
42
|
+
const model = isRecord(override) ? nonBlank(override.model) : null;
|
|
43
|
+
if (model !== null) out[channel] = model;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
function isPublishedAgent(athenaMetadata) {
|
|
48
|
+
if (!isRecord(athenaMetadata)) return false;
|
|
49
|
+
const versionId = athenaMetadata.published_version_id;
|
|
50
|
+
return typeof versionId === "string" && versionId !== "" || typeof versionId === "number" && Number.isFinite(versionId);
|
|
51
|
+
}
|
|
52
|
+
function publishedAgentModelSource(athenaMetadata) {
|
|
53
|
+
if (!isRecord(athenaMetadata) || !isPublishedAgent(athenaMetadata)) return null;
|
|
54
|
+
const config = athenaMetadata.published_config;
|
|
55
|
+
if (!isRecord(config)) return null;
|
|
56
|
+
const source = {
|
|
57
|
+
model: nonBlank(config.model),
|
|
58
|
+
models: labeledModelsOf(config.models),
|
|
59
|
+
channelModels: channelModelsOf(config.channelOverrides),
|
|
60
|
+
// The editor stores the field name; agora also accepts its snake-case alias.
|
|
61
|
+
allowAnyModel: allowsAnyModel(
|
|
62
|
+
Object.hasOwn(config, "allowAnyModel") ? config.allowAnyModel : config.allow_any_model
|
|
63
|
+
)
|
|
64
|
+
};
|
|
65
|
+
const namesAModel = source.model !== null || source.models.length > 0 || Object.keys(source.channelModels).length > 0;
|
|
66
|
+
return namesAModel ? source : null;
|
|
67
|
+
}
|
|
68
|
+
function isAutomaticModelLabel({
|
|
69
|
+
entry,
|
|
70
|
+
modelLabel
|
|
71
|
+
}) {
|
|
72
|
+
const label = entry.label.trim();
|
|
73
|
+
if (label === "") return true;
|
|
74
|
+
if (entry.id === LEGACY_DEFAULT_ENTRY_ID && label === LEGACY_DEFAULT_ENTRY_LABEL) return true;
|
|
75
|
+
return label === entry.model || label === modelLabel(entry.model);
|
|
76
|
+
}
|
|
77
|
+
function agentDefaultModel({
|
|
78
|
+
source,
|
|
79
|
+
channel
|
|
80
|
+
}) {
|
|
81
|
+
const marked = source.models.find((entry) => entry.isDefault) ?? source.models[0];
|
|
82
|
+
return (channel ? source.channelModels[channel] : void 0) ?? source.model ?? (marked == null ? void 0 : marked.model) ?? null;
|
|
83
|
+
}
|
|
84
|
+
function buildAgentModelOptions({
|
|
85
|
+
source,
|
|
86
|
+
channel,
|
|
87
|
+
pinnedModel,
|
|
88
|
+
modelLabel
|
|
89
|
+
}) {
|
|
90
|
+
const options = [];
|
|
91
|
+
const add = (model, label) => {
|
|
92
|
+
if (options.some((option) => option.model === model)) return;
|
|
93
|
+
options.push({ model, label, isDefault: false, pinnedOutside: false });
|
|
94
|
+
};
|
|
95
|
+
for (const entry of source.models) {
|
|
96
|
+
add(
|
|
97
|
+
entry.model,
|
|
98
|
+
isAutomaticModelLabel({ entry, modelLabel }) ? modelLabel(entry.model) : entry.label.trim()
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (options.length === 0 && source.model !== null) add(source.model, modelLabel(source.model));
|
|
102
|
+
const defaultModel = agentDefaultModel({ source, channel });
|
|
103
|
+
if (defaultModel !== null) {
|
|
104
|
+
add(defaultModel, modelLabel(defaultModel));
|
|
105
|
+
for (const option of options) option.isDefault = option.model === defaultModel;
|
|
106
|
+
}
|
|
107
|
+
const pinned = nonBlank(pinnedModel);
|
|
108
|
+
if (pinned !== null && !options.some((option) => option.model === pinned)) {
|
|
109
|
+
options.push({ model: pinned, label: modelLabel(pinned), isDefault: false, pinnedOutside: true });
|
|
110
|
+
}
|
|
111
|
+
return { options, defaultModel };
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
agentAssetIdOf,
|
|
115
|
+
agentDefaultModel,
|
|
116
|
+
allowsAnyModel,
|
|
117
|
+
buildAgentModelOptions,
|
|
118
|
+
isAutomaticModelLabel,
|
|
119
|
+
isPublishedAgent,
|
|
120
|
+
publishedAgentModelSource
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=agent-model-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-model-options.js","sources":["../../src/catalog/agent-model-options.ts"],"sourcesContent":["import { parseCollabAgentRef } from '../runtime/statewire-run-config';\n\n/**\n * A collab agent's own model choices, from its published definition: exactly\n * the models its author listed (the agent editor's Models section), the\n * default marked. The rules are Athena's own composer's (Olympus) and the\n * Jevin app's, so every host offers the same choices for one agent:\n *\n * - the options are the agent's labeled models, by the author's labels; an\n * automatic name (empty, the editor's old `{ id: 'default', label: 'Default' }`,\n * or one that only restates the model) shows the model's catalog label;\n * - a legacy agent with no labeled list offers its single `model`;\n * - the session channel's model override (`channelOverrides[channel].model`)\n * is that channel's default, added when the list lacks it;\n * - a model the thread pins that is none of the agent's models is shown as it\n * is (`pinnedOutside`), never replaced.\n *\n * Restricting a picker to these choices is opt-in per agent: only an agent\n * whose \"Allow any workspace model\" switch is off (`allowAnyModel: false`)\n * does; every other agent keeps the workspace's models.\n *\n * Pure, for `useAthenaAgentModelOptions` and the tests.\n */\n\n/** One model choice of a collab agent. */\nexport interface AthenaAgentModelOption {\n /** The model id a send carries (`model`). */\n model: string;\n /** The author's label, or the model's catalog label for an automatic name. */\n label: string;\n /** The model the thread runs while it pins none (the agent's own, or its channel's). */\n isDefault: boolean;\n /**\n * A model the thread's server config pins that is none of the agent's models\n * (pinned by another client, or by an older picker): shown, never replaced.\n */\n pinnedOutside: boolean;\n}\n\n/** One entry of the agent's labeled model list. */\nexport interface AgentLabeledModel {\n id: string;\n model: string;\n label: string;\n isDefault: boolean;\n}\n\n/** What an agent's published definition says about its models. */\nexport interface AgentModelSource {\n /** The model the definition runs (`config.model`); `null` when it names none. */\n model: string | null;\n /** The labeled list (`config.models`), complete rows only, in the author's order. */\n models: readonly AgentLabeledModel[];\n /** Per-channel model overrides (`channelOverrides[<channel>].model`), by channel id. */\n channelModels: Readonly<Record<string, string>>;\n /**\n * Whether people may pick any workspace model (`config.allowAnyModel`, the\n * agent editor's \"Allow any workspace model\" switch; see\n * {@link allowsAnyModel}). Only `false` restricts a picker to the agent's\n * own models.\n */\n allowAnyModel: boolean;\n}\n\n/**\n * Whether a config's `allowAnyModel` value lets people pick any model: only an\n * explicit `false` restricts; absent, `null`, `true` and any non-boolean allow\n * (agora's `collab_agent_allows_any_model`), so every agent saved before the\n * switch existed behaves as it always has.\n */\nexport function allowsAnyModel(value: unknown): boolean {\n return value !== false;\n}\n\n/** The display label of a model id; the id itself when the catalog does not know it. */\nexport type ModelLabelOf = (model: string) => string;\n\n/** The row the agent editor used to create for an agent with no stored entries. */\nconst LEGACY_DEFAULT_ENTRY_ID = 'default';\nconst LEGACY_DEFAULT_ENTRY_LABEL = 'Default';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst nonBlank = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() !== '' ? value.trim() : null;\n\n/**\n * The collab agent's asset id for an `agent` value: a `collab_agent:<id>` ref\n * (the provider's `agent` shape) or the bare asset id (the agent picker's\n * value). `null` for a blank value.\n */\nexport function agentAssetIdOf(agent: string | null | undefined): string | null {\n const trimmed = nonBlank(agent);\n if (trimmed === null) return null;\n return parseCollabAgentRef(trimmed) ?? (trimmed.includes(':') ? null : trimmed);\n}\n\n/** A stored `models` value: an array of rows, JSON-encoded or not; malformed rows dropped. */\nfunction labeledModelsOf(value: unknown): AgentLabeledModel[] {\n let rows: unknown = value;\n if (typeof rows === 'string') {\n try {\n rows = JSON.parse(rows);\n } catch {\n return [];\n }\n }\n if (!Array.isArray(rows)) return [];\n const entries: AgentLabeledModel[] = [];\n for (const row of rows) {\n if (!isRecord(row)) continue;\n const model = nonBlank(row.model);\n if (model === null) continue;\n entries.push({\n id: typeof row.id === 'string' && row.id !== '' ? row.id : model,\n model,\n label: nonBlank(row.label) ?? model,\n isDefault: row.isDefault === true,\n });\n }\n return entries;\n}\n\n/** A stored `channelOverrides` value's per-channel models. */\nfunction channelModelsOf(value: unknown): Record<string, string> {\n if (!isRecord(value)) return {};\n const out: Record<string, string> = {};\n for (const [channel, override] of Object.entries(value)) {\n const model = isRecord(override) ? nonBlank(override.model) : null;\n if (model !== null) out[channel] = model;\n }\n return out;\n}\n\n/** Whether the agent asset's `athena_metadata` points at a published version. */\nexport function isPublishedAgent(athenaMetadata: unknown): boolean {\n if (!isRecord(athenaMetadata)) return false;\n const versionId = athenaMetadata.published_version_id;\n return (\n (typeof versionId === 'string' && versionId !== '') ||\n (typeof versionId === 'number' && Number.isFinite(versionId))\n );\n}\n\n/**\n * The model source of the agent's PUBLISHED definition, which every SDK run\n * compiles, from the agent asset's `athena_metadata` (publish writes\n * `published_config` beside `published_version_id`). `null` for an agent\n * that was never published, or whose published definition names no model\n * (not even a channel's).\n */\nexport function publishedAgentModelSource(athenaMetadata: unknown): AgentModelSource | null {\n if (!isRecord(athenaMetadata) || !isPublishedAgent(athenaMetadata)) return null;\n const config = athenaMetadata.published_config;\n if (!isRecord(config)) return null;\n const source: AgentModelSource = {\n model: nonBlank(config.model),\n models: labeledModelsOf(config.models),\n channelModels: channelModelsOf(config.channelOverrides),\n // The editor stores the field name; agora also accepts its snake-case alias.\n allowAnyModel: allowsAnyModel(\n Object.hasOwn(config, 'allowAnyModel') ? config.allowAnyModel : config.allow_any_model,\n ),\n };\n const namesAModel =\n source.model !== null ||\n source.models.length > 0 ||\n Object.keys(source.channelModels).length > 0;\n return namesAModel ? source : null;\n}\n\n/**\n * Whether an entry's name is automatic: empty, the editor's old \"Default\", or\n * a name that only restates the entry's model (its id or catalog label).\n */\nexport function isAutomaticModelLabel({\n entry,\n modelLabel,\n}: {\n entry: Pick<AgentLabeledModel, 'id' | 'model' | 'label'>;\n modelLabel: ModelLabelOf;\n}): boolean {\n const label = entry.label.trim();\n if (label === '') return true;\n if (entry.id === LEGACY_DEFAULT_ENTRY_ID && label === LEGACY_DEFAULT_ENTRY_LABEL) return true;\n return label === entry.model || label === modelLabel(entry.model);\n}\n\n/**\n * The model a thread runs while it pins none: the channel's override, else the\n * definition's `model`, else its marked (or first) labeled entry.\n */\nexport function agentDefaultModel({\n source,\n channel,\n}: {\n source: AgentModelSource;\n channel: string | null;\n}): string | null {\n const marked = source.models.find((entry) => entry.isDefault) ?? source.models[0];\n return (channel ? source.channelModels[channel] : undefined) ?? source.model ?? marked?.model ?? null;\n}\n\n/**\n * The agent's model choices and its default, by the rules above. Options keep\n * the author's order, one per model (the first entry of a model names it); the\n * default is marked, and appended when the list lacks it; a pinned model\n * outside the list comes last.\n */\nexport function buildAgentModelOptions({\n source,\n channel,\n pinnedModel,\n modelLabel,\n}: {\n source: AgentModelSource;\n channel: string | null;\n /** The model the thread's server config pins; `null` while it pins none (or is unknown). */\n pinnedModel: string | null;\n modelLabel: ModelLabelOf;\n}): { options: AthenaAgentModelOption[]; defaultModel: string | null } {\n const options: AthenaAgentModelOption[] = [];\n const add = (model: string, label: string) => {\n if (options.some((option) => option.model === model)) return;\n options.push({ model, label, isDefault: false, pinnedOutside: false });\n };\n for (const entry of source.models) {\n add(\n entry.model,\n isAutomaticModelLabel({ entry, modelLabel }) ? modelLabel(entry.model) : entry.label.trim(),\n );\n }\n if (options.length === 0 && source.model !== null) add(source.model, modelLabel(source.model));\n\n const defaultModel = agentDefaultModel({ source, channel });\n if (defaultModel !== null) {\n add(defaultModel, modelLabel(defaultModel));\n for (const option of options) option.isDefault = option.model === defaultModel;\n }\n\n const pinned = nonBlank(pinnedModel);\n if (pinned !== null && !options.some((option) => option.model === pinned)) {\n options.push({ model: pinned, label: modelLabel(pinned), isDefault: false, pinnedOutside: true });\n }\n return { options, defaultModel };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -6,12 +6,16 @@ const radixUi = require("radix-ui");
|
|
|
6
6
|
const react = require("react");
|
|
7
7
|
const lib_ownerDocument = require("../lib/owner-document.cjs");
|
|
8
8
|
const portalSurface = require("../lib/portal-surface.cjs");
|
|
9
|
+
const agentSelectionContext = require("../provider/agent-selection-context.cjs");
|
|
9
10
|
const themeStyleContext = require("../provider/theme-style-context.cjs");
|
|
11
|
+
const agentModelOptions = require("./agent-model-options.cjs");
|
|
10
12
|
const runtimeCatalog = require("./runtime-catalog.cjs");
|
|
11
13
|
const cnfast = require("cnfast");
|
|
12
14
|
const CHIP_CLASS = "inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
|
|
15
|
+
const STATIC_CHIP_CLASS = "inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground";
|
|
13
16
|
const ITEM_CLASS = "relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-7 text-sm outline-none data-[highlighted]:bg-muted data-[state=checked]:font-medium";
|
|
14
17
|
const AGENT_OWN_MODEL = "__agent_own_model__";
|
|
18
|
+
const AGENT_MODEL_LABEL = "Agent’s model";
|
|
15
19
|
function PickerMenu({ label, children }) {
|
|
16
20
|
const themeStyle = themeStyleContext.useAthenaThemeStyle();
|
|
17
21
|
const container = lib_ownerDocument.usePortalContainer();
|
|
@@ -31,9 +35,16 @@ function PickerMenu({ label, children }) {
|
|
|
31
35
|
}
|
|
32
36
|
) });
|
|
33
37
|
}
|
|
34
|
-
function PickerItem({
|
|
38
|
+
function PickerItem({
|
|
39
|
+
value,
|
|
40
|
+
detail,
|
|
41
|
+
children
|
|
42
|
+
}) {
|
|
35
43
|
return /* @__PURE__ */ jsxRuntime.jsxs(radixUi.DropdownMenu.RadioItem, { value, className: ITEM_CLASS, children: [
|
|
36
|
-
/* @__PURE__ */ jsxRuntime.
|
|
44
|
+
detail ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-normal text-muted-foreground", children: detail })
|
|
47
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children }),
|
|
37
48
|
/* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.ItemIndicator, { className: "absolute right-2 inline-flex", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-3.5", "aria-hidden": true }) })
|
|
38
49
|
] });
|
|
39
50
|
}
|
|
@@ -52,10 +63,93 @@ function ChatModelPicker({
|
|
|
52
63
|
onChange,
|
|
53
64
|
defaultModelId,
|
|
54
65
|
agentSelected = false,
|
|
66
|
+
agent,
|
|
67
|
+
channel,
|
|
55
68
|
disabled = false,
|
|
56
69
|
className
|
|
57
70
|
}) {
|
|
71
|
+
const providerSelection = react.useContext(agentSelectionContext.AthenaAgentSelectionContext);
|
|
72
|
+
const agentAssetId = agent !== void 0 ? agentModelOptions.agentAssetIdOf(agent) : agentSelected ? (providerSelection == null ? void 0 : providerSelection.agentAssetId) ?? null : null;
|
|
73
|
+
if (agentAssetId !== null) {
|
|
74
|
+
const agentChannel = channel !== void 0 ? channel : (providerSelection == null ? void 0 : providerSelection.agentAssetId) === agentAssetId ? providerSelection.channel : null;
|
|
75
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
AgentAwareModelPicker,
|
|
77
|
+
{
|
|
78
|
+
agentAssetId,
|
|
79
|
+
channel: agentChannel,
|
|
80
|
+
value,
|
|
81
|
+
onChange,
|
|
82
|
+
defaultModelId,
|
|
83
|
+
disabled,
|
|
84
|
+
className
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
89
|
+
WorkspaceModelPicker,
|
|
90
|
+
{
|
|
91
|
+
value,
|
|
92
|
+
onChange,
|
|
93
|
+
defaultModelId,
|
|
94
|
+
agentSelected,
|
|
95
|
+
disabled,
|
|
96
|
+
className
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
function AgentAwareModelPicker({
|
|
101
|
+
agentAssetId,
|
|
102
|
+
channel,
|
|
103
|
+
value,
|
|
104
|
+
onChange,
|
|
105
|
+
defaultModelId,
|
|
106
|
+
disabled,
|
|
107
|
+
className
|
|
108
|
+
}) {
|
|
109
|
+
const { choices, modelLabel, catalog } = runtimeCatalog.useAgentModelChoices({ agent: agentAssetId, channel });
|
|
110
|
+
if (choices.status === "ready" && !choices.allowAnyModel) {
|
|
111
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
+
AgentModelMenu,
|
|
113
|
+
{
|
|
114
|
+
choices,
|
|
115
|
+
modelLabel,
|
|
116
|
+
value,
|
|
117
|
+
onChange,
|
|
118
|
+
disabled,
|
|
119
|
+
className
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
124
|
+
WorkspaceModelMenu,
|
|
125
|
+
{
|
|
126
|
+
catalog,
|
|
127
|
+
value,
|
|
128
|
+
onChange,
|
|
129
|
+
defaultModelId,
|
|
130
|
+
agentSelected: true,
|
|
131
|
+
agentDefaultLabel: choices.defaultModel === null ? null : modelLabel(choices.defaultModel),
|
|
132
|
+
holdReplacement: choices.status === "loading",
|
|
133
|
+
disabled,
|
|
134
|
+
className
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function WorkspaceModelPicker(props) {
|
|
58
139
|
const catalog = runtimeCatalog.useAthenaModelCatalog();
|
|
140
|
+
return /* @__PURE__ */ jsxRuntime.jsx(WorkspaceModelMenu, { catalog, ...props });
|
|
141
|
+
}
|
|
142
|
+
function WorkspaceModelMenu({
|
|
143
|
+
catalog,
|
|
144
|
+
value,
|
|
145
|
+
onChange,
|
|
146
|
+
defaultModelId,
|
|
147
|
+
agentSelected,
|
|
148
|
+
agentDefaultLabel = null,
|
|
149
|
+
holdReplacement = false,
|
|
150
|
+
disabled,
|
|
151
|
+
className
|
|
152
|
+
}) {
|
|
59
153
|
const [open, setOpen] = react.useState(false);
|
|
60
154
|
const models = catalog.data ?? [];
|
|
61
155
|
const resolved = value === null && agentSelected ? null : runtimeCatalog.resolveCatalogModelId({ stored: value, defaultModelId, models });
|
|
@@ -63,11 +157,12 @@ function ChatModelPicker({
|
|
|
63
157
|
const label = resolved === null ? "Agent’s model" : (current == null ? void 0 : current.label) ?? resolved;
|
|
64
158
|
const replacedRef = react.useRef(null);
|
|
65
159
|
react.useEffect(() => {
|
|
160
|
+
if (holdReplacement) return;
|
|
66
161
|
if (!catalog.isSuccess || value === null || resolved === null || resolved === value) return;
|
|
67
162
|
if (models.some((model) => model.id === value) || replacedRef.current === value) return;
|
|
68
163
|
replacedRef.current = value;
|
|
69
164
|
onChange(resolved);
|
|
70
|
-
}, [catalog.isSuccess, models, value, resolved, onChange]);
|
|
165
|
+
}, [holdReplacement, catalog.isSuccess, models, value, resolved, onChange]);
|
|
71
166
|
return /* @__PURE__ */ jsxRuntime.jsxs(radixUi.DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
|
|
72
167
|
/* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
73
168
|
"button",
|
|
@@ -89,7 +184,7 @@ function ChatModelPicker({
|
|
|
89
184
|
value: resolved ?? AGENT_OWN_MODEL,
|
|
90
185
|
onValueChange: (next) => onChange(next === AGENT_OWN_MODEL ? null : next),
|
|
91
186
|
children: [
|
|
92
|
-
agentSelected && /* @__PURE__ */ jsxRuntime.jsx(PickerItem, { value: AGENT_OWN_MODEL, children: "Agent’s own model" }),
|
|
187
|
+
agentSelected && /* @__PURE__ */ jsxRuntime.jsx(PickerItem, { value: AGENT_OWN_MODEL, detail: agentDefaultLabel, children: "Agent’s own model" }),
|
|
93
188
|
catalog.isPending && /* @__PURE__ */ jsxRuntime.jsx(PickerNote, { children: "Loading models…" }),
|
|
94
189
|
catalog.isError && /* @__PURE__ */ jsxRuntime.jsx(PickerNote, { alert: true, children: "Couldn’t load the models. Try again in a moment." }),
|
|
95
190
|
runtimeCatalog.groupModelsByProvider({ models }).map((group) => /* @__PURE__ */ jsxRuntime.jsxs(radixUi.DropdownMenu.Group, { children: [
|
|
@@ -104,6 +199,91 @@ function ChatModelPicker({
|
|
|
104
199
|
) })
|
|
105
200
|
] });
|
|
106
201
|
}
|
|
202
|
+
function AgentModelMenu({
|
|
203
|
+
choices,
|
|
204
|
+
modelLabel,
|
|
205
|
+
value,
|
|
206
|
+
onChange,
|
|
207
|
+
disabled,
|
|
208
|
+
className
|
|
209
|
+
}) {
|
|
210
|
+
const [open, setOpen] = react.useState(false);
|
|
211
|
+
const pinsDefault = value !== null && value === choices.defaultModel;
|
|
212
|
+
const items = choices.options.map((option) => {
|
|
213
|
+
const display = modelLabel(option.model);
|
|
214
|
+
return {
|
|
215
|
+
value: option.isDefault && !pinsDefault ? AGENT_OWN_MODEL : option.model,
|
|
216
|
+
label: option.label,
|
|
217
|
+
isDefault: option.isDefault,
|
|
218
|
+
detail: option.pinnedOutside ? "Set for this conversation outside the agent" : display === option.label ? null : display
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
if (value !== null && !choices.options.some((option) => option.model === value)) {
|
|
222
|
+
items.push({
|
|
223
|
+
value,
|
|
224
|
+
label: modelLabel(value),
|
|
225
|
+
isDefault: false,
|
|
226
|
+
detail: "Not one of the agent’s models"
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (pinsDefault) {
|
|
230
|
+
items.push({
|
|
231
|
+
value: AGENT_OWN_MODEL,
|
|
232
|
+
label: "Agent’s own model",
|
|
233
|
+
isDefault: false,
|
|
234
|
+
detail: "Follows the agent’s default"
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const selectedValue = value ?? AGENT_OWN_MODEL;
|
|
238
|
+
const selected = items.find((item) => item.value === selectedValue) ?? null;
|
|
239
|
+
const label = (selected == null ? void 0 : selected.label) || AGENT_MODEL_LABEL;
|
|
240
|
+
if (items.length < 2) {
|
|
241
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
242
|
+
"span",
|
|
243
|
+
{
|
|
244
|
+
role: "img",
|
|
245
|
+
"aria-label": `Model: ${label}`,
|
|
246
|
+
title: selected ? `This agent runs ${label}` : "This agent runs its own model",
|
|
247
|
+
"data-slot": "chat-model-picker-label",
|
|
248
|
+
className: cnfast.cn(STATIC_CHIP_CLASS, className),
|
|
249
|
+
children: [
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SparklesIcon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(radixUi.DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
|
|
257
|
+
/* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
258
|
+
"button",
|
|
259
|
+
{
|
|
260
|
+
type: "button",
|
|
261
|
+
className: cnfast.cn(CHIP_CLASS, className),
|
|
262
|
+
disabled,
|
|
263
|
+
"aria-label": `Model: ${label}`,
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SparklesIcon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label }),
|
|
267
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": true })
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
) }),
|
|
271
|
+
/* @__PURE__ */ jsxRuntime.jsx(PickerMenu, { label: "Model", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
272
|
+
radixUi.DropdownMenu.RadioGroup,
|
|
273
|
+
{
|
|
274
|
+
value: selectedValue,
|
|
275
|
+
onValueChange: (next) => onChange(next === AGENT_OWN_MODEL ? null : next),
|
|
276
|
+
children: [
|
|
277
|
+
/* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.Label, { className: "px-2 pb-0.5 pt-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Agent models" }),
|
|
278
|
+
items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(PickerItem, { value: item.value, detail: item.detail, children: [
|
|
279
|
+
item.label,
|
|
280
|
+
item.isDefault ? " (default)" : ""
|
|
281
|
+
] }, item.value))
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
) })
|
|
285
|
+
] });
|
|
286
|
+
}
|
|
107
287
|
const NO_AGENT = "__athena__";
|
|
108
288
|
function ChatAgentPicker({ value, onChange, disabled = false, className }) {
|
|
109
289
|
var _a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-pickers.cjs","sources":["../../src/catalog/chat-pickers.tsx"],"sourcesContent":["import { BotIcon, CheckIcon, ChevronDownIcon, SparklesIcon } from 'lucide-react';\nimport { DropdownMenu } from 'radix-ui';\nimport { type ReactNode, useEffect, useRef, useState } from 'react';\nimport { usePortalContainer } from '../lib/owner-document';\nimport { portalSurfaceStyle } from '../lib/portal-surface';\nimport { cn } from '../lib/utils';\nimport { useAthenaThemeStyle } from '../provider/theme-style-context';\nimport {\n groupModelsByProvider,\n resolveCatalogModelId,\n useAthenaAgentCatalog,\n useAthenaModelCatalog,\n} from './runtime-catalog';\n\n/**\n * The composer's agent and model pickers: compact chips for `AthenaChat`'s `toolbarStart` slot\n * that open a menu, as ChatGPT's and Codex's composers do. They are controlled: the host keeps the\n * choice (and remembers it if it likes) and passes it to `AthenaProvider` as `model` and\n * `agent=\"collab_agent:<id>\"`. New messages run with the choice. The menus are Radix radio menus,\n * so arrow keys, typeahead, Escape and focus return work as in any native menu.\n */\n\nconst CHIP_CLASS =\n 'inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50';\n\nconst ITEM_CLASS =\n 'relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-7 text-sm outline-none data-[highlighted]:bg-muted data-[state=checked]:font-medium';\n\n/** The \"Agent's own model\" item's value: a chosen agent runs the model its author set. */\nconst AGENT_OWN_MODEL = '__agent_own_model__';\n\n/** The menu body, portaled and themed like the SDK's popovers (it renders outside the provider). */\nfunction PickerMenu({ label, children }: { label: string; children: ReactNode }) {\n const themeStyle = useAthenaThemeStyle();\n const container = usePortalContainer();\n return (\n <DropdownMenu.Portal container={container}>\n <DropdownMenu.Content\n align=\"start\"\n sideOffset={4}\n collisionPadding={8}\n aria-label={label}\n // Its box and colours inline: no host stylesheet can take them away\n // (lib/portal-surface.ts).\n style={portalSurfaceStyle({ surface: 'popover', themeStyle })}\n className={cn(\n 'athena-sdk athena-sdk-chrome',\n 'z-50 block max-h-80 w-64 overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-none',\n )}\n >\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n );\n}\n\nfunction PickerItem({ value, children }: { value: string; children: ReactNode }) {\n return (\n <DropdownMenu.RadioItem value={value} className={ITEM_CLASS}>\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n <DropdownMenu.ItemIndicator className=\"absolute right-2 inline-flex\">\n <CheckIcon className=\"size-3.5\" aria-hidden />\n </DropdownMenu.ItemIndicator>\n </DropdownMenu.RadioItem>\n );\n}\n\nfunction PickerNote({ children, alert = false }: { children: ReactNode; alert?: boolean }) {\n return (\n <p\n className={cn('px-2 py-1.5 text-xs', alert ? 'text-destructive' : 'text-muted-foreground')}\n role={alert ? 'alert' : undefined}\n >\n {children}\n </p>\n );\n}\n\nexport interface ChatModelPickerProps {\n /** The chosen model id; `null` lets a selected agent run its own model. */\n value: string | null;\n onChange: (modelId: string | null) => void;\n /** The model a person who chose nothing runs, e.g. `claude-opus-5-5`. */\n defaultModelId: string;\n /** A collab agent is chosen: offer \"Agent's own model\" (`null`). */\n agentSelected?: boolean;\n disabled?: boolean;\n className?: string;\n}\n\n/** Which model new messages run, from the models the workspace allows this person. */\nexport function ChatModelPicker({\n value,\n onChange,\n defaultModelId,\n agentSelected = false,\n disabled = false,\n className,\n}: ChatModelPickerProps) {\n const catalog = useAthenaModelCatalog();\n const [open, setOpen] = useState(false);\n const models = catalog.data ?? [];\n const resolved =\n value === null && agentSelected\n ? null\n : resolveCatalogModelId({ stored: value, defaultModelId, models });\n const current = models.find((model) => model.id === resolved);\n const label = resolved === null ? 'Agent’s model' : (current?.label ?? resolved);\n // The host's choice is no longer offered (retired, or the workspace stopped allowing it): hand\n // the host the model the chip shows, so new messages run it instead of the dropped id. Once per\n // choice, so a host that keeps the old value is not asked again on every render.\n const replacedRef = useRef<string | null>(null);\n useEffect(() => {\n if (!catalog.isSuccess || value === null || resolved === null || resolved === value) return;\n if (models.some((model) => model.id === value) || replacedRef.current === value) return;\n replacedRef.current = value;\n onChange(resolved);\n }, [catalog.isSuccess, models, value, resolved, onChange]);\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(CHIP_CLASS, className)}\n disabled={disabled}\n aria-label={`Model: ${label}`}\n >\n <SparklesIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n <ChevronDownIcon className=\"size-3 shrink-0\" aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <PickerMenu label=\"Model\">\n <DropdownMenu.RadioGroup\n value={resolved ?? AGENT_OWN_MODEL}\n onValueChange={(next) => onChange(next === AGENT_OWN_MODEL ? null : next)}\n >\n {agentSelected && <PickerItem value={AGENT_OWN_MODEL}>Agent’s own model</PickerItem>}\n {catalog.isPending && <PickerNote>Loading models…</PickerNote>}\n {catalog.isError && <PickerNote alert>Couldn’t load the models. Try again in a moment.</PickerNote>}\n {groupModelsByProvider({ models }).map((group) => (\n <DropdownMenu.Group key={group.provider}>\n <DropdownMenu.Label className=\"px-2 pb-0.5 pt-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n {group.provider}\n </DropdownMenu.Label>\n {group.models.map((model) => (\n <PickerItem key={model.id} value={model.id}>\n {model.label}\n {model.status === 'LEGACY' ? ' (legacy)' : ''}\n </PickerItem>\n ))}\n </DropdownMenu.Group>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n\nexport interface ChatAgentPickerProps {\n /** The chosen collab agent's asset id; `null` is Athena. */\n value: string | null;\n onChange: (agentId: string | null) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/** The \"Athena\" item's value: no collab agent. */\nconst NO_AGENT = '__athena__';\n\n/** Who answers new messages: Athena, or a published collab agent the person can see. */\nexport function ChatAgentPicker({ value, onChange, disabled = false, className }: ChatAgentPickerProps) {\n const catalog = useAthenaAgentCatalog();\n const [open, setOpen] = useState(false);\n const agents = catalog.data ?? [];\n const label = value === null ? 'Athena' : (agents.find((agent) => agent.id === value)?.name ?? 'Agent');\n // The chosen agent is gone (unpublished, or no longer shared with this person): fall back to\n // Athena, so new messages do not target an agent they cannot reach. Once per choice.\n const clearedRef = useRef<string | null>(null);\n useEffect(() => {\n if (!catalog.isSuccess || value === null || clearedRef.current === value) return;\n if (agents.some((agent) => agent.id === value)) return;\n clearedRef.current = value;\n onChange(null);\n }, [catalog.isSuccess, agents, value, onChange]);\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(CHIP_CLASS, className)}\n disabled={disabled}\n aria-label={`Agent: ${label}`}\n >\n <BotIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n <ChevronDownIcon className=\"size-3 shrink-0\" aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <PickerMenu label=\"Agent\">\n <DropdownMenu.RadioGroup\n value={value ?? NO_AGENT}\n onValueChange={(next) => onChange(next === NO_AGENT ? null : next)}\n >\n <PickerItem value={NO_AGENT}>Athena</PickerItem>\n {catalog.isError && <PickerNote alert>Couldn’t load the agents. Try again in a moment.</PickerNote>}\n {agents.map((agent) => (\n <PickerItem key={agent.id} value={agent.id}>\n {agent.name}\n </PickerItem>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n"],"names":["useAthenaThemeStyle","usePortalContainer","jsx","DropdownMenu","portalSurfaceStyle","cn","CheckIcon","useAthenaModelCatalog","useState","resolveCatalogModelId","useRef","useEffect","jsxs","SparklesIcon","ChevronDownIcon","groupModelsByProvider","useAthenaAgentCatalog","BotIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat-pickers.cjs","sources":["../../src/catalog/chat-pickers.tsx"],"sourcesContent":["import { BotIcon, CheckIcon, ChevronDownIcon, SparklesIcon } from 'lucide-react';\nimport { DropdownMenu } from 'radix-ui';\nimport { type ReactNode, useContext, useEffect, useRef, useState } from 'react';\nimport { usePortalContainer } from '../lib/owner-document';\nimport { portalSurfaceStyle } from '../lib/portal-surface';\nimport { cn } from '../lib/utils';\nimport { AthenaAgentSelectionContext } from '../provider/agent-selection-context';\nimport { useAthenaThemeStyle } from '../provider/theme-style-context';\nimport { agentAssetIdOf } from './agent-model-options';\nimport {\n type AthenaAgentModelOptions,\n groupModelsByProvider,\n resolveCatalogModelId,\n useAgentModelChoices,\n useAthenaAgentCatalog,\n useAthenaModelCatalog,\n} from './runtime-catalog';\n\n/**\n * The composer's agent and model pickers: compact chips for `AthenaChat`'s `toolbarStart` slot\n * that open a menu, as ChatGPT's and Codex's composers do. They are controlled: the host keeps the\n * choice (and remembers it if it likes) and passes it to `AthenaProvider` as `model` and\n * `agent=\"collab_agent:<id>\"`. New messages run with the choice. The menus are Radix radio menus,\n * so arrow keys, typeahead, Escape and focus return work as in any native menu.\n */\n\nconst CHIP_CLASS =\n 'inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50';\n\n/** The chip without a menu: one choice, shown as a label. */\nconst STATIC_CHIP_CLASS =\n 'inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground';\n\nconst ITEM_CLASS =\n 'relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-7 text-sm outline-none data-[highlighted]:bg-muted data-[state=checked]:font-medium';\n\n/** The \"Agent's own model\" item's value: a chosen agent runs the model its author set. */\nconst AGENT_OWN_MODEL = '__agent_own_model__';\n\n/** What the chip says while a chosen agent's model is not known. */\nconst AGENT_MODEL_LABEL = 'Agent’s model';\n\n/** The menu body, portaled and themed like the SDK's popovers (it renders outside the provider). */\nfunction PickerMenu({ label, children }: { label: string; children: ReactNode }) {\n const themeStyle = useAthenaThemeStyle();\n const container = usePortalContainer();\n return (\n <DropdownMenu.Portal container={container}>\n <DropdownMenu.Content\n align=\"start\"\n sideOffset={4}\n collisionPadding={8}\n aria-label={label}\n // Its box and colours inline: no host stylesheet can take them away\n // (lib/portal-surface.ts).\n style={portalSurfaceStyle({ surface: 'popover', themeStyle })}\n className={cn(\n 'athena-sdk athena-sdk-chrome',\n 'z-50 block max-h-80 w-64 overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-none',\n )}\n >\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n );\n}\n\nfunction PickerItem({\n value,\n detail,\n children,\n}: {\n value: string;\n /** A second, muted line (the model behind an author's label, or why the item is listed). */\n detail?: ReactNode;\n children: ReactNode;\n}) {\n return (\n <DropdownMenu.RadioItem value={value} className={ITEM_CLASS}>\n {detail ? (\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate\">{children}</span>\n <span className=\"truncate text-xs font-normal text-muted-foreground\">{detail}</span>\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n )}\n <DropdownMenu.ItemIndicator className=\"absolute right-2 inline-flex\">\n <CheckIcon className=\"size-3.5\" aria-hidden />\n </DropdownMenu.ItemIndicator>\n </DropdownMenu.RadioItem>\n );\n}\n\nfunction PickerNote({ children, alert = false }: { children: ReactNode; alert?: boolean }) {\n return (\n <p\n className={cn('px-2 py-1.5 text-xs', alert ? 'text-destructive' : 'text-muted-foreground')}\n role={alert ? 'alert' : undefined}\n >\n {children}\n </p>\n );\n}\n\nexport interface ChatModelPickerProps {\n /** The chosen model id; `null` lets a selected agent run its own model. */\n value: string | null;\n onChange: (modelId: string | null) => void;\n /** The model a person who chose nothing runs, e.g. `claude-opus-5-5`. */\n defaultModelId: string;\n /**\n * A collab agent is chosen: the picker offers the workspace's models and\n * \"Agent's own model\" (`null`), as before, unless the agent restricts its\n * models (its \"Allow any workspace model\" switch is off), when it offers\n * exactly the agent's own (`useAthenaAgentModelOptions`). Which agent:\n * `agent`, else the one the surrounding `AthenaProvider` runs as.\n */\n agentSelected?: boolean;\n /**\n * The chosen collab agent, as its asset id or `collab_agent:<id>` (implies\n * `agentSelected`). `null` is no agent.\n */\n agent?: string | null;\n /**\n * The collab channel the chat runs on (its model override is the default\n * there). Defaults to the provider's `channel` when the agent is the\n * provider's.\n */\n channel?: string | null;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Which model new messages run, from the models the workspace allows this\n * person; with an agent chosen, also \"Agent's own model\" (`null`), or exactly\n * the models its author listed when the agent restricts its models\n * (`allowAnyModel: false`, opt-in per agent). The host passes the choice to\n * `AthenaProvider` as `model`; a change reaches an open session too (the\n * provider writes it to the session's server config).\n */\nexport function ChatModelPicker({\n value,\n onChange,\n defaultModelId,\n agentSelected = false,\n agent,\n channel,\n disabled = false,\n className,\n}: ChatModelPickerProps) {\n const providerSelection = useContext(AthenaAgentSelectionContext);\n const agentAssetId =\n agent !== undefined\n ? agentAssetIdOf(agent)\n : agentSelected\n ? (providerSelection?.agentAssetId ?? null)\n : null;\n if (agentAssetId !== null) {\n const agentChannel =\n channel !== undefined\n ? channel\n : providerSelection?.agentAssetId === agentAssetId\n ? providerSelection.channel\n : null;\n return (\n <AgentAwareModelPicker\n agentAssetId={agentAssetId}\n channel={agentChannel}\n value={value}\n onChange={onChange}\n defaultModelId={defaultModelId}\n disabled={disabled}\n className={className}\n />\n );\n }\n return (\n <WorkspaceModelPicker\n value={value}\n onChange={onChange}\n defaultModelId={defaultModelId}\n agentSelected={agentSelected}\n disabled={disabled}\n className={className}\n />\n );\n}\n\n/**\n * The picker with a collab agent chosen. The agent is read first: one that\n * restricts its models gets {@link AgentModelMenu}; every other agent (the\n * default, and one this person cannot read) gets the workspace menu as before,\n * its \"Agent's own model\" naming the agent's default when known. Until the\n * read settles the workspace menu shows but replaces nothing on the host's\n * behalf, since the host's model may be one only the agent offers.\n */\nfunction AgentAwareModelPicker({\n agentAssetId,\n channel,\n value,\n onChange,\n defaultModelId,\n disabled,\n className,\n}: {\n agentAssetId: string;\n channel: string | null;\n value: string | null;\n onChange: (modelId: string | null) => void;\n defaultModelId: string;\n disabled: boolean;\n className?: string;\n}) {\n // One query client for the agent read and the catalog both menus name models from.\n const { choices, modelLabel, catalog } = useAgentModelChoices({ agent: agentAssetId, channel });\n if (choices.status === 'ready' && !choices.allowAnyModel) {\n return (\n <AgentModelMenu\n choices={choices}\n modelLabel={modelLabel}\n value={value}\n onChange={onChange}\n disabled={disabled}\n className={className}\n />\n );\n }\n return (\n <WorkspaceModelMenu\n catalog={catalog}\n value={value}\n onChange={onChange}\n defaultModelId={defaultModelId}\n agentSelected\n agentDefaultLabel={choices.defaultModel === null ? null : modelLabel(choices.defaultModel)}\n holdReplacement={choices.status === 'loading'}\n disabled={disabled}\n className={className}\n />\n );\n}\n\n/** The model picker over the workspace's catalog, with no agent chosen (or none it can name). */\nfunction WorkspaceModelPicker(props: {\n value: string | null;\n onChange: (modelId: string | null) => void;\n defaultModelId: string;\n agentSelected: boolean;\n disabled: boolean;\n className?: string;\n}) {\n const catalog = useAthenaModelCatalog();\n return <WorkspaceModelMenu catalog={catalog} {...props} />;\n}\n\n/** The workspace catalog's menu (the picker as it was before agents could restrict models). */\nfunction WorkspaceModelMenu({\n catalog,\n value,\n onChange,\n defaultModelId,\n agentSelected,\n agentDefaultLabel = null,\n holdReplacement = false,\n disabled,\n className,\n}: {\n catalog: ReturnType<typeof useAthenaModelCatalog>;\n value: string | null;\n onChange: (modelId: string | null) => void;\n defaultModelId: string;\n agentSelected: boolean;\n /** The chosen agent's default model (its channel's override when it has one), named under \"Agent's own model\". */\n agentDefaultLabel?: string | null;\n /** Replace no unoffered choice yet (the chosen agent is still being read). */\n holdReplacement?: boolean;\n disabled: boolean;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n const models = catalog.data ?? [];\n const resolved =\n value === null && agentSelected\n ? null\n : resolveCatalogModelId({ stored: value, defaultModelId, models });\n const current = models.find((model) => model.id === resolved);\n const label = resolved === null ? 'Agent’s model' : (current?.label ?? resolved);\n // The host's choice is no longer offered (retired, or the workspace stopped allowing it): hand\n // the host the model the chip shows, so new messages run it instead of the dropped id. Once per\n // choice, so a host that keeps the old value is not asked again on every render.\n const replacedRef = useRef<string | null>(null);\n useEffect(() => {\n if (holdReplacement) return;\n if (!catalog.isSuccess || value === null || resolved === null || resolved === value) return;\n if (models.some((model) => model.id === value) || replacedRef.current === value) return;\n replacedRef.current = value;\n onChange(resolved);\n }, [holdReplacement, catalog.isSuccess, models, value, resolved, onChange]);\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(CHIP_CLASS, className)}\n disabled={disabled}\n aria-label={`Model: ${label}`}\n >\n <SparklesIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n <ChevronDownIcon className=\"size-3 shrink-0\" aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <PickerMenu label=\"Model\">\n <DropdownMenu.RadioGroup\n value={resolved ?? AGENT_OWN_MODEL}\n onValueChange={(next) => onChange(next === AGENT_OWN_MODEL ? null : next)}\n >\n {agentSelected && (\n <PickerItem value={AGENT_OWN_MODEL} detail={agentDefaultLabel}>\n Agent’s own model\n </PickerItem>\n )}\n {catalog.isPending && <PickerNote>Loading models…</PickerNote>}\n {catalog.isError && <PickerNote alert>Couldn’t load the models. Try again in a moment.</PickerNote>}\n {groupModelsByProvider({ models }).map((group) => (\n <DropdownMenu.Group key={group.provider}>\n <DropdownMenu.Label className=\"px-2 pb-0.5 pt-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n {group.provider}\n </DropdownMenu.Label>\n {group.models.map((model) => (\n <PickerItem key={model.id} value={model.id}>\n {model.label}\n {model.status === 'LEGACY' ? ' (legacy)' : ''}\n </PickerItem>\n ))}\n </DropdownMenu.Group>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n\n/** One item of the agent's model menu. */\ninterface AgentModelItem {\n /** The radio value: a model id, or {@link AGENT_OWN_MODEL} for \"the agent's default\" (`null`). */\n value: string;\n label: string;\n isDefault: boolean;\n detail: string | null;\n}\n\n/**\n * The menu of a chosen collab agent that restricts its models: exactly its own\n * (`useAthenaAgentModelOptions`), the default as `null`. One choice is a label;\n * two or more a menu. Nothing is replaced on the host's behalf: a host choice\n * the agent does not list (an older pick) is shown and listed as it is, as is\n * a model the session pins outside the agent's list. A host choice that names\n * the default model explicitly is a pin, which the agent's next default would\n * not follow, so the menu then also offers \"Agent's own model\" (`null`).\n */\nfunction AgentModelMenu({\n choices,\n modelLabel,\n value,\n onChange,\n disabled,\n className,\n}: {\n choices: AthenaAgentModelOptions;\n modelLabel: (model: string) => string;\n value: string | null;\n onChange: (modelId: string | null) => void;\n disabled: boolean;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n const pinsDefault = value !== null && value === choices.defaultModel;\n const items: AgentModelItem[] = choices.options.map((option) => {\n const display = modelLabel(option.model);\n return {\n value: option.isDefault && !pinsDefault ? AGENT_OWN_MODEL : option.model,\n label: option.label,\n isDefault: option.isDefault,\n detail: option.pinnedOutside\n ? 'Set for this conversation outside the agent'\n : display === option.label\n ? null\n : display,\n };\n });\n if (value !== null && !choices.options.some((option) => option.model === value)) {\n items.push({\n value,\n label: modelLabel(value),\n isDefault: false,\n detail: 'Not one of the agent’s models',\n });\n }\n if (pinsDefault) {\n items.push({\n value: AGENT_OWN_MODEL,\n label: 'Agent’s own model',\n isDefault: false,\n detail: 'Follows the agent’s default',\n });\n }\n const selectedValue = value ?? AGENT_OWN_MODEL;\n const selected = items.find((item) => item.value === selectedValue) ?? null;\n const label = selected?.label || AGENT_MODEL_LABEL;\n\n if (items.length < 2) {\n return (\n <span\n role=\"img\"\n aria-label={`Model: ${label}`}\n title={selected ? `This agent runs ${label}` : 'This agent runs its own model'}\n data-slot=\"chat-model-picker-label\"\n className={cn(STATIC_CHIP_CLASS, className)}\n >\n <SparklesIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n </span>\n );\n }\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(CHIP_CLASS, className)}\n disabled={disabled}\n aria-label={`Model: ${label}`}\n >\n <SparklesIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n <ChevronDownIcon className=\"size-3 shrink-0\" aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <PickerMenu label=\"Model\">\n <DropdownMenu.RadioGroup\n value={selectedValue}\n onValueChange={(next) => onChange(next === AGENT_OWN_MODEL ? null : next)}\n >\n <DropdownMenu.Label className=\"px-2 pb-0.5 pt-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n Agent models\n </DropdownMenu.Label>\n {items.map((item) => (\n <PickerItem key={item.value} value={item.value} detail={item.detail}>\n {item.label}\n {item.isDefault ? ' (default)' : ''}\n </PickerItem>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n\nexport interface ChatAgentPickerProps {\n /** The chosen collab agent's asset id; `null` is Athena. */\n value: string | null;\n onChange: (agentId: string | null) => void;\n disabled?: boolean;\n className?: string;\n}\n\n/** The \"Athena\" item's value: no collab agent. */\nconst NO_AGENT = '__athena__';\n\n/** Who answers new messages: Athena, or a published collab agent the person can see. */\nexport function ChatAgentPicker({ value, onChange, disabled = false, className }: ChatAgentPickerProps) {\n const catalog = useAthenaAgentCatalog();\n const [open, setOpen] = useState(false);\n const agents = catalog.data ?? [];\n const label = value === null ? 'Athena' : (agents.find((agent) => agent.id === value)?.name ?? 'Agent');\n // The chosen agent is gone (unpublished, or no longer shared with this person): fall back to\n // Athena, so new messages do not target an agent they cannot reach. Once per choice.\n const clearedRef = useRef<string | null>(null);\n useEffect(() => {\n if (!catalog.isSuccess || value === null || clearedRef.current === value) return;\n if (agents.some((agent) => agent.id === value)) return;\n clearedRef.current = value;\n onChange(null);\n }, [catalog.isSuccess, agents, value, onChange]);\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(CHIP_CLASS, className)}\n disabled={disabled}\n aria-label={`Agent: ${label}`}\n >\n <BotIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"truncate\">{label}</span>\n <ChevronDownIcon className=\"size-3 shrink-0\" aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <PickerMenu label=\"Agent\">\n <DropdownMenu.RadioGroup\n value={value ?? NO_AGENT}\n onValueChange={(next) => onChange(next === NO_AGENT ? null : next)}\n >\n <PickerItem value={NO_AGENT}>Athena</PickerItem>\n {catalog.isError && <PickerNote alert>Couldn’t load the agents. Try again in a moment.</PickerNote>}\n {agents.map((agent) => (\n <PickerItem key={agent.id} value={agent.id}>\n {agent.name}\n </PickerItem>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n"],"names":["useAthenaThemeStyle","usePortalContainer","jsx","DropdownMenu","portalSurfaceStyle","cn","jsxs","CheckIcon","useContext","AthenaAgentSelectionContext","agentAssetIdOf","useAgentModelChoices","useAthenaModelCatalog","useState","resolveCatalogModelId","useRef","useEffect","SparklesIcon","ChevronDownIcon","groupModelsByProvider","useAthenaAgentCatalog","BotIcon"],"mappings":";;;;;;;;;;;;;AA0BA,MAAM,aACJ;AAGF,MAAM,oBACJ;AAEF,MAAM,aACJ;AAGF,MAAM,kBAAkB;AAGxB,MAAM,oBAAoB;AAG1B,SAAS,WAAW,EAAE,OAAO,YAAoD;AAC/E,QAAM,aAAaA,kBAAAA,oBAAA;AACnB,QAAM,YAAYC,kBAAAA,mBAAA;AAClB,SACEC,2BAAAA,IAACC,QAAAA,aAAa,QAAb,EAAoB,WACnB,UAAAD,2BAAAA;AAAAA,IAACC,QAAAA,aAAa;AAAA,IAAb;AAAA,MACC,OAAM;AAAA,MACN,YAAY;AAAA,MACZ,kBAAkB;AAAA,MAClB,cAAY;AAAA,MAGZ,OAAOC,cAAAA,mBAAmB,EAAE,SAAS,WAAW,YAAY;AAAA,MAC5D,WAAWC,OAAAA;AAAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAGD;AAAA,IAAA;AAAA,EAAA,GAEL;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,yCACGF,QAAAA,aAAa,WAAb,EAAuB,OAAc,WAAW,YAC9C,UAAA;AAAA,IAAA,SACCG,2BAAAA,KAAC,QAAA,EAAK,WAAU,gCACd,UAAA;AAAA,MAAAJ,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,SAAA,CAAS;AAAA,MACrCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,sDAAsD,UAAA,OAAA,CAAO;AAAA,IAAA,EAAA,CAC/E,IAEAA,2BAAAA,IAAC,QAAA,EAAK,WAAU,2BAA2B,UAAS;AAAA,IAEtDA,2BAAAA,IAACC,QAAAA,aAAa,eAAb,EAA2B,WAAU,gCACpC,UAAAD,2BAAAA,IAACK,YAAAA,WAAA,EAAU,WAAU,YAAW,eAAW,KAAA,CAAC,EAAA,CAC9C;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS,WAAW,EAAE,UAAU,QAAQ,SAAmD;AACzF,SACEL,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWG,OAAAA,GAAG,uBAAuB,QAAQ,qBAAqB,uBAAuB;AAAA,MACzF,MAAM,QAAQ,UAAU;AAAA,MAEvB;AAAA,IAAA;AAAA,EAAA;AAGP;AAuCO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,GAAyB;AACvB,QAAM,oBAAoBG,MAAAA,WAAWC,iDAA2B;AAChE,QAAM,eACJ,UAAU,SACNC,iCAAe,KAAK,IACpB,iBACG,uDAAmB,iBAAgB,OACpC;AACR,MAAI,iBAAiB,MAAM;AACzB,UAAM,eACJ,YAAY,SACR,WACA,uDAAmB,kBAAiB,eAClC,kBAAkB,UAClB;AACR,WACER,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACA,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAUA,SAAS,sBAAsB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AAED,QAAM,EAAE,SAAS,YAAY,QAAA,IAAYS,eAAAA,qBAAqB,EAAE,OAAO,cAAc,SAAS;AAC9F,MAAI,QAAQ,WAAW,WAAW,CAAC,QAAQ,eAAe;AACxD,WACET,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACA,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAa;AAAA,MACb,mBAAmB,QAAQ,iBAAiB,OAAO,OAAO,WAAW,QAAQ,YAAY;AAAA,MACzF,iBAAiB,QAAQ,WAAW;AAAA,MACpC;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAGA,SAAS,qBAAqB,OAO3B;AACD,QAAM,UAAUU,eAAAA,sBAAA;AAChB,SAAOV,2BAAAA,IAAC,oBAAA,EAAmB,SAAmB,GAAG,MAAA,CAAO;AAC1D;AAGA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB;AAAA,EACA;AACF,GAYG;AACD,QAAM,CAAC,MAAM,OAAO,IAAIW,MAAAA,SAAS,KAAK;AACtC,QAAM,SAAS,QAAQ,QAAQ,CAAA;AAC/B,QAAM,WACJ,UAAU,QAAQ,gBACd,OACAC,qCAAsB,EAAE,QAAQ,OAAO,gBAAgB,OAAA,CAAQ;AACrE,QAAM,UAAU,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,QAAQ;AAC5D,QAAM,QAAQ,aAAa,OAAO,mBAAmB,mCAAS,UAAS;AAIvE,QAAM,cAAcC,MAAAA,OAAsB,IAAI;AAC9CC,QAAAA,UAAU,MAAM;AACd,QAAI,gBAAiB;AACrB,QAAI,CAAC,QAAQ,aAAa,UAAU,QAAQ,aAAa,QAAQ,aAAa,MAAO;AACrF,QAAI,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,KAAK,YAAY,YAAY,MAAO;AACjF,gBAAY,UAAU;AACtB,aAAS,QAAQ;AAAA,EACnB,GAAG,CAAC,iBAAiB,QAAQ,WAAW,QAAQ,OAAO,UAAU,QAAQ,CAAC;AAC1E,yCACGb,QAAAA,aAAa,MAAb,EAAkB,MAAY,cAAc,SAC3C,UAAA;AAAA,IAAAD,2BAAAA,IAACC,QAAAA,aAAa,SAAb,EAAqB,SAAO,MAC3B,UAAAG,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWD,OAAAA,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACA,cAAY,UAAU,KAAK;AAAA,QAE3B,UAAA;AAAA,UAAAH,2BAAAA,IAACe,YAAAA,cAAA,EAAa,WAAU,qBAAoB,eAAW,MAAC;AAAA,UACxDf,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,UAAA,OAAM;AAAA,UAClCA,2BAAAA,IAACgB,YAAAA,iBAAA,EAAgB,WAAU,mBAAkB,eAAW,KAAA,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,GAE7D;AAAA,IACAhB,2BAAAA,IAAC,YAAA,EAAW,OAAM,SAChB,UAAAI,2BAAAA;AAAAA,MAACH,QAAAA,aAAa;AAAA,MAAb;AAAA,QACC,OAAO,YAAY;AAAA,QACnB,eAAe,CAAC,SAAS,SAAS,SAAS,kBAAkB,OAAO,IAAI;AAAA,QAEvE,UAAA;AAAA,UAAA,gDACE,YAAA,EAAW,OAAO,iBAAiB,QAAQ,mBAAmB,UAAA,qBAE/D;AAAA,UAED,QAAQ,aAAaD,2BAAAA,IAAC,YAAA,EAAW,UAAA,mBAAe;AAAA,UAChD,QAAQ,WAAWA,2BAAAA,IAAC,YAAA,EAAW,OAAK,MAAC,UAAA,oDAAgD;AAAA,UACrFiB,eAAAA,sBAAsB,EAAE,QAAQ,EAAE,IAAI,CAAC,UACtCb,2BAAAA,KAACH,QAAAA,aAAa,OAAb,EACC,UAAA;AAAA,YAAAD,+BAACC,QAAAA,aAAa,OAAb,EAAmB,WAAU,4FAC3B,gBAAM,UACT;AAAA,YACC,MAAM,OAAO,IAAI,CAAC,UACjBG,2BAAAA,KAAC,YAAA,EAA0B,OAAO,MAAM,IACrC,UAAA;AAAA,cAAA,MAAM;AAAA,cACN,MAAM,WAAW,WAAW,cAAc;AAAA,YAAA,EAAA,GAF5B,MAAM,EAGvB,CACD;AAAA,UAAA,EAAA,GATsB,MAAM,QAU/B,CACD;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;AAoBA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,CAAC,MAAM,OAAO,IAAIO,MAAAA,SAAS,KAAK;AACtC,QAAM,cAAc,UAAU,QAAQ,UAAU,QAAQ;AACxD,QAAM,QAA0B,QAAQ,QAAQ,IAAI,CAAC,WAAW;AAC9D,UAAM,UAAU,WAAW,OAAO,KAAK;AACvC,WAAO;AAAA,MACL,OAAO,OAAO,aAAa,CAAC,cAAc,kBAAkB,OAAO;AAAA,MACnE,OAAO,OAAO;AAAA,MACd,WAAW,OAAO;AAAA,MAClB,QAAQ,OAAO,gBACX,gDACA,YAAY,OAAO,QACjB,OACA;AAAA,IAAA;AAAA,EAEV,CAAC;AACD,MAAI,UAAU,QAAQ,CAAC,QAAQ,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,KAAK,GAAG;AAC/E,UAAM,KAAK;AAAA,MACT;AAAA,MACA,OAAO,WAAW,KAAK;AAAA,MACvB,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,CACT;AAAA,EACH;AACA,MAAI,aAAa;AACf,UAAM,KAAK;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,CACT;AAAA,EACH;AACA,QAAM,gBAAgB,SAAS;AAC/B,QAAM,WAAW,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,aAAa,KAAK;AACvE,QAAM,SAAQ,qCAAU,UAAS;AAEjC,MAAI,MAAM,SAAS,GAAG;AACpB,WACEP,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY,UAAU,KAAK;AAAA,QAC3B,OAAO,WAAW,mBAAmB,KAAK,KAAK;AAAA,QAC/C,aAAU;AAAA,QACV,WAAWD,OAAAA,GAAG,mBAAmB,SAAS;AAAA,QAE1C,UAAA;AAAA,UAAAH,2BAAAA,IAACe,YAAAA,cAAA,EAAa,WAAU,qBAAoB,eAAW,MAAC;AAAA,UACxDf,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,UAAA,MAAA,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGxC;AACA,yCACGC,QAAAA,aAAa,MAAb,EAAkB,MAAY,cAAc,SAC3C,UAAA;AAAA,IAAAD,2BAAAA,IAACC,QAAAA,aAAa,SAAb,EAAqB,SAAO,MAC3B,UAAAG,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWD,OAAAA,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACA,cAAY,UAAU,KAAK;AAAA,QAE3B,UAAA;AAAA,UAAAH,2BAAAA,IAACe,YAAAA,cAAA,EAAa,WAAU,qBAAoB,eAAW,MAAC;AAAA,UACxDf,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,UAAA,OAAM;AAAA,UAClCA,2BAAAA,IAACgB,YAAAA,iBAAA,EAAgB,WAAU,mBAAkB,eAAW,KAAA,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,GAE7D;AAAA,IACAhB,2BAAAA,IAAC,YAAA,EAAW,OAAM,SAChB,UAAAI,2BAAAA;AAAAA,MAACH,QAAAA,aAAa;AAAA,MAAb;AAAA,QACC,OAAO;AAAA,QACP,eAAe,CAAC,SAAS,SAAS,SAAS,kBAAkB,OAAO,IAAI;AAAA,QAExE,UAAA;AAAA,UAAAD,2BAAAA,IAACC,QAAAA,aAAa,OAAb,EAAmB,WAAU,4FAA2F,UAAA,gBAEzH;AAAA,UACC,MAAM,IAAI,CAAC,SACVG,2BAAAA,KAAC,YAAA,EAA4B,OAAO,KAAK,OAAO,QAAQ,KAAK,QAC1D,UAAA;AAAA,YAAA,KAAK;AAAA,YACL,KAAK,YAAY,eAAe;AAAA,UAAA,EAAA,GAFlB,KAAK,KAGtB,CACD;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;AAWA,MAAM,WAAW;AAGV,SAAS,gBAAgB,EAAE,OAAO,UAAU,WAAW,OAAO,aAAmC;;AACtG,QAAM,UAAUc,eAAAA,sBAAA;AAChB,QAAM,CAAC,MAAM,OAAO,IAAIP,MAAAA,SAAS,KAAK;AACtC,QAAM,SAAS,QAAQ,QAAQ,CAAA;AAC/B,QAAM,QAAQ,UAAU,OAAO,aAAY,YAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,MAAzC,mBAA4C,SAAQ;AAG/F,QAAM,aAAaE,MAAAA,OAAsB,IAAI;AAC7CC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,QAAQ,aAAa,UAAU,QAAQ,WAAW,YAAY,MAAO;AAC1E,QAAI,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,EAAG;AAChD,eAAW,UAAU;AACrB,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,QAAQ,WAAW,QAAQ,OAAO,QAAQ,CAAC;AAC/C,yCACGb,QAAAA,aAAa,MAAb,EAAkB,MAAY,cAAc,SAC3C,UAAA;AAAA,IAAAD,2BAAAA,IAACC,QAAAA,aAAa,SAAb,EAAqB,SAAO,MAC3B,UAAAG,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWD,OAAAA,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACA,cAAY,UAAU,KAAK;AAAA,QAE3B,UAAA;AAAA,UAAAH,2BAAAA,IAACmB,YAAAA,SAAA,EAAQ,WAAU,qBAAoB,eAAW,MAAC;AAAA,UACnDnB,2BAAAA,IAAC,QAAA,EAAK,WAAU,YAAY,UAAA,OAAM;AAAA,UAClCA,2BAAAA,IAACgB,YAAAA,iBAAA,EAAgB,WAAU,mBAAkB,eAAW,KAAA,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,GAE7D;AAAA,IACAhB,2BAAAA,IAAC,YAAA,EAAW,OAAM,SAChB,UAAAI,2BAAAA;AAAAA,MAACH,QAAAA,aAAa;AAAA,MAAb;AAAA,QACC,OAAO,SAAS;AAAA,QAChB,eAAe,CAAC,SAAS,SAAS,SAAS,WAAW,OAAO,IAAI;AAAA,QAEjE,UAAA;AAAA,UAAAD,2BAAAA,IAAC,YAAA,EAAW,OAAO,UAAU,UAAA,UAAM;AAAA,UAClC,QAAQ,WAAWA,2BAAAA,IAAC,YAAA,EAAW,OAAK,MAAC,UAAA,oDAAgD;AAAA,UACrF,OAAO,IAAI,CAAC,UACXA,2BAAAA,IAAC,YAAA,EAA0B,OAAO,MAAM,IACrC,UAAA,MAAM,KAAA,GADQ,MAAM,EAEvB,CACD;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;;;"}
|