summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-30 20:06:03 -0600
committerAdam <[email protected]>2025-12-30 20:06:03 -0600
commit1e74560796da159d393210a150ba4fb9d41b8792 (patch)
tree847c809961d5930929ac987da64a321a3fa6c01d
parent48f2419d9d8495a94af11167a44c29c0efd19766 (diff)
downloadopencode-1e74560796da159d393210a150ba4fb9d41b8792.tar.gz
opencode-1e74560796da159d393210a150ba4fb9d41b8792.zip
feat(app): model variants
-rw-r--r--packages/app/src/components/prompt-input.tsx33
-rw-r--r--packages/app/src/context/local.tsx41
2 files changed, 68 insertions, 6 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
index df8a2f3b2..5128fc0e6 100644
--- a/packages/app/src/components/prompt-input.tsx
+++ b/packages/app/src/components/prompt-input.tsx
@@ -1126,6 +1126,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
providerID: currentModel.provider.id,
}
const agent = currentAgent.name
+ const variant = local.model.variant.current()
if (isShellMode) {
sdk.client.session
@@ -1153,6 +1154,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
arguments: args.join(" "),
agent,
model: `${model.providerID}/${model.modelID}`,
+ variant,
})
.catch((e) => {
console.error("Failed to send command", e)
@@ -1189,6 +1191,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
model,
messageID,
parts: requestParts,
+ variant,
})
.catch((e) => {
console.error("Failed to send prompt", e)
@@ -1375,9 +1378,14 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<Tooltip
placement="top"
value={
- <div class="flex items-center gap-2">
- <span>Choose model</span>
- <span class="text-icon-base text-12-medium">{command.keybind("model.choose")}</span>
+ <div class="flex flex-col gap-1">
+ <div class="flex items-center gap-2">
+ <span>Choose model</span>
+ <span class="text-icon-base text-12-medium">{command.keybind("model.choose")}</span>
+ </div>
+ <Show when={local.model.current()?.provider.name}>
+ <span class="text-text-weak">{local.model.current()?.provider.name}</span>
+ </Show>
</div>
}
>
@@ -1391,12 +1399,25 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}
>
{local.model.current()?.name ?? "Select model"}
- <span class="hidden md:block ml-0.5 text-text-weak text-12-regular">
- {local.model.current()?.provider.name}
- </span>
<Icon name="chevron-down" size="small" />
</Button>
</Tooltip>
+ <Show when={local.model.variant.list().length > 0}>
+ <Tooltip placement="top" value="Cycle effort level">
+ <Button
+ variant="ghost"
+ onClick={() => local.model.variant.cycle()}
+ classList={{
+ "text-icon-warning": !!local.model.variant.current(),
+ }}
+ >
+ <Icon name="brain" size="small" />
+ <Show when={local.model.variant.current()}>
+ <span class="text-12-regular">{local.model.variant.current()}</span>
+ </Show>
+ </Button>
+ </Tooltip>
+ </Show>
</Match>
</Switch>
</div>
diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx
index 23d706bb0..559d5c2f9 100644
--- a/packages/app/src/context/local.tsx
+++ b/packages/app/src/context/local.tsx
@@ -115,9 +115,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
createStore<{
user: (ModelKey & { visibility: "show" | "hide"; favorite?: boolean })[]
recent: ModelKey[]
+ variant?: Record<string, string | undefined>
}>({
user: [],
recent: [],
+ variant: {},
}),
)
@@ -272,6 +274,45 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
setVisibility(model: ModelKey, visible: boolean) {
updateVisibility(model, visible ? "show" : "hide")
},
+ variant: {
+ current() {
+ const m = current()
+ if (!m) return undefined
+ const key = `${m.provider.id}/${m.id}`
+ return store.variant?.[key]
+ },
+ list() {
+ const m = current()
+ if (!m) return []
+ if (!m.variants) return []
+ return Object.keys(m.variants)
+ },
+ set(value: string | undefined) {
+ const m = current()
+ if (!m) return
+ const key = `${m.provider.id}/${m.id}`
+ if (!store.variant) {
+ setStore("variant", { [key]: value })
+ } else {
+ setStore("variant", key, value)
+ }
+ },
+ cycle() {
+ const variants = this.list()
+ if (variants.length === 0) return
+ const currentVariant = this.current()
+ if (!currentVariant) {
+ this.set(variants[0])
+ return
+ }
+ const index = variants.indexOf(currentVariant)
+ if (index === -1 || index === variants.length - 1) {
+ this.set(undefined)
+ return
+ }
+ this.set(variants[index + 1])
+ },
+ },
}
})()