From 8bd177971a8bb63e826b7e4d93b680d45d2b80cb Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Fri, 15 May 2026 22:09:18 +0400 Subject: [PATCH] studio/chat: friendly English-word names for auto-created containers Replaces the "chat-" auto-name with a random English-word + short hex suffix (e.g. "kestrel-3f9c"). Applies only to the chat-adapter's lazy-create path; the OpenAI container_auto path stays unnamed (only fires when no custom TTL is set). --- .../src/features/chat/api/chat-adapter.ts | 6 +- .../src/features/chat/lib/friendly-names.ts | 244 ++++++++++++++++++ 2 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 studio/frontend/src/features/chat/lib/friendly-names.ts diff --git a/studio/frontend/src/features/chat/api/chat-adapter.ts b/studio/frontend/src/features/chat/api/chat-adapter.ts index c0e09febb7..d091c14a90 100644 --- a/studio/frontend/src/features/chat/api/chat-adapter.ts +++ b/studio/frontend/src/features/chat/api/chat-adapter.ts @@ -15,6 +15,7 @@ import { streamChatCompletions, validateModel, } from "./chat-api"; +import { pickFriendlyContainerName } from "../lib/friendly-names"; import { createOpenAIContainer } from "./openai-containers"; import { encryptProviderApiKey, @@ -1056,7 +1057,10 @@ export function createOpenAIStreamAdapter(): ChatModelAdapter { baseUrl: externalProvider.baseUrl || null, }, { - name: `chat-${resolvedThreadId.slice(0, 8)}`, + // Friendly English-word name so the container + // is human-readable in the picker list (e.g. + // "kestrel-3f9c") instead of a thread-id slug. + name: pickFriendlyContainerName(), ttlMinutes: ttl, }, ); diff --git a/studio/frontend/src/features/chat/lib/friendly-names.ts b/studio/frontend/src/features/chat/lib/friendly-names.ts new file mode 100644 index 0000000000..503008f761 --- /dev/null +++ b/studio/frontend/src/features/chat/lib/friendly-names.ts @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +/** + * Friendly default names for auto-created OpenAI shell containers. + * Used by the chat-adapter when the lazy-create path fires (Code pill + * on, no thread container yet, user has set a non-default TTL). The + * goal is a human-memorable label like "otter" or "harbor" instead of + * "chat-abc12345" — the user can still rename via the Studio-side + * alias map. + * + * The list is curated to: + * - Be unambiguous, non-offensive nouns from natural categories + * (animals, plants, geography, materials, weather). + * - Avoid technical / political / brand words that might read as + * odd in a chat UI. + * - Stay reasonably small so the bundle cost is negligible (~200 + * entries × ~7 bytes ≈ 1.5 KB). + * + * Collisions are tolerated — the container's real unique key is its + * ``cntr_*`` id, not its name. A short random hex suffix is appended + * to make accidental same-name collisions visually distinct in the + * picker list. + */ + +const WORDS = [ + // animals + "otter", + "falcon", + "heron", + "lynx", + "marten", + "stoat", + "raven", + "magpie", + "salmon", + "trout", + "perch", + "tortoise", + "gecko", + "iguana", + "axolotl", + "narwhal", + "manatee", + "dolphin", + "porpoise", + "octopus", + "cuttlefish", + "nautilus", + "starfish", + "urchin", + "anemone", + "coral", + "puffin", + "kestrel", + "osprey", + "buzzard", + "kingfisher", + "robin", + "wren", + "finch", + "sparrow", + "thrush", + "siskin", + "warbler", + "tanager", + "oriole", + "hare", + "badger", + "weasel", + "ferret", + "polecat", + "civet", + "tapir", + "okapi", + "ibex", + "chamois", + // plants & trees + "alder", + "aspen", + "birch", + "cedar", + "cypress", + "elder", + "elm", + "fir", + "ginkgo", + "hawthorn", + "hazel", + "hemlock", + "holly", + "juniper", + "larch", + "linden", + "maple", + "oak", + "olive", + "pine", + "rowan", + "spruce", + "sycamore", + "willow", + "yew", + "thistle", + "fern", + "moss", + "ivy", + "clover", + "heather", + "lavender", + "rosemary", + "sage", + "thyme", + "myrtle", + "laurel", + "magnolia", + // geography / landscape + "harbor", + "atoll", + "lagoon", + "estuary", + "fjord", + "delta", + "isthmus", + "mesa", + "plateau", + "valley", + "ridge", + "summit", + "glade", + "meadow", + "moor", + "heath", + "tundra", + "savanna", + "prairie", + "steppe", + "bayou", + "marsh", + "fen", + "grotto", + "cavern", + "canyon", + "ravine", + "gorge", + "knoll", + "dell", + "vale", + "coast", + // materials / minerals / colors + "amber", + "agate", + "onyx", + "opal", + "jade", + "quartz", + "obsidian", + "basalt", + "granite", + "marble", + "slate", + "flint", + "lapis", + "topaz", + "garnet", + "pearl", + "coral", + "ivory", + "ebony", + "copper", + "cobalt", + "indigo", + "saffron", + "vermilion", + "ochre", + "umber", + "sienna", + "russet", + // weather / sky / time + "aurora", + "comet", + "ember", + "frost", + "gale", + "harvest", + "monsoon", + "nebula", + "solstice", + "twilight", + "zephyr", + "drizzle", + "tempest", + "halcyon", + "equinox", + "rainbow", + "horizon", + "meridian", + "zenith", + "comet", + // misc tactile / cozy nouns + "lantern", + "kettle", + "compass", + "anchor", + "beacon", + "harbor", + "voyage", + "trellis", + "cottage", + "thicket", + "orchard", + "bramble", + "haystack", + "snowfall", + "campfire", +]; + +/** RFC 4122-ish 4-character lowercase hex suffix using crypto.randomUUID. */ +function randomHexSuffix(): string { + if ( + typeof crypto !== "undefined" && + typeof crypto.randomUUID === "function" + ) { + return crypto.randomUUID().replace(/-/g, "").slice(0, 4); + } + // Older browser fallback. Math.random is fine here — this is a + // display suffix, not a security token. + return Math.floor(Math.random() * 0xffff) + .toString(16) + .padStart(4, "0"); +} + +/** + * Returns a single English-word name with a short random hex suffix. + * + * Example output: "kestrel-3f9c", "harbor-a012". + * + * The suffix keeps containers visually distinguishable in the picker + * when the same word recurs across creations. + */ +export function pickFriendlyContainerName(): string { + const word = WORDS[Math.floor(Math.random() * WORDS.length)] ?? "container"; + return `${word}-${randomHexSuffix()}`; +}