diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
index 5cc114f92f0..3ff8fec4b93 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
@@ -24,7 +24,7 @@ export function createDialogProviderOptions() {
const dialog = useDialog()
const sdk = useSDK()
const options = createMemo(() => {
- return pipe(
+ const providerOptions = pipe(
sync.data.provider_next.all,
sortBy((x) => PROVIDER_PRIORITY[x.id] ?? 99),
map((provider) => ({
@@ -84,6 +84,19 @@ export function createDialogProviderOptions() {
},
})),
)
+
+ // Add "Other" option for custom providers
+ providerOptions.push({
+ title: "Other",
+ value: "other",
+ description: "(Custom provider)",
+ category: "Other",
+ async onSelect() {
+ dialog.replace(() => )
+ },
+ })
+
+ return providerOptions
})
return options
}
@@ -222,3 +235,58 @@ function ApiMethod(props: ApiMethodProps) {
/>
)
}
+
+function CustomProviderMethod() {
+ const dialog = useDialog()
+ const sdk = useSDK()
+ const sync = useSync()
+ const { theme } = useTheme()
+ const [providerID, setProviderID] = createSignal(null)
+
+ return (
+ (
+ Enter a unique identifier for your custom provider (e.g. my-provider)
+ )}
+ onConfirm={(value) => {
+ if (!value) return
+ const cleaned = value.replace(/^@ai-sdk\//, "")
+ if (!cleaned.match(/^[0-9a-z-]+$/)) return
+ setProviderID(cleaned)
+ }}
+ />
+ }
+ >
+ (
+
+
+ This only stores a credential for {providerID()} - you will need
+ to configure it in opencode.json
+
+
+ )}
+ onConfirm={async (value) => {
+ if (!value) return
+ sdk.client.auth.set({
+ providerID: providerID()!,
+ auth: {
+ type: "api",
+ key: value,
+ },
+ })
+ await sdk.client.instance.dispose()
+ await sync.bootstrap()
+ dialog.clear()
+ }}
+ />
+
+ )
+}