diff --git a/ui-tui/src/__tests__/providers.test.ts b/ui-tui/src/__tests__/providers.test.ts
new file mode 100644
index 0000000000..a46102e893
--- /dev/null
+++ b/ui-tui/src/__tests__/providers.test.ts
@@ -0,0 +1,62 @@
+import { describe, expect, it } from 'vitest'
+
+import { providerDisplayNames } from '../domain/providers.js'
+
+describe('providerDisplayNames', () => {
+ it('returns bare names when all are unique', () => {
+ expect(providerDisplayNames([{ name: 'Anthropic', slug: 'anthropic' }, { name: 'OpenAI', slug: 'openai' }])).toEqual(
+ ['Anthropic', 'OpenAI']
+ )
+ })
+
+ it('appends slug to every collision so the disambiguation is symmetric', () => {
+ expect(
+ providerDisplayNames([
+ { name: 'Kimi For Coding', slug: 'kimi-coding' },
+ { name: 'Kimi For Coding', slug: 'kimi-coding-cn' }
+ ])
+ ).toEqual(['Kimi For Coding (kimi-coding)', 'Kimi For Coding (kimi-coding-cn)'])
+ })
+
+ it('only disambiguates the colliding group', () => {
+ expect(
+ providerDisplayNames([
+ { name: 'Anthropic', slug: 'anthropic' },
+ { name: 'Foo', slug: 'foo-a' },
+ { name: 'Foo', slug: 'foo-b' }
+ ])
+ ).toEqual(['Anthropic', 'Foo (foo-a)', 'Foo (foo-b)'])
+ })
+
+ it('falls back to plain name if slug is empty', () => {
+ expect(
+ providerDisplayNames([
+ { name: 'Foo', slug: '' },
+ { name: 'Foo', slug: '' }
+ ])
+ ).toEqual(['Foo', 'Foo'])
+ })
+
+ it('skips disambiguation when slug equals name', () => {
+ expect(
+ providerDisplayNames([
+ { name: 'foo', slug: 'foo' },
+ { name: 'foo', slug: 'foo' }
+ ])
+ ).toEqual(['foo', 'foo'])
+ })
+
+ it('handles empty input', () => {
+ expect(providerDisplayNames([])).toEqual([])
+ })
+
+ it('preserves order', () => {
+ const input = [
+ { name: 'Z', slug: 'z' },
+ { name: 'A', slug: 'a1' },
+ { name: 'A', slug: 'a2' }
+ ]
+
+ expect(providerDisplayNames(input)).toEqual(['Z', 'A (a1)', 'A (a2)'])
+ })
+})
diff --git a/ui-tui/src/components/modelPicker.tsx b/ui-tui/src/components/modelPicker.tsx
index 10a00cdf19..1bc95481da 100644
--- a/ui-tui/src/components/modelPicker.tsx
+++ b/ui-tui/src/components/modelPicker.tsx
@@ -1,6 +1,7 @@
import { Box, Text, useInput } from '@hermes/ink'
-import { useEffect, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
+import { providerDisplayNames } from '../domain/providers.js'
import type { GatewayClient } from '../gatewayClient.js'
import type { ModelOptionProvider, ModelOptionsResponse } from '../gatewayTypes.js'
import { asRpcResult, rpcErrorMessage } from '../lib/rpc.js'
@@ -59,6 +60,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
const provider = providers[providerIdx]
const models = provider?.models ?? []
+ const names = useMemo(() => providerDisplayNames(providers), [providers])
useInput((ch, key) => {
if (key.escape) {
@@ -160,7 +162,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
if (stage === 'provider') {
const rows = providers.map(
- p => `${p.is_current ? '*' : ' '} ${p.name} · ${p.total_models ?? p.models?.length ?? 0} models`
+ (p, i) => `${p.is_current ? '*' : ' '} ${names[i]} · ${p.total_models ?? p.models?.length ?? 0} models`
)
const { items, off } = visibleItems(rows, providerIdx)
@@ -201,7 +203,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
Select Model
- {provider?.name || '(unknown provider)'}
+ {names[providerIdx] || '(unknown provider)'}
{!models.length ? no models listed for this provider : null}
{provider?.warning ? warning: {provider.warning} : null}
{off > 0 && ↑ {off} more}
diff --git a/ui-tui/src/domain/providers.ts b/ui-tui/src/domain/providers.ts
new file mode 100644
index 0000000000..02cc99b922
--- /dev/null
+++ b/ui-tui/src/domain/providers.ts
@@ -0,0 +1,17 @@
+export const providerDisplayNames = (providers: readonly { name: string; slug: string }[]): string[] => {
+ const counts = new Map()
+
+ for (const p of providers) {
+ counts.set(p.name, (counts.get(p.name) ?? 0) + 1)
+ }
+
+ return providers.map(p => {
+ const dup = (counts.get(p.name) ?? 0) > 1
+
+ if (!dup || !p.slug || p.slug === p.name) {
+ return p.name
+ }
+
+ return `${p.name} (${p.slug})`
+ })
+}