@athenaintel/react 0.35.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +4 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.js +4 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +11 -0
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +11 -0
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +24 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js +24 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/catalog/agent-mode-menu.cjs +115 -0
- package/dist/catalog/agent-mode-menu.cjs.map +1 -0
- package/dist/catalog/agent-mode-menu.d.ts +101 -0
- package/dist/catalog/agent-mode-menu.js +115 -0
- package/dist/catalog/agent-mode-menu.js.map +1 -0
- package/dist/catalog/chat-pickers.cjs +51 -0
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +28 -0
- package/dist/catalog/chat-pickers.js +52 -1
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +4 -0
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +16 -0
- package/dist/catalog/runtime-catalog.js +5 -1
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/catalog/use-athena-chat-mode.cjs +139 -0
- package/dist/catalog/use-athena-chat-mode.cjs.map +1 -0
- package/dist/catalog/use-athena-chat-mode.d.ts +43 -0
- package/dist/catalog/use-athena-chat-mode.js +139 -0
- package/dist/catalog/use-athena-chat-mode.js.map +1 -0
- package/dist/chat/AthenaChat.cjs +2 -0
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +2 -0
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat-ui/statewire.cjs +3 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +4 -2
- package/dist/chat-ui/statewire.js +3 -0
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +149 -26
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +10 -3
- package/dist/chat-ui/thread/statewire-history-edge.js +152 -29
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +52 -1
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +11 -1
- package/dist/provider/AthenaProvider.js +53 -2
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/chat-mode-context.cjs +6 -0
- package/dist/provider/chat-mode-context.cjs.map +1 -0
- package/dist/provider/chat-mode-context.d.ts +35 -0
- package/dist/provider/chat-mode-context.js +6 -0
- package/dist/provider/chat-mode-context.js.map +1 -0
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/statewire-run-config.cjs +10 -6
- package/dist/runtime/statewire-run-config.cjs.map +1 -1
- package/dist/runtime/statewire-run-config.d.ts +7 -0
- package/dist/runtime/statewire-run-config.js +10 -6
- package/dist/runtime/statewire-run-config.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const BASE_MODE_ID = "base";
|
|
2
|
+
const WEB_ENTRY = "web";
|
|
3
|
+
const MAX_MODE_KEY_LENGTH = 64;
|
|
4
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
const isModeKey = (value) => typeof value === "string" && value.length > 0 && value.length <= MAX_MODE_KEY_LENGTH;
|
|
6
|
+
const decoded = (value) => {
|
|
7
|
+
if (typeof value !== "string") return value;
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(value);
|
|
10
|
+
} catch {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const uniqueKeys = (value) => {
|
|
15
|
+
const kept = [];
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
for (const entry of value) {
|
|
18
|
+
if (isModeKey(entry) && !kept.includes(entry)) kept.push(entry);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return kept;
|
|
22
|
+
};
|
|
23
|
+
function publishedAgentModeSource(athenaMetadata) {
|
|
24
|
+
if (!isRecord(athenaMetadata) || !athenaMetadata.published_version_id) return null;
|
|
25
|
+
const config = athenaMetadata.published_config;
|
|
26
|
+
if (!isRecord(config)) return null;
|
|
27
|
+
const agentModes = decoded(config.agentModes);
|
|
28
|
+
const stored = isRecord(agentModes) ? agentModes : {};
|
|
29
|
+
const startModes = {};
|
|
30
|
+
if (isRecord(stored.startModes)) {
|
|
31
|
+
for (const [channel, mode] of Object.entries(stored.startModes)) {
|
|
32
|
+
if (isModeKey(channel) && isModeKey(mode)) startModes[channel] = mode;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const switchModes = {};
|
|
36
|
+
if (isRecord(stored.switchModes)) {
|
|
37
|
+
for (const [channel, targets] of Object.entries(stored.switchModes)) {
|
|
38
|
+
const kept = uniqueKeys(targets);
|
|
39
|
+
if (isModeKey(channel) && kept.length > 0) switchModes[channel] = kept;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const channels = {};
|
|
43
|
+
const customChannels = decoded(config.customChannels);
|
|
44
|
+
if (Array.isArray(customChannels)) {
|
|
45
|
+
for (const entry of customChannels) {
|
|
46
|
+
if (!isRecord(entry) || !isModeKey(entry.id) || entry.id in channels) continue;
|
|
47
|
+
const name = typeof entry.name === "string" ? entry.name.trim() : "";
|
|
48
|
+
channels[entry.id] = { label: name || entry.id, enabled: entry.enabled !== false };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
modes: uniqueKeys(stored.modes).filter((id) => id !== BASE_MODE_ID),
|
|
53
|
+
startModes,
|
|
54
|
+
switchModes,
|
|
55
|
+
lockedChannels: uniqueKeys(stored.lockedChannels),
|
|
56
|
+
channels
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function agentModeEntry({
|
|
60
|
+
source,
|
|
61
|
+
channel
|
|
62
|
+
}) {
|
|
63
|
+
return channel && isCustomEntry({ source, channel }) ? channel : WEB_ENTRY;
|
|
64
|
+
}
|
|
65
|
+
const isCustomEntry = ({ source, channel }) => channel !== BASE_MODE_ID && !source.modes.includes(channel) && channel in source.channels;
|
|
66
|
+
function agentModeOfChannel({
|
|
67
|
+
source,
|
|
68
|
+
channel
|
|
69
|
+
}) {
|
|
70
|
+
return isCustomEntry({ source, channel }) ? source.startModes[channel] ?? channel : channel;
|
|
71
|
+
}
|
|
72
|
+
const optionLabel = ({ source, id }) => {
|
|
73
|
+
var _a;
|
|
74
|
+
return id === BASE_MODE_ID ? "Default" : ((_a = source.channels[id]) == null ? void 0 : _a.label) ?? id;
|
|
75
|
+
};
|
|
76
|
+
function agentModeMenu({
|
|
77
|
+
source,
|
|
78
|
+
channel,
|
|
79
|
+
hostModes
|
|
80
|
+
}) {
|
|
81
|
+
var _a;
|
|
82
|
+
const entry = agentModeEntry({ source, channel });
|
|
83
|
+
const startModeId = source.startModes[entry] ?? (entry === WEB_ENTRY ? BASE_MODE_ID : entry);
|
|
84
|
+
const ownMode = channel && agentModeOfChannel({ source, channel }) === channel ? [channel] : [];
|
|
85
|
+
const offered = /* @__PURE__ */ new Set([startModeId, ...ownMode, ...source.switchModes[entry] ?? []]);
|
|
86
|
+
const options = [];
|
|
87
|
+
for (const id of hostModes) {
|
|
88
|
+
if (!offered.has(id) || options.some((option) => option.id === id)) continue;
|
|
89
|
+
if (id !== BASE_MODE_ID && ((_a = source.channels[id]) == null ? void 0 : _a.enabled) === false) continue;
|
|
90
|
+
options.push({ id, label: optionLabel({ source, id }) });
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
entry,
|
|
94
|
+
startModeId,
|
|
95
|
+
firstSendModeId: channel ? agentModeOfChannel({ source, channel }) : startModeId,
|
|
96
|
+
options,
|
|
97
|
+
locked: source.lockedChannels.includes(entry)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function sessionChannelFromMetadata(athenaMetadata) {
|
|
101
|
+
if (!isRecord(athenaMetadata)) return null;
|
|
102
|
+
const current = athenaMetadata.collab_current_channel_id;
|
|
103
|
+
if (isModeKey(current)) return current;
|
|
104
|
+
const stamp = athenaMetadata.collab_channel_id;
|
|
105
|
+
return isModeKey(stamp) ? stamp : null;
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
BASE_MODE_ID,
|
|
109
|
+
agentModeEntry,
|
|
110
|
+
agentModeMenu,
|
|
111
|
+
agentModeOfChannel,
|
|
112
|
+
publishedAgentModeSource,
|
|
113
|
+
sessionChannelFromMetadata
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=agent-mode-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-mode-menu.js","sources":["../../src/catalog/agent-mode-menu.ts"],"sourcesContent":["/**\n * A collab agent's mode menu for an SDK chat, from its published definition.\n *\n * A chat offers the modes a session entered through its channel may run in,\n * by the rule agora checks every switch with (`resolve_mode_switch`): the\n * channel's start mode, the channel itself, and the modes the agent's author\n * lists for it (`agentModes.switchModes[<entry>]`). A channel the author\n * locks (`agentModes.lockedChannels`) keeps each session in the mode it\n * starts in: people pick the mode before a session's first message, and it\n * stays. A custom channel that is not itself a mode is its own entry; no\n * channel, a mode or a built-in channel is the Default (Text) entry (`web`).\n *\n * The host lists which of those modes its menu shows (`AthenaProvider`'s\n * `modes`); a mode the agent does not offer there is left out, never sent.\n *\n * Pure, for `useAthenaChatMode` and the tests.\n */\n\n/** The id of the agent as configured, with no mode's overrides (agora's `base`). */\nexport const BASE_MODE_ID = 'base';\n\n/** The Default (Text) entry: chats that name no custom channel of their own. */\nconst WEB_ENTRY = 'web';\n\n/** agora's limit on a mode key's length (`_MAX_MODE_KEY_LENGTH`). */\nconst MAX_MODE_KEY_LENGTH = 64;\n\n/** What an agent's published definition says about its modes. */\nexport interface AgentModeSource {\n /** Custom channels the author marked as modes (`agentModes.modes`). */\n modes: readonly string[];\n /** Channel key → the mode its sessions start in (`agentModes.startModes`). */\n startModes: Readonly<Record<string, string>>;\n /** Entry channel key → the modes its sessions may switch to (`agentModes.switchModes`). */\n switchModes: Readonly<Record<string, readonly string[]>>;\n /** Entry channels that keep each session in its start mode (`agentModes.lockedChannels`). */\n lockedChannels: readonly string[];\n /** The agent's custom channels by id (`customChannels`). */\n channels: Readonly<Record<string, { label: string; enabled: boolean }>>;\n}\n\n/** One mode a chat may run in. */\nexport interface AthenaChatModeOption {\n /** What a send names as `collab_channel_id`: `base` or a mode's id. */\n id: string;\n /** The author's name for it (`Default` for `base`). */\n label: string;\n}\n\n/** The mode menu of a chat on one channel of an agent. */\nexport interface AgentModeMenu {\n /** The entry channel its sessions are judged by (`web` for the Default (Text) entry). */\n entry: string;\n /** The mode a session of the entry starts in. */\n startModeId: string;\n /** The mode a new chat's first send runs in when nobody picks one: the\n * entry's start mode, or the channel itself when it names a mode. */\n firstSendModeId: string;\n /** The modes the host listed that the agent offers there, in the host's order. */\n options: readonly AthenaChatModeOption[];\n /** The channel keeps each session in the mode it starts in. */\n locked: boolean;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isModeKey = (value: unknown): value is string =>\n typeof value === 'string' && value.length > 0 && value.length <= MAX_MODE_KEY_LENGTH;\n\n/** A stored JSON field: the live doc keeps it as a string, the caches decoded. */\nconst decoded = (value: unknown): unknown => {\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value) as unknown;\n } catch {\n return value;\n }\n};\n\nconst uniqueKeys = (value: unknown): string[] => {\n const kept: string[] = [];\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (isModeKey(entry) && !kept.includes(entry)) kept.push(entry);\n }\n }\n return kept;\n};\n\n/**\n * What an agent's published definition (`athenaMetadata.published_config`)\n * says about its modes, read as leniently as agora reads it\n * (`parse_agent_modes`, `parse_custom_channels`): malformed parts are dropped.\n * `null` for an agent never published.\n */\nexport function publishedAgentModeSource(athenaMetadata: unknown): AgentModeSource | null {\n if (!isRecord(athenaMetadata) || !athenaMetadata.published_version_id) return null;\n const config = athenaMetadata.published_config;\n if (!isRecord(config)) return null;\n const agentModes = decoded(config.agentModes);\n const stored = isRecord(agentModes) ? agentModes : {};\n const startModes: Record<string, string> = {};\n if (isRecord(stored.startModes)) {\n for (const [channel, mode] of Object.entries(stored.startModes)) {\n if (isModeKey(channel) && isModeKey(mode)) startModes[channel] = mode;\n }\n }\n const switchModes: Record<string, string[]> = {};\n if (isRecord(stored.switchModes)) {\n for (const [channel, targets] of Object.entries(stored.switchModes)) {\n const kept = uniqueKeys(targets);\n if (isModeKey(channel) && kept.length > 0) switchModes[channel] = kept;\n }\n }\n const channels: Record<string, { label: string; enabled: boolean }> = {};\n const customChannels = decoded(config.customChannels);\n if (Array.isArray(customChannels)) {\n for (const entry of customChannels) {\n if (!isRecord(entry) || !isModeKey(entry.id) || entry.id in channels) continue;\n const name = typeof entry.name === 'string' ? entry.name.trim() : '';\n channels[entry.id] = { label: name || entry.id, enabled: entry.enabled !== false };\n }\n }\n return {\n modes: uniqueKeys(stored.modes).filter((id) => id !== BASE_MODE_ID),\n startModes,\n switchModes,\n lockedChannels: uniqueKeys(stored.lockedChannels),\n channels,\n };\n}\n\n/**\n * The entry a session on `channel` is judged by (agora `session_entry_channel`):\n * one of the agent's custom channels that is not a mode, else the Default\n * (Text) entry.\n */\nexport function agentModeEntry({\n source,\n channel,\n}: {\n source: AgentModeSource;\n channel: string | null;\n}): string {\n return channel && isCustomEntry({ source, channel }) ? channel : WEB_ENTRY;\n}\n\nconst isCustomEntry = ({ source, channel }: { source: AgentModeSource; channel: string }) =>\n channel !== BASE_MODE_ID && !source.modes.includes(channel) && channel in source.channels;\n\n/**\n * The mode a run on `channel` runs in, as agora compiles it: a custom entry\n * channel follows its start mode even when a send names it, while `base`, a\n * mode or a built-in channel runs its own layer.\n */\nexport function agentModeOfChannel({\n source,\n channel,\n}: {\n source: AgentModeSource;\n channel: string;\n}): string {\n return isCustomEntry({ source, channel }) ? (source.startModes[channel] ?? channel) : channel;\n}\n\nconst optionLabel = ({ source, id }: { source: AgentModeSource; id: string }): string =>\n id === BASE_MODE_ID ? 'Default' : (source.channels[id]?.label ?? id);\n\n/**\n * The menu of a chat on `channel` (the provider's `channel`, `null` for none)\n * that lists `hostModes`: the modes the agent offers its entry — its start\n * mode, the channel itself (unless naming it runs that start mode), its switch\n * list — that the host listed, in the host's order, without a mode that is\n * switched off.\n */\nexport function agentModeMenu({\n source,\n channel,\n hostModes,\n}: {\n source: AgentModeSource;\n channel: string | null;\n hostModes: readonly string[];\n}): AgentModeMenu {\n const entry = agentModeEntry({ source, channel });\n const startModeId = source.startModes[entry] ?? (entry === WEB_ENTRY ? BASE_MODE_ID : entry);\n // A custom entry channel that starts in another mode runs that mode when\n // named, so it is no option of its own.\n const ownMode = channel && agentModeOfChannel({ source, channel }) === channel ? [channel] : [];\n const offered = new Set([startModeId, ...ownMode, ...(source.switchModes[entry] ?? [])]);\n const options: AthenaChatModeOption[] = [];\n for (const id of hostModes) {\n if (!offered.has(id) || options.some((option) => option.id === id)) continue;\n if (id !== BASE_MODE_ID && source.channels[id]?.enabled === false) continue;\n options.push({ id, label: optionLabel({ source, id }) });\n }\n return {\n entry,\n startModeId,\n firstSendModeId: channel ? agentModeOfChannel({ source, channel }) : startModeId,\n options,\n locked: source.lockedChannels.includes(entry),\n };\n}\n\n/**\n * The channel agora reads as a session's current one, from its session\n * asset's metadata: the mode it last switched to or started in\n * (`collab_current_channel_id`), else its channel stamp (`collab_channel_id`).\n * A send that names it continues the session without switching it; the mode\n * it runs in is {@link agentModeOfChannel} of it. `null` when neither is set.\n */\nexport function sessionChannelFromMetadata(athenaMetadata: unknown): string | null {\n if (!isRecord(athenaMetadata)) return null;\n const current = athenaMetadata.collab_current_channel_id;\n if (isModeKey(current)) return current;\n const stamp = athenaMetadata.collab_channel_id;\n return isModeKey(stamp) ? stamp : null;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ const agentSelectionContext = require("../provider/agent-selection-context.cjs")
|
|
|
10
10
|
const themeStyleContext = require("../provider/theme-style-context.cjs");
|
|
11
11
|
const agentModelOptions = require("./agent-model-options.cjs");
|
|
12
12
|
const runtimeCatalog = require("./runtime-catalog.cjs");
|
|
13
|
+
const useAthenaChatMode = require("./use-athena-chat-mode.cjs");
|
|
13
14
|
const cnfast = require("cnfast");
|
|
14
15
|
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
16
|
const STATIC_CHIP_CLASS = "inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground";
|
|
@@ -327,6 +328,56 @@ function ChatAgentPicker({ value, onChange, disabled = false, className }) {
|
|
|
327
328
|
) })
|
|
328
329
|
] });
|
|
329
330
|
}
|
|
331
|
+
function ChatModePicker({
|
|
332
|
+
value,
|
|
333
|
+
options,
|
|
334
|
+
onChange,
|
|
335
|
+
valueLabel,
|
|
336
|
+
disabled = false,
|
|
337
|
+
disabledReason,
|
|
338
|
+
className
|
|
339
|
+
}) {
|
|
340
|
+
var _a;
|
|
341
|
+
const [open, setOpen] = react.useState(false);
|
|
342
|
+
const label = ((_a = options.find((option) => option.id === value)) == null ? void 0 : _a.label) ?? valueLabel ?? value;
|
|
343
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(radixUi.DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
|
|
344
|
+
/* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
345
|
+
"button",
|
|
346
|
+
{
|
|
347
|
+
type: "button",
|
|
348
|
+
className: cnfast.cn(CHIP_CLASS, className),
|
|
349
|
+
disabled,
|
|
350
|
+
title: disabled ? disabledReason : void 0,
|
|
351
|
+
"aria-label": `Mode: ${label}`,
|
|
352
|
+
"data-slot": "chat-mode-picker",
|
|
353
|
+
children: [
|
|
354
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayersIcon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
355
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label }),
|
|
356
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": true })
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
) }),
|
|
360
|
+
/* @__PURE__ */ jsxRuntime.jsx(PickerMenu, { label: "Mode", children: /* @__PURE__ */ jsxRuntime.jsx(radixUi.DropdownMenu.RadioGroup, { value, onValueChange: onChange, children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(PickerItem, { value: option.id, children: option.label }, option.id)) }) })
|
|
361
|
+
] });
|
|
362
|
+
}
|
|
363
|
+
function AthenaChatModeMenu({ className }) {
|
|
364
|
+
const mode = useAthenaChatMode.useAthenaChatMode();
|
|
365
|
+
if (mode.status !== "ready") return null;
|
|
366
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
367
|
+
ChatModePicker,
|
|
368
|
+
{
|
|
369
|
+
value: mode.current,
|
|
370
|
+
valueLabel: mode.currentLabel,
|
|
371
|
+
options: mode.options,
|
|
372
|
+
onChange: mode.select,
|
|
373
|
+
disabled: !mode.canSwitch,
|
|
374
|
+
disabledReason: "This channel keeps each conversation in the mode it started in. Start a new conversation to pick another.",
|
|
375
|
+
className
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
exports.AthenaChatModeMenu = AthenaChatModeMenu;
|
|
330
380
|
exports.ChatAgentPicker = ChatAgentPicker;
|
|
381
|
+
exports.ChatModePicker = ChatModePicker;
|
|
331
382
|
exports.ChatModelPicker = ChatModelPicker;
|
|
332
383
|
//# sourceMappingURL=chat-pickers.cjs.map
|
|
@@ -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, 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":"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"}
|
|
1
|
+
{"version":3,"file":"chat-pickers.cjs","sources":["../../src/catalog/chat-pickers.tsx"],"sourcesContent":["import { BotIcon, CheckIcon, ChevronDownIcon, LayersIcon, 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 type { AthenaChatModeOption } from './agent-mode-menu';\nimport { agentAssetIdOf } from './agent-model-options';\nimport {\n type AthenaAgentModelOptions,\n groupModelsByProvider,\n resolveCatalogModelId,\n useAgentModelChoices,\n useAthenaAgentCatalog,\n useAthenaModelCatalog,\n} from './runtime-catalog';\nimport { useAthenaChatMode } from './use-athena-chat-mode';\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\nexport interface ChatModePickerProps {\n /** The mode the session runs in: `base` or a mode's id. */\n value: string;\n /** The modes to offer. */\n options: readonly AthenaChatModeOption[];\n onChange: (modeId: string) => void;\n /** The name of `value` when it is none of `options`. */\n valueLabel?: string;\n disabled?: boolean;\n /** Why the picker is disabled, shown as its tooltip. */\n disabledReason?: string;\n className?: string;\n}\n\n/**\n * Which of the agent's modes the chat runs in, as a chip with a radio menu\n * like the other composer pickers. Controlled: `useAthenaChatMode` gives the\n * options, the current mode and `select`, which `AthenaChat`'s built-in menu\n * ({@link AthenaChatModeMenu}) wires up for you.\n */\nexport function ChatModePicker({\n value,\n options,\n onChange,\n valueLabel,\n disabled = false,\n disabledReason,\n className,\n}: ChatModePickerProps) {\n const [open, setOpen] = useState(false);\n const label = options.find((option) => option.id === value)?.label ?? valueLabel ?? value;\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 title={disabled ? disabledReason : undefined}\n aria-label={`Mode: ${label}`}\n data-slot=\"chat-mode-picker\"\n >\n <LayersIcon 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=\"Mode\">\n <DropdownMenu.RadioGroup value={value} onValueChange={onChange}>\n {options.map((option) => (\n <PickerItem key={option.id} value={option.id}>\n {option.label}\n </PickerItem>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n\n/**\n * `AthenaChat`'s mode menu: {@link ChatModePicker} over `useAthenaChatMode`,\n * shown only while the provider's `modes` give the chat two or more modes.\n */\nexport function AthenaChatModeMenu({ className }: { className?: string }) {\n const mode = useAthenaChatMode();\n if (mode.status !== 'ready') return null;\n return (\n <ChatModePicker\n value={mode.current}\n valueLabel={mode.currentLabel}\n options={mode.options}\n onChange={mode.select}\n disabled={!mode.canSwitch}\n disabledReason=\"This channel keeps each conversation in the mode it started in. Start a new conversation to pick another.\"\n className={className}\n />\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","LayersIcon","useAthenaChatMode"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AthenaChatModeOption } from './agent-mode-menu';
|
|
1
2
|
export interface ChatModelPickerProps {
|
|
2
3
|
/** The chosen model id; `null` lets a selected agent run its own model. */
|
|
3
4
|
value: string | null;
|
|
@@ -44,3 +45,30 @@ export interface ChatAgentPickerProps {
|
|
|
44
45
|
}
|
|
45
46
|
/** Who answers new messages: Athena, or a published collab agent the person can see. */
|
|
46
47
|
export declare function ChatAgentPicker({ value, onChange, disabled, className }: ChatAgentPickerProps): import("react").JSX.Element;
|
|
48
|
+
export interface ChatModePickerProps {
|
|
49
|
+
/** The mode the session runs in: `base` or a mode's id. */
|
|
50
|
+
value: string;
|
|
51
|
+
/** The modes to offer. */
|
|
52
|
+
options: readonly AthenaChatModeOption[];
|
|
53
|
+
onChange: (modeId: string) => void;
|
|
54
|
+
/** The name of `value` when it is none of `options`. */
|
|
55
|
+
valueLabel?: string;
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/** Why the picker is disabled, shown as its tooltip. */
|
|
58
|
+
disabledReason?: string;
|
|
59
|
+
className?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Which of the agent's modes the chat runs in, as a chip with a radio menu
|
|
63
|
+
* like the other composer pickers. Controlled: `useAthenaChatMode` gives the
|
|
64
|
+
* options, the current mode and `select`, which `AthenaChat`'s built-in menu
|
|
65
|
+
* ({@link AthenaChatModeMenu}) wires up for you.
|
|
66
|
+
*/
|
|
67
|
+
export declare function ChatModePicker({ value, options, onChange, valueLabel, disabled, disabledReason, className, }: ChatModePickerProps): import("react").JSX.Element;
|
|
68
|
+
/**
|
|
69
|
+
* `AthenaChat`'s mode menu: {@link ChatModePicker} over `useAthenaChatMode`,
|
|
70
|
+
* shown only while the provider's `modes` give the chat two or more modes.
|
|
71
|
+
*/
|
|
72
|
+
export declare function AthenaChatModeMenu({ className }: {
|
|
73
|
+
className?: string;
|
|
74
|
+
}): import("react").JSX.Element | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { BotIcon, ChevronDownIcon, CheckIcon, SparklesIcon } from "lucide-react";
|
|
2
|
+
import { BotIcon, ChevronDownIcon, LayersIcon, CheckIcon, SparklesIcon } from "lucide-react";
|
|
3
3
|
import { DropdownMenu } from "radix-ui";
|
|
4
4
|
import { useState, useRef, useEffect, useContext } from "react";
|
|
5
5
|
import { usePortalContainer } from "../lib/owner-document.js";
|
|
@@ -8,6 +8,7 @@ import { AthenaAgentSelectionContext } from "../provider/agent-selection-context
|
|
|
8
8
|
import { useAthenaThemeStyle } from "../provider/theme-style-context.js";
|
|
9
9
|
import { agentAssetIdOf } from "./agent-model-options.js";
|
|
10
10
|
import { useAthenaAgentCatalog, useAgentModelChoices, useAthenaModelCatalog, resolveCatalogModelId, groupModelsByProvider } from "./runtime-catalog.js";
|
|
11
|
+
import { useAthenaChatMode } from "./use-athena-chat-mode.js";
|
|
11
12
|
import { cn } from "cnfast";
|
|
12
13
|
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";
|
|
13
14
|
const STATIC_CHIP_CLASS = "inline-flex h-7 max-w-[14rem] items-center gap-1 rounded-md px-2 text-xs text-muted-foreground";
|
|
@@ -325,8 +326,58 @@ function ChatAgentPicker({ value, onChange, disabled = false, className }) {
|
|
|
325
326
|
) })
|
|
326
327
|
] });
|
|
327
328
|
}
|
|
329
|
+
function ChatModePicker({
|
|
330
|
+
value,
|
|
331
|
+
options,
|
|
332
|
+
onChange,
|
|
333
|
+
valueLabel,
|
|
334
|
+
disabled = false,
|
|
335
|
+
disabledReason,
|
|
336
|
+
className
|
|
337
|
+
}) {
|
|
338
|
+
var _a;
|
|
339
|
+
const [open, setOpen] = useState(false);
|
|
340
|
+
const label = ((_a = options.find((option) => option.id === value)) == null ? void 0 : _a.label) ?? valueLabel ?? value;
|
|
341
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
|
|
342
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
343
|
+
"button",
|
|
344
|
+
{
|
|
345
|
+
type: "button",
|
|
346
|
+
className: cn(CHIP_CLASS, className),
|
|
347
|
+
disabled,
|
|
348
|
+
title: disabled ? disabledReason : void 0,
|
|
349
|
+
"aria-label": `Mode: ${label}`,
|
|
350
|
+
"data-slot": "chat-mode-picker",
|
|
351
|
+
children: [
|
|
352
|
+
/* @__PURE__ */ jsx(LayersIcon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
353
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: label }),
|
|
354
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": true })
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
) }),
|
|
358
|
+
/* @__PURE__ */ jsx(PickerMenu, { label: "Mode", children: /* @__PURE__ */ jsx(DropdownMenu.RadioGroup, { value, onValueChange: onChange, children: options.map((option) => /* @__PURE__ */ jsx(PickerItem, { value: option.id, children: option.label }, option.id)) }) })
|
|
359
|
+
] });
|
|
360
|
+
}
|
|
361
|
+
function AthenaChatModeMenu({ className }) {
|
|
362
|
+
const mode = useAthenaChatMode();
|
|
363
|
+
if (mode.status !== "ready") return null;
|
|
364
|
+
return /* @__PURE__ */ jsx(
|
|
365
|
+
ChatModePicker,
|
|
366
|
+
{
|
|
367
|
+
value: mode.current,
|
|
368
|
+
valueLabel: mode.currentLabel,
|
|
369
|
+
options: mode.options,
|
|
370
|
+
onChange: mode.select,
|
|
371
|
+
disabled: !mode.canSwitch,
|
|
372
|
+
disabledReason: "This channel keeps each conversation in the mode it started in. Start a new conversation to pick another.",
|
|
373
|
+
className
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
}
|
|
328
377
|
export {
|
|
378
|
+
AthenaChatModeMenu,
|
|
329
379
|
ChatAgentPicker,
|
|
380
|
+
ChatModePicker,
|
|
330
381
|
ChatModelPicker
|
|
331
382
|
};
|
|
332
383
|
//# sourceMappingURL=chat-pickers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-pickers.js","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":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat-pickers.js","sources":["../../src/catalog/chat-pickers.tsx"],"sourcesContent":["import { BotIcon, CheckIcon, ChevronDownIcon, LayersIcon, 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 type { AthenaChatModeOption } from './agent-mode-menu';\nimport { agentAssetIdOf } from './agent-model-options';\nimport {\n type AthenaAgentModelOptions,\n groupModelsByProvider,\n resolveCatalogModelId,\n useAgentModelChoices,\n useAthenaAgentCatalog,\n useAthenaModelCatalog,\n} from './runtime-catalog';\nimport { useAthenaChatMode } from './use-athena-chat-mode';\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\nexport interface ChatModePickerProps {\n /** The mode the session runs in: `base` or a mode's id. */\n value: string;\n /** The modes to offer. */\n options: readonly AthenaChatModeOption[];\n onChange: (modeId: string) => void;\n /** The name of `value` when it is none of `options`. */\n valueLabel?: string;\n disabled?: boolean;\n /** Why the picker is disabled, shown as its tooltip. */\n disabledReason?: string;\n className?: string;\n}\n\n/**\n * Which of the agent's modes the chat runs in, as a chip with a radio menu\n * like the other composer pickers. Controlled: `useAthenaChatMode` gives the\n * options, the current mode and `select`, which `AthenaChat`'s built-in menu\n * ({@link AthenaChatModeMenu}) wires up for you.\n */\nexport function ChatModePicker({\n value,\n options,\n onChange,\n valueLabel,\n disabled = false,\n disabledReason,\n className,\n}: ChatModePickerProps) {\n const [open, setOpen] = useState(false);\n const label = options.find((option) => option.id === value)?.label ?? valueLabel ?? value;\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 title={disabled ? disabledReason : undefined}\n aria-label={`Mode: ${label}`}\n data-slot=\"chat-mode-picker\"\n >\n <LayersIcon 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=\"Mode\">\n <DropdownMenu.RadioGroup value={value} onValueChange={onChange}>\n {options.map((option) => (\n <PickerItem key={option.id} value={option.id}>\n {option.label}\n </PickerItem>\n ))}\n </DropdownMenu.RadioGroup>\n </PickerMenu>\n </DropdownMenu.Root>\n );\n}\n\n/**\n * `AthenaChat`'s mode menu: {@link ChatModePicker} over `useAthenaChatMode`,\n * shown only while the provider's `modes` give the chat two or more modes.\n */\nexport function AthenaChatModeMenu({ className }: { className?: string }) {\n const mode = useAthenaChatMode();\n if (mode.status !== 'ready') return null;\n return (\n <ChatModePicker\n value={mode.current}\n valueLabel={mode.currentLabel}\n options={mode.options}\n onChange={mode.select}\n disabled={!mode.canSwitch}\n disabledReason=\"This channel keeps each conversation in the mode it started in. Start a new conversation to pick another.\"\n className={className}\n />\n );\n}\n"],"names":[],"mappings":"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"}
|