diff --git a/packages/client-runtime/src/state/providerInstanceDisplay.test.ts b/packages/client-runtime/src/state/providerInstanceDisplay.test.ts index 7068a761605a1..27129f11128b3 100644 --- a/packages/client-runtime/src/state/providerInstanceDisplay.test.ts +++ b/packages/client-runtime/src/state/providerInstanceDisplay.test.ts @@ -12,6 +12,15 @@ const codex = ProviderDriverKind.make("codex"); const acpRegistry = ProviderDriverKind.make("acpRegistry"); describe("providerInstanceInitials", () => { + it("treats punctuation as a word break but keeps apostrophes between letters", () => { + expect(providerInstanceInitials("Codex (hub)")).toBe("CH"); + expect(providerInstanceInitials("work_codex")).toBe("WC"); + expect(providerInstanceInitials("Theo's Codex")).toBe("TC"); + expect(providerInstanceInitials("Codex 'hub'")).toBe("CH"); + expect(providerInstanceInitials("‘hub’")).toBe("HU"); + expect(providerInstanceInitials("(hub)")).toBe("HU"); + }); + it("keeps an emoji whole instead of splitting its surrogate pair", () => { expect(providerInstanceInitials("😀 Work")).toBe("😀W"); expect(providerInstanceInitials("😀")).toBe("😀"); diff --git a/packages/client-runtime/src/state/providerInstanceDisplay.ts b/packages/client-runtime/src/state/providerInstanceDisplay.ts index 64d1d941f1122..62f65445e8217 100644 --- a/packages/client-runtime/src/state/providerInstanceDisplay.ts +++ b/packages/client-runtime/src/state/providerInstanceDisplay.ts @@ -27,7 +27,14 @@ export function resolveProviderInstanceDisplayName( } export function providerInstanceInitials(label: string): string { - const words = label.replace(/[_-]+/g, " ").split(/\s+/u).filter(Boolean); + // Punctuation separates words so "Codex (hub)" reads CH, not C(. An apostrophe + // inside a word stays ("Theo's Codex" is TC); a quoting one does not + // ("Codex 'hub'" is CH). + const words = label + .replace(/[^\P{P}'’]+/gu, " ") + .split(/\s+/u) + .map((word) => word.replace(/^['’]+|['’]+$/gu, "")) + .filter(Boolean); if (words.length === 0) return ""; if (words.length === 1) return Array.from(words[0]!).slice(0, 2).join("").toUpperCase(); return words