@agent-native/toolkit 0.16.0 → 0.16.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.
Files changed (33) hide show
  1. package/dist/composer/ComposerPlusMenu.d.ts.map +1 -1
  2. package/dist/composer/ComposerPlusMenu.js +29 -19
  3. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  4. package/dist/composer/PromptComposer.d.ts +4 -0
  5. package/dist/composer/PromptComposer.d.ts.map +1 -1
  6. package/dist/composer/PromptComposer.js +2 -2
  7. package/dist/composer/PromptComposer.js.map +1 -1
  8. package/dist/composer/TiptapComposer.d.ts +12 -1
  9. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  10. package/dist/composer/TiptapComposer.js +249 -162
  11. package/dist/composer/TiptapComposer.js.map +1 -1
  12. package/dist/composer/TiptapComposer.spec.js +33 -1
  13. package/dist/composer/TiptapComposer.spec.js.map +1 -1
  14. package/dist/composer/index.d.ts +1 -0
  15. package/dist/composer/index.d.ts.map +1 -1
  16. package/dist/composer/index.js +1 -0
  17. package/dist/composer/index.js.map +1 -1
  18. package/dist/composer/model-selection.d.ts +12 -0
  19. package/dist/composer/model-selection.d.ts.map +1 -0
  20. package/dist/composer/model-selection.js +31 -0
  21. package/dist/composer/model-selection.js.map +1 -0
  22. package/dist/composer/model-selection.spec.d.ts +2 -0
  23. package/dist/composer/model-selection.spec.d.ts.map +1 -0
  24. package/dist/composer/model-selection.spec.js +38 -0
  25. package/dist/composer/model-selection.spec.js.map +1 -0
  26. package/package.json +1 -1
  27. package/src/composer/ComposerPlusMenu.tsx +122 -65
  28. package/src/composer/PromptComposer.tsx +8 -0
  29. package/src/composer/TiptapComposer.spec.ts +46 -0
  30. package/src/composer/TiptapComposer.tsx +678 -412
  31. package/src/composer/index.ts +6 -0
  32. package/src/composer/model-selection.spec.ts +45 -0
  33. package/src/composer/model-selection.ts +51 -0
@@ -1,12 +1,12 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
3
3
  import { useComposer, useComposerRuntime } from "@assistant-ui/react";
4
- import { IconArrowUp, IconCheck, IconChevronDown, IconChevronRight, IconBulb, IconClock, IconBolt, IconTool, IconX, IconClipboardList, IconKey, IconPencil, IconPlugConnected, } from "@tabler/icons-react";
4
+ import { IconArrowUp, IconCheck, IconChevronDown, IconChevronRight, IconBulb, IconClock, IconBolt, IconTool, IconX, IconClipboardList, IconKey, IconPencil, IconPlugConnected, IconHelpCircle, } from "@tabler/icons-react";
5
5
  import Placeholder from "@tiptap/extension-placeholder";
6
6
  import { useEditor, EditorContent } from "@tiptap/react";
7
7
  import StarterKit from "@tiptap/starter-kit";
8
8
  import { useState, useRef, useEffect, useCallback, useImperativeHandle, useMemo, } from "react";
9
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
9
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, } from "../ui/popover.js";
10
10
  import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip.js";
11
11
  import { ComposerPlusMenu } from "./ComposerPlusMenu.js";
12
12
  import { getComposerDraftKey } from "./draft-key.js";
@@ -14,6 +14,7 @@ import { FileReference } from "./extensions/FileReference.js";
14
14
  import { MentionReference } from "./extensions/MentionReference.js";
15
15
  import { SkillReference } from "./extensions/SkillReference.js";
16
16
  import { MentionPopover } from "./MentionPopover.js";
17
+ import { isClaudeCodeAgentId, isLunaModel, resolvePreferredAgentModel, } from "./model-selection.js";
17
18
  import { createPastedAttachmentFile, readClipboardPaste, shouldConvertClipboardToAttachment, } from "./pasted-text.js";
18
19
  import { AGENT_CHAT_INSERT_REFERENCE_EVENT, AGENT_CHAT_INSERT_REFERENCE_MESSAGE_TYPE, DEFAULT_REASONING_EFFORT, formatPromptContextItems, getReasoningEffortOptionsForModel, reasoningEffortLabel, resolveReasoningEffortSelection, useComposerRuntimeAdapters, } from "./runtime-adapters.js";
19
20
  import { useMentionSearch } from "./use-mention-search.js";
@@ -513,7 +514,7 @@ function ModeSelector({ mode, onChange, planModeDisabled = false, planModeDisabl
513
514
  setOpen(false);
514
515
  }, className: "flex w-full items-center gap-3 px-3 py-2 hover:bg-accent/50 text-start", children: [_jsx(IconPencil, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "font-medium text-foreground text-[13px]", children: t("agentChat.plan.act", { defaultValue: "Act" }) }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: t("agentChat.composer.actDescription", {
515
516
  defaultValue: "Use tools and make approved changes",
516
- }) })] }), mode === "build" && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }), _jsxs("button", { type: "button", disabled: planModeDisabled, title: planModeDisabled ? resolvedPlanModeDisabledReason : undefined, onClick: () => {
517
+ }) })] }), mode === "build" && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] }), _jsxs("button", { type: "button", disabled: planModeDisabled, title: planModeDisabled ? resolvedPlanModeDisabledReason : undefined, onClick: () => {
517
518
  if (planModeDisabled)
518
519
  return;
519
520
  onChange("plan");
@@ -524,20 +525,48 @@ function ModeSelector({ mode, onChange, planModeDisabled = false, planModeDisabl
524
525
  ? resolvedPlanModeDisabledReason
525
526
  : t("agentChat.composer.planDescription", {
526
527
  defaultValue: "Read-only research and approval first",
527
- }) })] }), mode === "plan" && !planModeDisabled && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] })] })] }));
528
+ }) })] }), mode === "plan" && !planModeDisabled && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] })] })] }));
528
529
  }
529
530
  const FRIENDLY_MODEL_NAMES = {
530
531
  auto: "Default model",
531
532
  "codex-cli": "Codex",
533
+ "claude-cli": "Claude Code",
534
+ "pi-cli": "Pi",
535
+ "opencode-cli": "OpenCode",
532
536
  "claude-fable-5": "Fable 5",
533
537
  "kimi-k2-5": "Kimi K2.5",
534
538
  "deepseek-v3-1": "DeepSeek v3.1",
535
539
  "z-ai/glm-5.2": "GLM 5.2",
536
540
  };
541
+ const LOCAL_RUNTIME_ENGINES = new Set([
542
+ "codex-cli",
543
+ "claude-cli",
544
+ "pi-cli",
545
+ "opencode-cli",
546
+ ]);
547
+ function isOpenAiModelId(model) {
548
+ const normalizedModel = model.toLowerCase();
549
+ return (normalizedModel.startsWith("gpt-") ||
550
+ normalizedModel.startsWith("openai/gpt-"));
551
+ }
552
+ export function isOpenAiModelProviderGroup(group) {
553
+ const engine = group.engine.toLowerCase();
554
+ const label = group.label.toLowerCase();
555
+ if (engine === "codex-cli") {
556
+ return group.models.some(isOpenAiModelId);
557
+ }
558
+ return (engine.includes("openai") ||
559
+ label.includes("openai") ||
560
+ group.models.some(isOpenAiModelId));
561
+ }
562
+ const HARNESS_AGENTS_DOCS_URL = "https://www.agent-native.com/docs/harness-agents";
537
563
  export const MODEL_SELECTOR_POPOVER_STYLE = {
538
564
  fontSize: 13,
539
565
  maxHeight: "min(500px, var(--radix-popover-content-available-height, 500px))",
540
566
  };
567
+ const MODEL_SELECTOR_POPOVER_CLASS = "box-border w-64 rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg outline-none";
568
+ const PICKER_HELP_BUTTON_CLASS = "flex size-3 shrink-0 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground";
569
+ const PICKER_HELP_ICON_CLASS = "size-2";
541
570
  export function shouldShowModelSelectorSkeleton(isLoading, engineCount) {
542
571
  return isLoading && engineCount === 0;
543
572
  }
@@ -712,21 +741,25 @@ function ModelCostTier({ model }) {
712
741
  : tier === 2
713
742
  ? t("agentChat.composer.costMedium", { defaultValue: "Medium cost" })
714
743
  : t("agentChat.composer.costHigher", { defaultValue: "Higher cost" });
715
- return (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: "shrink-0 text-[11px] tabular-nums text-muted-foreground/60", children: "$".repeat(tier) }), _jsx("span", { className: "sr-only", children: costLabel })] }));
744
+ return _jsx("span", { className: "sr-only", children: costLabel });
716
745
  }
717
746
  export function getComposerReasoningEffortOptions(model) {
718
747
  return model === "auto"
719
748
  ? ["low", "medium", "high", "xhigh", "max"]
720
749
  : getReasoningEffortOptionsForModel(model);
721
750
  }
722
- function ModelSelector({ model, effort, engines, agents, selectedAgent, showAutoModelOption = true, modelListLoading = false, onChange, onEffortChange, onAgentChange, providerConnectStatusEnabled = true, onConnectProvider, onConnectLocalRuntime, imageModel, }) {
751
+ function ModelSelector({ model, effort, engines, agents, selectedAgent, hostedHarness = false, showAutoModelOption = true, modelListLoading = false, open: controlledOpen, onChange, onEffortChange, onAgentChange, onModelSelectorOpenChange, providerConnectStatusEnabled = true, onConnectProvider, onConnectLocalRuntime, imageModel, }) {
723
752
  const adapters = useComposerRuntimeAdapters();
724
753
  const t = adapters.translate;
725
754
  const reasoning = adapters.models?.reasoning;
726
755
  const defaultEffort = reasoning?.defaultEffort ?? DEFAULT_REASONING_EFFORT;
727
- const [open, setOpen] = useState(false);
756
+ const [internalOpen, setInternalOpen] = useState(false);
757
+ const open = controlledOpen ?? internalOpen;
758
+ const isClaudeCodeAgent = isClaudeCodeAgentId(selectedAgent);
728
759
  const autoModelGroup = showAutoModelOption
729
- ? engines.find((group) => group.models.includes("auto"))
760
+ ? isClaudeCodeAgent
761
+ ? undefined
762
+ : engines.find((group) => group.models.includes("auto"))
730
763
  : undefined;
731
764
  const providerGroups = useMemo(() => engines
732
765
  .map((group) => ({
@@ -734,6 +767,52 @@ function ModelSelector({ model, effort, engines, agents, selectedAgent, showAuto
734
767
  models: group.models.filter((candidate) => candidate !== "auto"),
735
768
  }))
736
769
  .filter((group) => group.models.length > 0), [engines]);
770
+ const isCodexAgent = selectedAgent === "codex" || selectedAgent === "codex-cli";
771
+ const modelProviderGroups = useMemo(() => {
772
+ const hasCodexLocalGroup = providerGroups.some((group) => group.engine === "codex-cli");
773
+ const groups = providerGroups.flatMap((group) => {
774
+ if (group.engine === "codex-cli") {
775
+ return isCodexAgent && isOpenAiModelProviderGroup(group) ? [group] : [];
776
+ }
777
+ if (isCodexAgent &&
778
+ hasCodexLocalGroup &&
779
+ group.engine === "ai-sdk:openai") {
780
+ return [];
781
+ }
782
+ if (LOCAL_RUNTIME_ENGINES.has(group.engine))
783
+ return [];
784
+ if (!isCodexAgent)
785
+ return [group];
786
+ if (!isOpenAiModelProviderGroup(group))
787
+ return [];
788
+ const isExplicitOpenAiProvider = group.engine.toLowerCase().includes("openai") ||
789
+ group.label.toLowerCase().includes("openai");
790
+ const models = isExplicitOpenAiProvider
791
+ ? group.models
792
+ : group.models.filter(isOpenAiModelId);
793
+ return models.length > 0 ? [{ ...group, models }] : [];
794
+ });
795
+ if (!isClaudeCodeAgent)
796
+ return groups;
797
+ return groups
798
+ .map((group) => ({
799
+ ...group,
800
+ models: group.models.filter((candidate) => !isLunaModel(candidate)),
801
+ }))
802
+ .filter((group) => group.models.length > 0);
803
+ }, [isClaudeCodeAgent, isCodexAgent, providerGroups]);
804
+ const preferredAgentModel = useMemo(() => resolvePreferredAgentModel(selectedAgent, providerGroups), [providerGroups, selectedAgent]);
805
+ useEffect(() => {
806
+ if (!isClaudeCodeAgent || !isLunaModel(model) || !preferredAgentModel) {
807
+ return;
808
+ }
809
+ if (preferredAgentModel.model === model &&
810
+ preferredAgentModel.engine ===
811
+ engines.find((group) => group.models.includes(model))?.engine) {
812
+ return;
813
+ }
814
+ onChange(preferredAgentModel.model, preferredAgentModel.engine);
815
+ }, [engines, isClaudeCodeAgent, model, onChange, preferredAgentModel]);
737
816
  const effortOptions = reasoning?.getOptionsForModel?.(model) ??
738
817
  getComposerReasoningEffortOptions(model);
739
818
  const selectedEffort = reasoning?.resolve?.(model, effort) ??
@@ -741,180 +820,188 @@ function ModelSelector({ model, effort, engines, agents, selectedAgent, showAuto
741
820
  const effortLabel = useCallback((value) => localizedReasoningEffortLabel(t, value, (reasoning?.label ?? reasoningEffortLabel)(value)), [reasoning?.label, t]);
742
821
  const selectedAgentOption = agents?.find((agent) => agent.id === (selectedAgent ?? "default"));
743
822
  const selectedAgentLabel = selectedAgentOption?.label ?? "Default";
744
- // Collapse non-selected families by default. The family containing the
745
- // currently-selected model stays expanded so the user sees their pick at
746
- // a glance; clicking another family's header expands it inline.
747
- const selectedGroupKey = useMemo(() => {
748
- const found = providerGroups.find((g) => g.models.includes(model));
749
- return found ? `${found.engine}:${found.label}` : null;
750
- }, [model, providerGroups]);
751
- const [expandedGroups, setExpandedGroups] = useState(() => new Set(selectedGroupKey ? [selectedGroupKey] : []));
752
- // Reset expansion when the popover re-opens so the picker always lands
753
- // on the "selected family expanded, others collapsed" view.
754
- useEffect(() => {
755
- if (open) {
756
- setExpandedGroups(new Set(selectedGroupKey ? [selectedGroupKey] : []));
757
- }
758
- }, [open, selectedGroupKey]);
759
- const toggleGroup = useCallback((key) => {
760
- setExpandedGroups((prev) => {
761
- const next = new Set(prev);
762
- if (next.has(key))
763
- next.delete(key);
764
- else
765
- next.add(key);
766
- return next;
767
- });
768
- }, []);
769
- // The effort list is collapsed by default — it's a secondary
770
- // control most users don't touch, so it stays tucked behind a header that
771
- // reveals the current effort at a glance. Reset to collapsed on each open.
772
- const [effortExpanded, setEffortExpanded] = useState(false);
773
- useEffect(() => {
774
- if (open)
775
- setEffortExpanded(false);
776
- }, [open]);
777
- // The optional image-model section follows the same collapsed-by-default
778
- // pattern; the current selection shows next to the header.
779
- const [imageExpanded, setImageExpanded] = useState(false);
780
- useEffect(() => {
781
- if (open)
782
- setImageExpanded(false);
783
- }, [open]);
784
- const imageModelLabel = imageModel?.options.find((option) => option.value === imageModel.value)
785
- ?.label ?? imageModel?.value;
823
+ const selectedModelLabel = friendlyModelName(model, t).replace(/^GPT-/, "");
824
+ const [detailSection, setDetailSection] = useState(null);
825
+ const resolvedSection = detailSection ?? "model";
826
+ const setPickerOpen = useCallback((nextOpen) => {
827
+ if (controlledOpen === undefined)
828
+ setInternalOpen(nextOpen);
829
+ if (nextOpen)
830
+ setDetailSection(null);
831
+ onModelSelectorOpenChange?.(nextOpen);
832
+ }, [controlledOpen, onModelSelectorOpenChange]);
833
+ const visibleProviderGroups = modelProviderGroups;
786
834
  const showModelListSkeleton = shouldShowModelSelectorSkeleton(modelListLoading, engines.length);
787
- // When Builder.io isn't connected, surface a one-click connect path
788
- // it unlocks every model family (Claude, OpenAI, Gemini) without the
789
- // user having to paste individual API keys.
835
+ // Keep setup actions beside model choices while any visible provider still
836
+ // needs configuration. The model rows remain visible so the user can see
837
+ // what becomes available after connecting or adding a key.
790
838
  const builderFlow = adapters.builder.useConnectFlow({
791
839
  enabled: providerConnectStatusEnabled,
792
840
  trackingSource: "composer_builder_cta",
793
841
  });
794
842
  const hasConfiguredBuilderModels = providerGroups.some((group) => group.engine === "builder" && group.configured);
795
843
  const hasConnectedSubscription = providerGroups.some((group) => group.configured && group.isSubscription);
796
- const showBuilderCta = (builderFlow.hasFetchedStatus ||
797
- (!providerConnectStatusEnabled && !!onConnectProvider)) &&
798
- !builderFlow.configured &&
799
- !builderFlow.envManaged &&
800
- !hasConfiguredBuilderModels &&
801
- !hasConnectedSubscription;
802
- const onlyConnectPathAvailable = shouldShowOnlyConnectPath(showBuilderCta, providerGroups);
844
+ const hasUnconfiguredVisibleModels = modelProviderGroups.some((group) => !group.configured);
845
+ const showBuilderAction = hasUnconfiguredVisibleModels &&
846
+ (Boolean(onConnectProvider) ||
847
+ (providerConnectStatusEnabled &&
848
+ !builderFlow.configured &&
849
+ !builderFlow.envManaged &&
850
+ !hasConfiguredBuilderModels &&
851
+ !hasConnectedSubscription));
852
+ const showAddKeysAction = hasUnconfiguredVisibleModels;
853
+ const showProviderActions = showBuilderAction || showAddKeysAction;
854
+ const onlyConnectPathAvailable = shouldShowOnlyConnectPath(showBuilderAction, providerGroups) &&
855
+ modelProviderGroups.length === 0;
803
856
  const openLlmSettings = useCallback(() => {
804
857
  try {
805
858
  window.location.hash = "llm";
806
859
  }
807
860
  catch { }
808
861
  window.dispatchEvent(new CustomEvent("agent-panel:open-settings"));
809
- setOpen(false);
810
- }, []);
862
+ setPickerOpen(false);
863
+ }, [setPickerOpen]);
811
864
  const connectLocalRuntime = useCallback((engine) => {
812
865
  onConnectLocalRuntime?.(engine);
813
- setOpen(false);
814
- }, [onConnectLocalRuntime]);
815
- return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-agent-composer-slot": "model-button", "aria-label": `${t("agentChat.composer.model", {
866
+ setPickerOpen(false);
867
+ }, [onConnectLocalRuntime, setPickerOpen]);
868
+ return (_jsxs(Popover, { open: open, onOpenChange: setPickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-agent-composer-slot": "model-button", "aria-label": `${t("agentChat.composer.model", {
816
869
  defaultValue: "Model",
817
870
  })}: ${friendlyModelName(model, t)}${effortOptions.length > 0
818
- ? `. ${t("agentChat.composer.reasoning", {
819
- defaultValue: "Reasoning",
871
+ ? `. ${t("agentChat.composer.effort", {
872
+ defaultValue: "Effort",
820
873
  })}: ${effortLabel(selectedEffort)}`
821
874
  : ""}${selectedAgentOption && selectedAgentOption.id !== "default"
822
875
  ? `. Agent: ${selectedAgentLabel}`
823
876
  : ""}`, className: "agent-composer-model-button flex min-w-0 max-w-[10.5rem] shrink items-center gap-1 rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground", children: [_jsx("span", { className: "min-w-0 truncate", children: selectedAgentOption && selectedAgentOption.id !== "default"
824
877
  ? selectedAgentLabel
825
- : compactComposerModelName(model, t) }), effortOptions.length > 0 && (_jsxs("span", { className: "agent-composer-model-effort min-w-0 shrink truncate text-muted-foreground/70", children: ["\u00B7 ", compactComposerReasoningEffortLabel(selectedEffort, t)] })), _jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 opacity-60" })] }) }), _jsxs(PopoverContent, { side: "top", align: "end", sideOffset: 6, collisionPadding: 8, "data-agent-native-composer-popover": "true", className: "z-[260] box-border w-72 overflow-y-auto rounded-lg border-border p-0 py-1 shadow-lg", style: MODEL_SELECTOR_POPOVER_STYLE, children: [agents && agents.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "px-3 pb-1 pt-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Agents" }), agents.map((agent) => {
826
- const isSelected = agent.id === (selectedAgent ?? "default");
827
- const isConfigured = agent.configured !== false;
828
- const canConnect = !isConfigured && Boolean(onConnectLocalRuntime);
829
- const statusLabel = agent.statusLabel ??
830
- (!isConfigured ? "Unavailable" : undefined);
831
- return (_jsxs("div", { className: "flex items-center hover:bg-accent/30", children: [_jsxs("button", { type: "button", disabled: !isConfigured || !onAgentChange, "aria-current": isSelected ? "true" : undefined, onClick: () => {
832
- if (!isConfigured)
833
- return;
834
- onAgentChange?.(agent.id);
835
- setOpen(false);
836
- }, className: `flex min-w-0 flex-1 items-center gap-3 px-3 py-1.5 text-start ${isConfigured
837
- ? "hover:bg-accent/50"
838
- : "cursor-default opacity-50"}`, children: [_jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate text-[13px] text-foreground", children: agent.label }), agent.description && (_jsx("span", { className: "block truncate text-[11px] text-muted-foreground", children: agent.description }))] }), isSelected && isConfigured && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-primary" }))] }), !isConfigured && statusLabel && (_jsx("button", { type: "button", disabled: !canConnect, className: "ms-auto max-w-[6rem] shrink-0 truncate px-3 py-1.5 text-end text-[10px] text-muted-foreground/70 hover:text-foreground disabled:cursor-default", onClick: () => {
839
- if (canConnect)
840
- connectLocalRuntime(agent.id);
841
- }, children: statusLabel }))] }, agent.id));
842
- }), _jsx("div", { className: "my-1 border-t border-border" })] })), showBuilderCta && (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => {
843
- if (onConnectProvider) {
844
- onConnectProvider();
845
- }
846
- else {
847
- builderFlow.start();
848
- }
849
- }, disabled: !onConnectProvider && builderFlow.connecting, className: "flex w-full items-start gap-2 px-3 py-2 text-start hover:bg-accent/50 disabled:opacity-60", children: [_jsx(IconPlugConnected, { className: "h-4 w-4 shrink-0 mt-0.5 text-blue-500" }), _jsxs("span", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "block text-[12px] font-medium text-foreground", children: !onConnectProvider && builderFlow.connecting
850
- ? t("agentPanel.connectingBuilder", {
851
- defaultValue: "Connecting Builder.io…",
852
- })
853
- : t("agentPanel.connectBuilderIo", {
854
- defaultValue: "Connect Builder.io",
855
- }) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.builderModelCredits", {
856
- defaultValue: "Free credits for Claude, OpenAI & Gemini",
857
- }) })] })] }), !onConnectProvider && builderFlow.error && (_jsx("p", { role: "alert", className: "px-3 pb-2 ps-9 text-[11px] text-destructive", children: builderFlow.error })), _jsxs("button", { type: "button", onClick: openLlmSettings, className: "flex w-full items-start gap-2 px-3 py-2 text-start hover:bg-accent/50", children: [_jsx(IconKey, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block text-[12px] font-medium text-foreground", children: t("agentPanel.addOwnKeys", {
858
- defaultValue: "Add your own keys",
859
- }) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.configureProviderKeys", {
860
- defaultValue: "Choose a cloud, gateway, or local provider",
861
- }) })] })] }), !onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" }))] })), imageModel && imageModel.options.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": imageExpanded, onClick: () => setImageExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [imageExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: imageModel.label ??
862
- t("agentChat.composer.imageModel", {
863
- defaultValue: "Image model",
864
- }) }), !imageExpanded && imageModelLabel && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: imageModelLabel }))] }) }), imageExpanded &&
865
- imageModel.options.map((option) => (_jsxs("button", { type: "button", onClick: () => {
866
- imageModel.onChange(option.value);
867
- setImageExpanded(false);
868
- }, className: "flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: option.label }), option.value === imageModel.value && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, option.value))), _jsx("div", { className: "my-1 border-t border-border" })] })), showModelListSkeleton && _jsx(ModelSelectorSkeleton, {}), autoModelGroup && !onlyConnectPathAvailable && (_jsxs("button", { type: "button", onClick: () => {
869
- onChange("auto", autoModelGroup.engine);
870
- setOpen(false);
871
- }, className: "flex w-full items-center gap-3 px-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: t("agentChat.composer.auto", { defaultValue: "Auto" }) }), model === "auto" && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] })), autoModelGroup &&
872
- providerGroups.length > 0 &&
873
- !onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" })), !onlyConnectPathAvailable &&
874
- providerGroups.map((group) => {
875
- const models = latestModelsOnly(group.models);
876
- const groupKey = `${group.engine}:${group.label}`;
877
- const isExpanded = expandedGroups.has(groupKey);
878
- const ChevronIcon = isExpanded ? IconChevronDown : IconChevronRight;
879
- const isLocalRuntime = group.engine === "codex-cli" || group.engine === "claude-cli";
880
- const canConnectLocalRuntime = isLocalRuntime && Boolean(onConnectLocalRuntime);
881
- const statusLabel = group.statusLabel ??
882
- (!group.configured
883
- ? canConnectLocalRuntime
884
- ? t("agentChat.auth.logIn", { defaultValue: "Sign in" })
885
- : t("agentChat.composer.needsApiKey", {
886
- defaultValue: "needs API key",
887
- })
888
- : undefined);
889
- return (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center hover:bg-accent/30", children: [_jsxs("button", { type: "button", "aria-expanded": isExpanded, onClick: () => toggleGroup(groupKey), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [_jsx(ChevronIcon, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" }), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: group.label }), !isExpanded && groupKey === selectedGroupKey && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: friendlyModelName(model, t) }))] }), !group.configured && statusLabel && (_jsx("button", { type: "button", className: "ms-auto max-w-[9rem] shrink-0 text-end text-[10px] text-muted-foreground/60 hover:text-foreground cursor-pointer pe-3 py-1.5", onClick: () => canConnectLocalRuntime
890
- ? connectLocalRuntime(group.engine)
891
- : openLlmSettings(), children: statusLabel })), group.configured && statusLabel && (_jsx("span", { className: "ms-auto max-w-[9rem] shrink-0 pe-3 text-end text-[10px] text-muted-foreground/70", children: statusLabel }))] }), isExpanded &&
892
- models.map((m) => (_jsxs("button", { type: "button", onClick: () => {
893
- if (!group.configured) {
894
- if (canConnectLocalRuntime) {
895
- connectLocalRuntime(group.engine);
896
- }
897
- else {
898
- openLlmSettings();
899
- }
900
- return;
901
- }
902
- onChange(m, group.engine);
903
- const nextOptions = getReasoningEffortOptionsForModel(m);
904
- if (nextOptions.length > 0 &&
905
- !nextOptions.includes(selectedEffort)) {
906
- onEffortChange?.(defaultEffort);
907
- }
908
- setOpen(false);
909
- }, className: `flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start ${group.configured
910
- ? "hover:bg-accent/50"
911
- : "opacity-40 cursor-default"}`, children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: friendlyModelName(m, t) }), _jsx(ModelCostTier, { model: m }), m === model && group.configured && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, m)))] }, groupKey));
912
- }), !showModelListSkeleton &&
913
- !onlyConnectPathAvailable &&
914
- effortOptions.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 border-t border-border" }), _jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": effortExpanded, onClick: () => setEffortExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [effortExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: t("agentChat.composer.reasoning", {
915
- defaultValue: "Reasoning",
916
- }) }), !effortExpanded && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: effortLabel(selectedEffort) }))] }) }), effortExpanded &&
917
- effortOptions.map((option) => (_jsxs("button", { type: "button", onClick: () => onEffortChange?.(option), className: "flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: effortLabel(option) }), option === selectedEffort && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, option)))] }))] })] }));
878
+ : compactComposerModelName(model, t) }), effortOptions.length > 0 && (_jsxs("span", { className: "agent-composer-model-effort min-w-0 shrink truncate text-muted-foreground/70", children: ["\u00B7 ", compactComposerReasoningEffortLabel(selectedEffort, t)] })), _jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 opacity-60" })] }) }), _jsx(PopoverContent, { side: "top", align: "end", sideOffset: 6, collisionPadding: 8, "data-agent-native-composer-popover": "true", className: `z-[260] overflow-visible ${MODEL_SELECTOR_POPOVER_CLASS}`, style: MODEL_SELECTOR_POPOVER_STYLE, children: _jsxs(Popover, { open: detailSection !== null, onOpenChange: () => undefined, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsxs("div", { className: "flex flex-col", role: "tablist", "aria-label": t("agentChat.composer.pickerSections", {
879
+ defaultValue: "Picker sections",
880
+ }), children: [agents && agents.length > 0 && (_jsxs("button", { type: "button", role: "tab", "aria-selected": resolvedSection === "agent", onClick: () => setDetailSection("agent"), onMouseEnter: () => setDetailSection("agent"), className: `flex w-full min-w-0 items-center gap-1 rounded-md px-2 py-2 text-start transition-colors ${resolvedSection === "agent"
881
+ ? "bg-accent text-foreground"
882
+ : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"}`, children: [_jsxs("span", { className: "flex min-w-0 items-center", children: [_jsx("span", { className: "shrink-0 text-[12px] font-medium", children: "Agent" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { role: "img", "aria-label": t("agentChat.composer.harnessAgentHelp", {
883
+ defaultValue: "Learn about harness agents",
884
+ }), onClick: (event) => event.stopPropagation(), className: `ms-1.5 ${PICKER_HELP_BUTTON_CLASS}`, children: _jsx(IconHelpCircle, { "aria-hidden": "true", className: PICKER_HELP_ICON_CLASS, strokeWidth: 1.8 }) }) }), _jsxs(TooltipContent, { side: "right", className: "z-[400] max-w-xs", children: [_jsx("span", { className: "block", children: hostedHarness
885
+ ? t("agentChat.composer.hostedHarnessDescription", {
886
+ defaultValue: "Hosted mode uses app tools only. For full coding with a repository and shell, use Agent Native Desktop.",
887
+ })
888
+ : t("agentChat.composer.harnessAgentDescription", {
889
+ defaultValue: "Harnesses run their own coding loop and local tools.",
890
+ }) }), _jsx("a", { href: HARNESS_AGENTS_DOCS_URL, target: "_blank", rel: "noreferrer", className: "mt-1 block underline underline-offset-2 hover:no-underline", children: t("agentChat.composer.learnMoreHarnessAgents", {
891
+ defaultValue: "Learn more about harness agents",
892
+ }) })] })] })] }), _jsx("span", { className: "ms-auto min-w-0 max-w-[6rem] truncate text-end text-[11px] text-muted-foreground/80", children: selectedAgentLabel }), _jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 opacity-60 rtl:-scale-x-100" })] })), _jsxs("button", { type: "button", role: "tab", "aria-selected": resolvedSection === "model", onClick: () => setDetailSection("model"), onMouseEnter: () => setDetailSection("model"), className: `flex w-full min-w-0 items-center gap-1 rounded-md px-2 py-2 text-start transition-colors ${resolvedSection === "model"
893
+ ? "bg-accent text-foreground"
894
+ : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"}`, children: [_jsx("span", { className: "shrink-0 text-[12px] font-medium", children: "Model" }), _jsx("span", { className: "ms-auto min-w-0 max-w-[6rem] truncate text-end text-[11px] text-muted-foreground/80", children: selectedModelLabel }), _jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 opacity-60 rtl:-scale-x-100" })] }), effortOptions.length > 0 && (_jsxs("button", { type: "button", role: "tab", "aria-selected": resolvedSection === "effort", onClick: () => setDetailSection("effort"), onMouseEnter: () => setDetailSection("effort"), className: `flex w-full min-w-0 items-center gap-1 rounded-md px-2 py-2 text-start transition-colors ${resolvedSection === "effort"
895
+ ? "bg-accent text-foreground"
896
+ : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"}`, children: [_jsx("span", { className: "shrink-0 text-[12px] font-medium", children: t("agentChat.composer.effort", {
897
+ defaultValue: "Effort",
898
+ }) }), _jsx("span", { className: "ms-auto min-w-0 max-w-[6rem] truncate text-end text-[11px] text-muted-foreground/80", children: effortLabel(selectedEffort) }), _jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 opacity-60 rtl:-scale-x-100" })] }))] }) }), _jsx(PopoverContent, { side: "right", align: "start", sideOffset: 4, alignOffset: -8, collisionPadding: 8, className: `z-[320] overflow-visible ${MODEL_SELECTOR_POPOVER_CLASS}`, style: MODEL_SELECTOR_POPOVER_STYLE, children: _jsx("div", { className: "max-h-[min(500px,var(--radix-popover-content-available-height,500px))] overflow-y-auto", children: _jsxs("div", { className: "min-h-0 min-w-0", role: "tabpanel", "aria-label": resolvedSection, children: [resolvedSection === "agent" && agents && (_jsx("div", { className: "flex flex-col", children: agents.map((agent) => {
899
+ const isSelected = agent.id === (selectedAgent ?? "default");
900
+ const isConfigured = agent.configured !== false;
901
+ const canConnect = !isConfigured && Boolean(onConnectLocalRuntime);
902
+ const statusLabel = agent.statusLabel ??
903
+ (!isConfigured ? "Unavailable" : undefined);
904
+ return (_jsxs("div", { className: "group flex items-center rounded-md hover:bg-accent/30", children: [_jsxs("button", { type: "button", disabled: !isConfigured || !onAgentChange, "aria-current": isSelected ? "true" : undefined, onClick: () => {
905
+ if (!isConfigured)
906
+ return;
907
+ onAgentChange?.(agent.id);
908
+ setPickerOpen(false);
909
+ }, className: `flex min-w-0 flex-1 items-center gap-0.5 px-2 py-2 text-start ${isConfigured
910
+ ? "hover:bg-accent/50"
911
+ : "cursor-default opacity-50"}`, children: [_jsx("span", { className: `min-w-0 truncate text-[12px] ${isSelected
912
+ ? "text-foreground"
913
+ : "text-muted-foreground"}`, children: agent.label }), agent.description && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { role: "img", "aria-label": `${agent.label} details`, onClick: (event) => event.stopPropagation(), className: PICKER_HELP_BUTTON_CLASS, children: _jsx(IconHelpCircle, { "aria-hidden": "true", className: PICKER_HELP_ICON_CLASS, strokeWidth: 1.8 }) }) }), _jsx(TooltipContent, { side: "left", className: "z-[400] max-w-xs", children: agent.description })] })), _jsx("span", { className: "min-w-0 flex-1", "aria-hidden": "true" }), isSelected && isConfigured && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] }), !isConfigured && statusLabel && (_jsx("button", { type: "button", disabled: !canConnect, className: "ms-auto max-w-[6rem] shrink-0 truncate px-2 py-2 text-end text-[10px] text-muted-foreground/70 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 hover:text-foreground focus-visible:opacity-100 disabled:cursor-default", onClick: () => {
914
+ if (canConnect)
915
+ connectLocalRuntime(agent.id);
916
+ }, children: statusLabel }))] }, agent.id));
917
+ }) })), resolvedSection === "model" && (_jsxs(_Fragment, { children: [showProviderActions && (_jsxs(_Fragment, { children: [showBuilderAction && (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => {
918
+ if (onConnectProvider) {
919
+ onConnectProvider();
920
+ }
921
+ else {
922
+ builderFlow.start();
923
+ }
924
+ }, disabled: !onConnectProvider && builderFlow.connecting, className: "flex w-full items-start gap-2 rounded-md px-2 py-2 text-start hover:bg-accent/50 disabled:opacity-60", children: [_jsx(IconPlugConnected, { className: "mt-0.5 h-4 w-4 shrink-0 text-primary" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block text-[12px] font-medium text-foreground", children: !onConnectProvider && builderFlow.connecting
925
+ ? t("agentPanel.connectingBuilder", {
926
+ defaultValue: "Connecting Builder.io…",
927
+ })
928
+ : t("agentPanel.connectBuilderIo", {
929
+ defaultValue: "Connect Builder.io",
930
+ }) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.builderModelCredits", {
931
+ defaultValue: "Free credits for Claude, OpenAI & Gemini",
932
+ }) })] })] }), !onConnectProvider && builderFlow.error && (_jsx("p", { role: "alert", className: "px-2 pb-2 ps-8 text-[11px] text-destructive", children: builderFlow.error }))] })), showAddKeysAction && (_jsxs("button", { type: "button", onClick: openLlmSettings, className: "flex w-full items-start gap-2 rounded-md px-2 py-2 text-start hover:bg-accent/50", children: [_jsx(IconKey, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block text-[12px] font-medium text-foreground", children: t("agentPanel.addOwnKeys", {
933
+ defaultValue: "Add your own keys",
934
+ }) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.configureProviderKeys", {
935
+ defaultValue: "Choose a cloud, gateway, or local provider",
936
+ }) })] })] }))] })), imageModel && imageModel.options.length > 0 && (_jsxs("div", { className: "mt-2 pt-1", children: [_jsx("div", { className: "px-2 py-1 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: imageModel.label ??
937
+ t("agentChat.composer.imageModel", {
938
+ defaultValue: "Image model",
939
+ }) }), imageModel.options.map((option) => (_jsxs("button", { type: "button", onClick: () => {
940
+ imageModel.onChange(option.value);
941
+ setPickerOpen(false);
942
+ }, className: "flex w-full items-center gap-3 rounded-md px-2 py-2 text-start hover:bg-accent/50", children: [_jsx("span", { className: `min-w-0 flex-1 truncate text-[12px] ${option.value === imageModel.value
943
+ ? "text-foreground"
944
+ : "text-muted-foreground"}`, children: option.label }), option.value === imageModel.value && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] }, option.value)))] })), showModelListSkeleton && _jsx(ModelSelectorSkeleton, {}), isCodexAgent &&
945
+ !showModelListSkeleton &&
946
+ !onlyConnectPathAvailable &&
947
+ modelProviderGroups.length === 0 && (_jsxs("button", { type: "button", onClick: openLlmSettings, className: "flex w-full items-center rounded-md px-2 py-2 text-start hover:bg-accent/50", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-[12px] text-muted-foreground", children: t("agentChat.composer.noOpenAiModels", {
948
+ defaultValue: "No OpenAI models configured",
949
+ }) }), _jsx("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: "Configure" })] })), autoModelGroup && !onlyConnectPathAvailable && (_jsxs("button", { type: "button", onClick: () => {
950
+ onChange("auto", autoModelGroup.engine);
951
+ setPickerOpen(false);
952
+ }, className: "mt-1 flex w-full items-center gap-3 rounded-md px-2 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: `min-w-0 flex-1 truncate text-[13px] ${model === "auto"
953
+ ? "text-foreground"
954
+ : "text-muted-foreground"}`, children: t("agentChat.composer.auto", {
955
+ defaultValue: "Auto",
956
+ }) }), model === "auto" && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] })), !onlyConnectPathAvailable &&
957
+ visibleProviderGroups.map((group, groupIndex) => {
958
+ const models = latestModelsOnly(group.models);
959
+ const showProviderLabels = visibleProviderGroups.length > 1;
960
+ const isLocalRuntime = group.engine === "codex-cli" ||
961
+ group.engine === "claude-cli";
962
+ const canConnectLocalRuntime = isLocalRuntime && Boolean(onConnectLocalRuntime);
963
+ const statusLabel = group.statusLabel ??
964
+ (!group.configured
965
+ ? canConnectLocalRuntime
966
+ ? t("agentChat.auth.logIn", {
967
+ defaultValue: "Sign in",
968
+ })
969
+ : t("agentChat.composer.needsApiKey", {
970
+ defaultValue: "needs API key",
971
+ })
972
+ : undefined);
973
+ return (_jsxs("div", { className: showProviderLabels && groupIndex > 0
974
+ ? "mt-2 pt-1"
975
+ : "", children: [showProviderLabels && (_jsxs("div", { className: "group flex items-center px-2 py-1", children: [_jsx("span", { className: "shrink-0 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: group.label }), !group.configured && statusLabel && (_jsx("button", { type: "button", "aria-label": statusLabel, className: "ms-auto max-w-[9rem] shrink-0 cursor-pointer truncate px-0 py-1 text-end text-[10px] text-muted-foreground/60 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 hover:text-foreground focus-visible:opacity-100", onClick: () => canConnectLocalRuntime
976
+ ? connectLocalRuntime(group.engine)
977
+ : openLlmSettings(), children: statusLabel })), group.configured && statusLabel && (_jsx("span", { className: "ms-auto max-w-[9rem] shrink-0 truncate py-1 text-end text-[10px] text-muted-foreground/70 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100", children: statusLabel }))] })), models.map((m) => {
978
+ const isSelected = m === model && group.configured;
979
+ return (_jsxs("button", { type: "button", onClick: () => {
980
+ if (!group.configured) {
981
+ if (canConnectLocalRuntime) {
982
+ connectLocalRuntime(group.engine);
983
+ }
984
+ else {
985
+ openLlmSettings();
986
+ }
987
+ return;
988
+ }
989
+ onChange(m, group.engine);
990
+ const nextOptions = getReasoningEffortOptionsForModel(m);
991
+ if (nextOptions.length > 0 &&
992
+ !nextOptions.includes(selectedEffort)) {
993
+ onEffortChange?.(defaultEffort);
994
+ }
995
+ setPickerOpen(false);
996
+ }, className: `group flex w-full items-center gap-3 rounded-md px-2 py-2 text-start ${group.configured
997
+ ? "hover:bg-accent/50"
998
+ : "cursor-default opacity-40"}`, children: [_jsx("span", { className: `min-w-0 flex-1 truncate text-[12px] ${isSelected
999
+ ? "text-foreground"
1000
+ : "text-muted-foreground"}`, children: friendlyModelName(m, t) }), _jsx(ModelCostTier, { model: m }), !showProviderLabels && statusLabel && (_jsx("span", { className: "hidden max-w-[9rem] shrink-0 truncate text-[10px] text-muted-foreground/70 group-hover:inline", children: statusLabel })), isSelected && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] }, m));
1001
+ })] }, `${group.engine}:${group.label}`));
1002
+ })] })), resolvedSection === "effort" && effortOptions.length > 0 && (_jsx("div", { className: "flex flex-col", children: effortOptions.map((option) => (_jsxs("button", { type: "button", onClick: () => onEffortChange?.(option), className: "flex w-full items-center gap-3 rounded-md px-2 py-2 text-start hover:bg-accent/50", children: [_jsx("span", { className: `min-w-0 flex-1 truncate text-[12px] ${option === selectedEffort
1003
+ ? "text-foreground"
1004
+ : "text-muted-foreground"}`, children: effortLabel(option) }), option === selectedEffort && (_jsx(IconCheck, { className: "size-4 shrink-0 text-primary" }))] }, option))) }))] }) }) })] }) })] }));
918
1005
  }
919
1006
  function ModelSelectorSkeleton() {
920
1007
  const t = useComposerRuntimeAdapters().translate;
@@ -924,7 +1011,7 @@ function ModelSelectorSkeleton() {
924
1011
  defaultValue: "Loading models…",
925
1012
  }) }), ["w-24", "w-32", "w-20", "w-28"].map((width, index) => (_jsxs("div", { className: "flex items-center gap-1.5 px-1 py-1.5", children: [_jsx(Skeleton, { className: "size-3 rounded-sm" }), _jsx(Skeleton, { className: `h-3 ${width}` })] }, index)))] }));
926
1013
  }
927
- export function TiptapComposer({ placeholder, disabled = false, maxDocumentAttachmentBytes = MAX_DOCUMENT_ATTACHMENT_BYTES, documentAttachmentLimitLabel = "PDFs", focusRef, initialText, initialTextKey, onSubmit, onBeforeSubmit, clearOnSubmit = true, onTextChange, actionButton, willQueue = false, extraActionButton, stopButton, attachButton, modeControl, toolbarSlot, layoutVariant = "default", slashCommands = [], slashSkills = [], includeDefaultSlashCommands = true, includeDefaultSlashSkills = true, onSlashCommand, execMode, onExecModeChange, planModeDisabled = false, planModeDisabledReason, voiceEnabled = DEFAULT_VOICE_DICTATION_ENABLED, selectedModel, selectedEffort, showAutoModelOption = true, availableModels, modelListLoading, onModelChange, onEffortChange, availableAgents, selectedAgent, onAgentChange, providerConnectStatusEnabled, onConnectProvider, onConnectLocalRuntime, imageModelMenu, draftScope, contextItems = [], onRemoveContextItem, plusMenuMode = "full", extensionTools = false, interceptBuildRequestsForBuilder = false, onAttachmentError, }) {
1014
+ export function TiptapComposer({ placeholder, disabled = false, maxDocumentAttachmentBytes = MAX_DOCUMENT_ATTACHMENT_BYTES, documentAttachmentLimitLabel = "PDFs", focusRef, initialText, initialTextKey, onSubmit, onBeforeSubmit, clearOnSubmit = true, onTextChange, actionButton, willQueue = false, extraActionButton, stopButton, attachButton, modeControl, toolbarSlot, layoutVariant = "default", slashCommands = [], slashSkills = [], includeDefaultSlashCommands = true, includeDefaultSlashSkills = true, onSlashCommand, execMode, onExecModeChange, planModeDisabled = false, planModeDisabledReason, voiceEnabled = DEFAULT_VOICE_DICTATION_ENABLED, selectedModel, selectedEffort, showAutoModelOption = true, modelSelectorOpen, availableModels, modelListLoading, onModelChange, onEffortChange, availableAgents, selectedAgent, hostedHarness, onAgentChange, onModelSelectorOpenChange, providerConnectStatusEnabled, onConnectProvider, onConnectLocalRuntime, imageModelMenu, draftScope, contextItems = [], onRemoveContextItem, plusMenuMode = "full", extensionTools = false, interceptBuildRequestsForBuilder = false, onAttachmentError, }) {
928
1015
  const adapters = useComposerRuntimeAdapters();
929
1016
  const t = adapters.translate;
930
1017
  const sendButtonTooltip = t(getComposerSendTooltipKey(willQueue), {
@@ -2139,6 +2226,6 @@ export function TiptapComposer({ placeholder, disabled = false, maxDocumentAttac
2139
2226
  defaultValue: "Remove {{name}} context",
2140
2227
  name: item.title,
2141
2228
  }), className: "ms-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconX, { className: "h-3 w-3" }) })] }, item.key)))] })), _jsx("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "editor-wrap", className: `agent-composer-editor-wrap ${composerMode || hasContextRows ? "px-2 pt-1 pb-1" : "px-2 pt-2 pb-1"}`, children: _jsx(EditorContent, { editor: editor, "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "editor", className: "agent-composer-editor aui-composer flex-1 min-w-0 [&_.ProseMirror]:outline-none [&_.ProseMirror_p]:m-0 px-0.5" }) }), voiceEnabled && _jsx(VoiceRecordingOverlay, { voice: voice }), _jsxs("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "toolbar", className: "agent-composer-toolbar flex items-center gap-1 px-2 py-1.5", children: [attachButton ??
2142
- (plusMenuMode === "hidden" ? null : (_jsx(ComposerPlusMenu, { onSelectMode: handleSelectMode, mode: plusMenuMode, extensionTools: extensionTools, onAttachmentError: onAttachmentError }))), toolbarSlot ?? modeControl, _jsx("div", { "data-agent-composer-slot": "toolbar-spacer", className: "flex-1" }), selectedModel && availableModels && onModelChange && (_jsx(ModelSelector, { model: selectedModel, effort: selectedEffort, engines: availableModels, agents: availableAgents, selectedAgent: selectedAgent, showAutoModelOption: showAutoModelOption, modelListLoading: modelListLoading, onChange: onModelChange, onEffortChange: onEffortChange, onAgentChange: onAgentChange, providerConnectStatusEnabled: providerConnectStatusEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, imageModel: imageModelMenu })), execMode && onExecModeChange && (_jsx(ModeSelector, { mode: execMode, onChange: onExecModeChange, planModeDisabled: planModeDisabled, planModeDisabledReason: planModeDisabledReason })), actionButton ?? (_jsxs(_Fragment, { children: [extraActionButton, voiceEnabled && (_jsx(VoiceButton, { voice: voice, isMac: isMac, disabled: disabled })), primaryAction === "stop" ? (stopButton) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => void submitComposer("immediate"), disabled: !canSend, "data-agent-composer-slot": "send-button", className: "agent-composer-send-button shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-primary text-primary-foreground hover:opacity-90 transition-[opacity,transform] duration-150 active:scale-[0.97] disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx(IconArrowUp, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: sendButtonTooltip })] }))] }))] }), _jsx(MentionPopover, { ref: popoverRef, type: popover?.type ?? "@", position: popover?.position ?? null, mentionItems: filteredMentionItems, skills: filteredSkills, commands: filteredCommands, hint: hint, isLoading: popover?.type === "@" ? mentionsLoading : skillsLoading, query: popover?.query ?? "", onSelectMention: handleSelectMention, onSelectSkill: handleSelectSkill, onSelectCommand: handleSelectCommand, onClose: closePopover })] }));
2229
+ (plusMenuMode === "hidden" ? null : (_jsx(ComposerPlusMenu, { onSelectMode: handleSelectMode, mode: plusMenuMode, extensionTools: extensionTools, onAttachmentError: onAttachmentError }))), toolbarSlot ?? modeControl, _jsx("div", { "data-agent-composer-slot": "toolbar-spacer", className: "flex-1" }), selectedModel && availableModels && onModelChange && (_jsx(ModelSelector, { model: selectedModel, open: modelSelectorOpen, effort: selectedEffort, engines: availableModels, agents: availableAgents, selectedAgent: selectedAgent, hostedHarness: hostedHarness, showAutoModelOption: showAutoModelOption, modelListLoading: modelListLoading, onChange: onModelChange, onEffortChange: onEffortChange, onAgentChange: onAgentChange, onModelSelectorOpenChange: onModelSelectorOpenChange, providerConnectStatusEnabled: providerConnectStatusEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, imageModel: imageModelMenu })), execMode && onExecModeChange && (_jsx(ModeSelector, { mode: execMode, onChange: onExecModeChange, planModeDisabled: planModeDisabled, planModeDisabledReason: planModeDisabledReason })), actionButton ?? (_jsxs(_Fragment, { children: [extraActionButton, voiceEnabled && (_jsx(VoiceButton, { voice: voice, isMac: isMac, disabled: disabled })), primaryAction === "stop" ? (stopButton) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => void submitComposer("immediate"), disabled: !canSend, "data-agent-composer-slot": "send-button", className: "agent-composer-send-button shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-primary text-primary-foreground hover:opacity-90 transition-[opacity,transform] duration-150 active:scale-[0.97] disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx(IconArrowUp, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: sendButtonTooltip })] }))] }))] }), _jsx(MentionPopover, { ref: popoverRef, type: popover?.type ?? "@", position: popover?.position ?? null, mentionItems: filteredMentionItems, skills: filteredSkills, commands: filteredCommands, hint: hint, isLoading: popover?.type === "@" ? mentionsLoading : skillsLoading, query: popover?.query ?? "", onSelectMention: handleSelectMention, onSelectSkill: handleSelectSkill, onSelectCommand: handleSelectCommand, onClose: closePopover })] }));
2143
2230
  }
2144
2231
  //# sourceMappingURL=TiptapComposer.js.map