mirror of
https://github.com/unslothai/unsloth.git
synced 2026-10-23 23:11:17 +00:00
Merge remote-tracking branch 'origin/main' into studio-ssm-on-demand-followups
This commit is contained in:
commit
4a6429a654
3 changed files with 77 additions and 25 deletions
|
|
@ -1 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g clip-path="url(#prefix__clip0_8_13)"><path fill-rule="evenodd" clip-rule="evenodd" d="M358.485 41.75l154.027 87.573v1.856l-155.605 86.634.362-45.162-17.514-.64c-22.592-.598-34.368.042-48.384 2.346-22.699 3.734-43.478 12.31-67.136 28.843l-46.208 32.107c-6.059 4.16-10.56 7.168-14.507 9.706l-10.987 6.87-8.469 4.992 8.213 4.906 11.307 7.211c10.155 6.699 24.96 16.981 57.621 39.808 23.68 16.533 44.438 25.109 67.136 28.843l6.4.96c14.806 1.941 29.334 2.005 60.267.704l.469-46.059 154.027 87.573v1.856l-155.605 86.656.298-39.722-13.546.469c-29.568.896-45.59.043-66.944-3.456-36.139-5.973-69.547-19.755-104.128-43.925l-46.038-32a467.072 467.072 0 00-16.106-10.624l-9.963-5.974c-5.38-3.1-10.785-6.157-16.213-9.173C62.037 314.24 12.01 301.141 0 301.141v-90.197l2.987.085c12.032-.149 62.08-13.269 81.258-23.978l21.675-12.374 9.344-5.845c9.131-5.973 22.869-15.488 57.301-39.531 34.582-24.17 67.968-37.973 104.128-43.925 24.576-4.053 42.112-4.544 81.366-2.944l.426-40.683z" fill="#000"/></g><defs><clipPath id="prefix__clip0_8_13"><path fill="#fff" d="M0 0h512v512H0z"/></clipPath></defs></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path fill="#C6FF00" fill-rule="evenodd" d="M226 555A226 226 0 0 1 226 103H497A136 136 0 0 1 497 375L631.7 509.8A26.5 26.5 0 0 1 613 555ZM226 193A136 136 0 1 0 226 465A136 136 0 1 0 226 193Z"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 262 B |
|
|
@ -20,7 +20,9 @@ interface ApiProviderLogoProps {
|
|||
title?: string;
|
||||
}
|
||||
|
||||
const DARK_INVERT_LOGOS = new Set(["openai", "openai_codex", "ollama", "openrouter", "liquid", "typesafe"]);
|
||||
const DARK_INVERT_LOGOS = new Set(["openai", "openai_codex", "ollama", "liquid", "typesafe"]);
|
||||
// Pale brand marks get a hairline edge on light surfaces instead of inverting.
|
||||
const LIGHT_OUTLINE_LOGOS = new Set(["openrouter"]);
|
||||
|
||||
/** Shared hub or connection logo; monochrome ones invert in dark mode. */
|
||||
export function ApiProviderLogo({ providerType, className, title }: ApiProviderLogoProps) {
|
||||
|
|
@ -43,6 +45,9 @@ export function ApiProviderLogo({ providerType, className, title }: ApiProviderL
|
|||
className={cn(
|
||||
"shrink-0 object-contain",
|
||||
providerType && DARK_INVERT_LOGOS.has(providerType) && "dark:invert",
|
||||
providerType &&
|
||||
LIGHT_OUTLINE_LOGOS.has(providerType) &&
|
||||
"drop-shadow-[0_0_0.5px_rgb(0_0_0/0.7)] dark:drop-shadow-none",
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -109,6 +109,25 @@ const CUSTOM_PROVIDER_MISSING_KEY_MESSAGE =
|
|||
"No API key found. Add a valid API key for this connection.";
|
||||
const HIDDEN_PROVIDER_TYPES = new Set(["qwen"]);
|
||||
|
||||
// Ends the open provider menu just above this item so the rows from it on need a scroll.
|
||||
function capProviderMenuAtItem(item: HTMLElement | null) {
|
||||
const content = item?.closest<HTMLElement>("[data-slot=select-content]");
|
||||
if (!item || !content) return;
|
||||
// offsetTop chain, not getBoundingClientRect: the open animation scales the menu.
|
||||
let top = 0;
|
||||
for (
|
||||
let node: HTMLElement | null = item;
|
||||
node && node !== content;
|
||||
node = node.offsetParent as HTMLElement | null
|
||||
) {
|
||||
top += node.offsetTop;
|
||||
}
|
||||
const viewport = item.closest<HTMLElement>("[data-radix-select-viewport]");
|
||||
top -= viewport?.scrollTop ?? 0;
|
||||
top += Number.parseFloat(getComputedStyle(content).paddingBottom) || 0;
|
||||
content.style.maxHeight = `min(var(--radix-select-content-available-height), ${top}px)`;
|
||||
}
|
||||
|
||||
function parseManualModelIds(text: string): string[] {
|
||||
const seen = new Set<string>();
|
||||
const out: string[] = [];
|
||||
|
|
@ -341,6 +360,21 @@ export function ChatProvidersSettings({
|
|||
() => new Map(registry.map((entry) => [entry.provider_type, entry])),
|
||||
[registry],
|
||||
);
|
||||
// Decision-only connections (TypeSafe, Liquid AI) sit last, below the menu's fold.
|
||||
const menuRegistry = useMemo(() => {
|
||||
const visible = registry.filter(
|
||||
(entry) => !HIDDEN_PROVIDER_TYPES.has(entry.provider_type),
|
||||
);
|
||||
const isDecision = (entry: ProviderRegistryEntry) =>
|
||||
isDecisionConnection({ providerType: entry.provider_type });
|
||||
return [
|
||||
...visible.filter((entry) => !isDecision(entry)),
|
||||
...visible.filter(isDecision),
|
||||
];
|
||||
}, [registry]);
|
||||
const firstBelowFoldProviderType = menuRegistry.find((entry) =>
|
||||
isDecisionConnection({ providerType: entry.provider_type }),
|
||||
)?.provider_type;
|
||||
const selectedProviderContract = registryByType.get(
|
||||
toExternalBackendProviderType(providerType),
|
||||
);
|
||||
|
|
@ -381,10 +415,19 @@ export function ChatProvidersSettings({
|
|||
availableModels.length > 0;
|
||||
const missingModelCatalogBaseUrl =
|
||||
supportsRemoteModelCatalog(providerType) && baseUrlDraft.trim().length === 0;
|
||||
const editingProviderHasSavedKey = Boolean(
|
||||
editingProviderId &&
|
||||
providers.find((provider) => provider.id === editingProviderId)?.hasApiKey,
|
||||
);
|
||||
const editingProvider = editingProviderId
|
||||
? providers.find((provider) => provider.id === editingProviderId)
|
||||
: undefined;
|
||||
const editingProviderHasSavedKey = Boolean(editingProvider?.hasApiKey);
|
||||
const selectedProviderLabel = isCustomProviderType(providerType)
|
||||
? customProviderDisplayName(providerType)
|
||||
: selectedProviderContract?.display_name;
|
||||
// A saved connection reads as its name; only an unsaved draft is "New".
|
||||
const formTitle = editingProviderId
|
||||
? editingProvider?.name || selectedProviderLabel || "Edit"
|
||||
: selectedProviderLabel
|
||||
? `New ${selectedProviderLabel}`
|
||||
: "New";
|
||||
const missingModelCatalogApiKey =
|
||||
!isCustomProvider &&
|
||||
!isCuratedModelList &&
|
||||
|
|
@ -1467,8 +1510,11 @@ export function ChatProvidersSettings({
|
|||
Connections
|
||||
</span>
|
||||
<span className="size-1 rounded-full bg-muted-foreground/35" />
|
||||
<span className="truncate text-xs font-medium text-muted-foreground">
|
||||
{editingProviderId ? "Edit" : "New"}
|
||||
<span
|
||||
className="truncate text-xs font-medium text-muted-foreground"
|
||||
title={formTitle}
|
||||
>
|
||||
{formTitle}
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -1510,8 +1556,19 @@ export function ChatProvidersSettings({
|
|||
>
|
||||
<SelectValue placeholder="Choose a connection" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{/* No scroll chevrons: the list scrolls by wheel, trackpad and keyboard. */}
|
||||
<SelectContent className="[&_[data-slot=select-scroll-down-button]]:hidden [&_[data-slot=select-scroll-up-button]]:hidden">
|
||||
<SelectGroup>
|
||||
<SelectItem value={LEGACY_CUSTOM_PROVIDER_TYPE}>
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<ApiProviderLogo
|
||||
providerType={LEGACY_CUSTOM_PROVIDER_TYPE}
|
||||
className="size-4"
|
||||
title={CUSTOM_PROVIDER_DISPLAY_NAME}
|
||||
/>
|
||||
<span className="truncate">{CUSTOM_PROVIDER_DISPLAY_NAME}</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
{CUSTOM_PROVIDER_PRESETS.map((preset) => (
|
||||
<SelectItem
|
||||
key={preset.providerType}
|
||||
|
|
@ -1527,28 +1584,18 @@ export function ChatProvidersSettings({
|
|||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectItem value={LEGACY_CUSTOM_PROVIDER_TYPE}>
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<ApiProviderLogo
|
||||
providerType={LEGACY_CUSTOM_PROVIDER_TYPE}
|
||||
className="size-4"
|
||||
title={CUSTOM_PROVIDER_DISPLAY_NAME}
|
||||
/>
|
||||
<span className="truncate">{CUSTOM_PROVIDER_DISPLAY_NAME}</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<SelectGroup>
|
||||
{registry
|
||||
.filter(
|
||||
(entry) =>
|
||||
!HIDDEN_PROVIDER_TYPES.has(entry.provider_type),
|
||||
)
|
||||
.map((entry) => (
|
||||
{menuRegistry.map((entry) => (
|
||||
<SelectItem
|
||||
key={entry.provider_type}
|
||||
value={entry.provider_type}
|
||||
ref={
|
||||
entry.provider_type === firstBelowFoldProviderType
|
||||
? capProviderMenuAtItem
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<ApiProviderLogo
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue