summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/app/src/components')
-rw-r--r--packages/app/src/components/prompt-input.tsx203
1 files changed, 109 insertions, 94 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
index 534215022..156b0b3a4 100644
--- a/packages/app/src/components/prompt-input.tsx
+++ b/packages/app/src/components/prompt-input.tsx
@@ -54,6 +54,8 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments"
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
import { promptPlaceholder } from "./prompt-input/placeholder"
import { ImagePreview } from "@opencode-ai/ui/image-preview"
+import { useQuery } from "@tanstack/solid-query"
+import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
interface PromptInputProps {
class?: string
@@ -100,6 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/
export const PromptInput: Component<PromptInputProps> = (props) => {
const sdk = useSDK()
+
const sync = useSync()
const local = useLocal()
const files = useFile()
@@ -1249,6 +1252,14 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}
}
+ const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory))
+ const agentsLoading = () => agentsQuery.isLoading
+
+ const globalProvidersQuery = useQuery(() => loadProvidersQuery(null))
+ const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory))
+
+ const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
+
return (
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
<PromptPopover
@@ -1444,53 +1455,89 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
<div class="size-4 shrink-0" />
</div>
- <div class="flex items-center gap-1.5 min-w-0 flex-1">
- <div data-component="prompt-agent-control">
- <TooltipKeybind
- placement="top"
- gutter={4}
- title={language.t("command.agent.cycle")}
- keybind={command.keybind("agent.cycle")}
- >
- <Select
- size="normal"
- options={agentNames()}
- current={local.agent.current()?.name ?? ""}
- onSelect={(value) => {
- local.agent.set(value)
- restoreFocus()
- }}
- class="capitalize max-w-[160px] text-text-base"
- valueClass="truncate text-13-regular text-text-base"
- triggerStyle={control()}
- triggerProps={{ "data-action": "prompt-agent" }}
- variant="ghost"
- />
- </TooltipKeybind>
- </div>
- <Show when={store.mode !== "shell"}>
- <div data-component="prompt-model-control">
- <Show
- when={providers.paid().length > 0}
- fallback={
+ <div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
+ <Show when={!agentsLoading()}>
+ <div data-component="prompt-agent-control">
+ <TooltipKeybind
+ placement="top"
+ gutter={4}
+ title={language.t("command.agent.cycle")}
+ keybind={command.keybind("agent.cycle")}
+ >
+ <Select
+ size="normal"
+ options={agentNames()}
+ current={local.agent.current()?.name ?? ""}
+ onSelect={(value) => {
+ local.agent.set(value)
+ restoreFocus()
+ }}
+ class="capitalize max-w-[160px] text-text-base"
+ valueClass="truncate text-13-regular text-text-base"
+ triggerStyle={control()}
+ triggerProps={{ "data-action": "prompt-agent" }}
+ variant="ghost"
+ />
+ </TooltipKeybind>
+ </div>
+ </Show>
+ <Show when={!providersLoading()}>
+ <Show when={store.mode !== "shell"}>
+ <div data-component="prompt-model-control">
+ <Show
+ when={providers.paid().length > 0}
+ fallback={
+ <TooltipKeybind
+ placement="top"
+ gutter={4}
+ title={language.t("command.model.choose")}
+ keybind={command.keybind("model.choose")}
+ >
+ <Button
+ data-action="prompt-model"
+ as="div"
+ variant="ghost"
+ size="normal"
+ class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
+ style={control()}
+ onClick={() => {
+ void import("@/components/dialog-select-model-unpaid").then((x) => {
+ dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
+ })
+ }}
+ >
+ <Show when={local.model.current()?.provider?.id}>
+ <ProviderIcon
+ id={local.model.current()?.provider?.id ?? ""}
+ class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
+ style={{ "will-change": "opacity", transform: "translateZ(0)" }}
+ />
+ </Show>
+ <span class="truncate">
+ {local.model.current()?.name ?? language.t("dialog.model.select.title")}
+ </span>
+ <Icon name="chevron-down" size="small" class="shrink-0" />
+ </Button>
+ </TooltipKeybind>
+ }
+ >
<TooltipKeybind
placement="top"
gutter={4}
title={language.t("command.model.choose")}
keybind={command.keybind("model.choose")}
>
- <Button
- data-action="prompt-model"
- as="div"
- variant="ghost"
- size="normal"
- class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
- style={control()}
- onClick={() => {
- void import("@/components/dialog-select-model-unpaid").then((x) => {
- dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
- })
+ <ModelSelectorPopover
+ model={local.model}
+ triggerAs={Button}
+ triggerProps={{
+ variant: "ghost",
+ size: "normal",
+ style: control(),
+ class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
+ "data-action": "prompt-model",
}}
+ onClose={restoreFocus}
>
<Show when={local.model.current()?.provider?.id}>
<ProviderIcon
@@ -1503,67 +1550,35 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
</span>
<Icon name="chevron-down" size="small" class="shrink-0" />
- </Button>
+ </ModelSelectorPopover>
</TooltipKeybind>
- }
- >
+ </Show>
+ </div>
+ <div data-component="prompt-variant-control">
<TooltipKeybind
placement="top"
gutter={4}
- title={language.t("command.model.choose")}
- keybind={command.keybind("model.choose")}
+ title={language.t("command.model.variant.cycle")}
+ keybind={command.keybind("model.variant.cycle")}
>
- <ModelSelectorPopover
- model={local.model}
- triggerAs={Button}
- triggerProps={{
- variant: "ghost",
- size: "normal",
- style: control(),
- class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
- "data-action": "prompt-model",
+ <Select
+ size="normal"
+ options={variants()}
+ current={local.model.variant.current() ?? "default"}
+ label={(x) => (x === "default" ? language.t("common.default") : x)}
+ onSelect={(value) => {
+ local.model.variant.set(value === "default" ? undefined : value)
+ restoreFocus()
}}
- onClose={restoreFocus}
- >
- <Show when={local.model.current()?.provider?.id}>
- <ProviderIcon
- id={local.model.current()?.provider?.id ?? ""}
- class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
- style={{ "will-change": "opacity", transform: "translateZ(0)" }}
- />
- </Show>
- <span class="truncate">
- {local.model.current()?.name ?? language.t("dialog.model.select.title")}
- </span>
- <Icon name="chevron-down" size="small" class="shrink-0" />
- </ModelSelectorPopover>
+ class="capitalize max-w-[160px] text-text-base"
+ valueClass="truncate text-13-regular text-text-base"
+ triggerStyle={control()}
+ triggerProps={{ "data-action": "prompt-model-variant" }}
+ variant="ghost"
+ />
</TooltipKeybind>
- </Show>
- </div>
- <div data-component="prompt-variant-control">
- <TooltipKeybind
- placement="top"
- gutter={4}
- title={language.t("command.model.variant.cycle")}
- keybind={command.keybind("model.variant.cycle")}
- >
- <Select
- size="normal"
- options={variants()}
- current={local.model.variant.current() ?? "default"}
- label={(x) => (x === "default" ? language.t("common.default") : x)}
- onSelect={(value) => {
- local.model.variant.set(value === "default" ? undefined : value)
- restoreFocus()
- }}
- class="capitalize max-w-[160px] text-text-base"
- valueClass="truncate text-13-regular text-text-base"
- triggerStyle={control()}
- triggerProps={{ "data-action": "prompt-model-variant" }}
- variant="ghost"
- />
- </TooltipKeybind>
- </div>
+ </div>
+ </Show>
</Show>
</div>
</div>