Move goose2 (#8516)

Signed-off-by: Jack Amadeo <jackamadeo@squareup.com>
Co-authored-by: block-open-source[bot] <201011344+block-open-source[bot]@users.noreply.github.com>
Co-authored-by: block-open-source[bot] <1159699+block-open-source[bot]@users.noreply.github.com>
Co-authored-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Matt Toohey <contact@matttoohey.com>
Co-authored-by: tulsi <tulsi@block.xyz>
Co-authored-by: morgmart <98432065+morgmart@users.noreply.github.com>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Nahiyan Khan <nahiyan.khan@gmail.com>
Co-authored-by: Lifei Zhou <lifei@squareup.com>
This commit is contained in:
Jack Amadeo
2026-04-14 10:39:30 -04:00
committed by GitHub
parent 17a404d4f9
commit 482f1962c1
503 changed files with 89093 additions and 105 deletions
@@ -1,5 +1,14 @@
import { useState, useCallback, useRef } from 'react';
import { Search, Download, ChevronDown, ChevronUp, Loader2, Star, Check, AlertTriangle } from 'lucide-react';
import {
Search,
Download,
ChevronDown,
ChevronUp,
Loader2,
Star,
Check,
AlertTriangle,
} from 'lucide-react';
import { Button } from '../../ui/button';
import {
searchHfModels,
@@ -90,7 +99,11 @@ interface Props {
downloadedModelIds?: Set<string>;
}
export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, downloadedModelIds }: Props) => {
export const HuggingFaceModelSearch = ({
onDownloadStarted,
activeDownloadIds,
downloadedModelIds,
}: Props) => {
const intl = useIntl();
const [query, setQuery] = useState('');
const [results, setResults] = useState<HfModelInfo[]>([]);
@@ -102,71 +115,79 @@ export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, d
const [error, setError] = useState<string | null>(null);
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const doSearch = useCallback(async (q: string) => {
if (!q.trim()) {
setResults([]);
setError(null);
return;
}
setSearching(true);
setError(null);
try {
const response = await searchHfModels({
query: { q, limit: 20 },
});
if (response.data) {
// Pre-fetch variants for all results and filter out repos with no suitable quantizations
const modelsWithVariants = await Promise.all(
response.data.map(async (model) => {
try {
const [author, repo] = model.repo_id.split('/');
const filesResponse = await getRepoFiles({ path: { author, repo } });
if (filesResponse.data && filesResponse.data.variants.length > 0) {
return { model, data: filesResponse.data };
}
} catch {
// Skip repos we can't fetch
}
return null;
})
);
const validResults = modelsWithVariants.filter(Boolean) as {
model: HfModelInfo;
data: { variants: HfQuantVariant[]; recommended_index?: number | null; available_memory_bytes: number; downloaded_quants: string[] };
}[];
setResults(validResults.map((r) => r.model));
setRepoData((prev) => {
const next = { ...prev };
for (const r of validResults) {
next[r.model.repo_id] = {
variants: r.data.variants,
recommendedIndex: r.data.recommended_index ?? null,
availableMemoryBytes: r.data.available_memory_bytes,
downloadedQuants: new Set(r.data.downloaded_quants),
};
}
return next;
});
if (validResults.length === 0) {
setError(intl.formatMessage(i18n.noGgufModels));
}
} else {
console.error('Search response:', response);
const errMsg = response.error
? intl.formatMessage(i18n.searchError, { details: JSON.stringify(response.error) })
: intl.formatMessage(i18n.searchNoData);
setError(errMsg);
const doSearch = useCallback(
async (q: string) => {
if (!q.trim()) {
setResults([]);
setError(null);
return;
}
} catch (e) {
console.error('Search failed:', e);
setError(intl.formatMessage(i18n.searchFailed));
} finally {
setSearching(false);
}
}, [intl]);
setSearching(true);
setError(null);
try {
const response = await searchHfModels({
query: { q, limit: 20 },
});
if (response.data) {
// Pre-fetch variants for all results and filter out repos with no suitable quantizations
const modelsWithVariants = await Promise.all(
response.data.map(async (model) => {
try {
const [author, repo] = model.repo_id.split('/');
const filesResponse = await getRepoFiles({ path: { author, repo } });
if (filesResponse.data && filesResponse.data.variants.length > 0) {
return { model, data: filesResponse.data };
}
} catch {
// Skip repos we can't fetch
}
return null;
})
);
const validResults = modelsWithVariants.filter(Boolean) as {
model: HfModelInfo;
data: {
variants: HfQuantVariant[];
recommended_index?: number | null;
available_memory_bytes: number;
downloaded_quants: string[];
};
}[];
setResults(validResults.map((r) => r.model));
setRepoData((prev) => {
const next = { ...prev };
for (const r of validResults) {
next[r.model.repo_id] = {
variants: r.data.variants,
recommendedIndex: r.data.recommended_index ?? null,
availableMemoryBytes: r.data.available_memory_bytes,
downloadedQuants: new Set(r.data.downloaded_quants),
};
}
return next;
});
if (validResults.length === 0) {
setError(intl.formatMessage(i18n.noGgufModels));
}
} else {
console.error('Search response:', response);
const errMsg = response.error
? intl.formatMessage(i18n.searchError, { details: JSON.stringify(response.error) })
: intl.formatMessage(i18n.searchNoData);
setError(errMsg);
}
} catch (e) {
console.error('Search failed:', e);
setError(intl.formatMessage(i18n.searchFailed));
} finally {
setSearching(false);
}
},
[intl]
);
const handleQueryChange = (value: string) => {
setQuery(value);
@@ -235,7 +256,9 @@ export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, d
return (
<div className="space-y-4">
<div>
<h4 className="text-sm font-medium text-text-default mb-2">{intl.formatMessage(i18n.searchHuggingFace)}</h4>
<h4 className="text-sm font-medium text-text-default mb-2">
{intl.formatMessage(i18n.searchHuggingFace)}
</h4>
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-text-muted" />
<input
@@ -305,7 +328,8 @@ export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, d
const isDownloaded = downloadedModelIds
? downloadedModelIds.has(modelId)
: downloadedQuants.has(variant.quantization);
const tooLarge = availableMemory > 0 && variant.size_bytes > availableMemory * 0.85;
const tooLarge =
availableMemory > 0 && variant.size_bytes > availableMemory * 0.85;
return (
<div
@@ -347,22 +371,12 @@ export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, d
)}
</div>
{isDownloaded ? (
<Button
variant="outline"
size="sm"
disabled
className="opacity-60"
>
<Button variant="outline" size="sm" disabled className="opacity-60">
<Check className="w-3 h-3 mr-1" />
{intl.formatMessage(i18n.downloaded)}
</Button>
) : isActiveDownload ? (
<Button
variant="outline"
size="sm"
disabled
className="opacity-60"
>
<Button variant="outline" size="sm" disabled className="opacity-60">
<Loader2 className="w-3 h-3 mr-1 animate-spin" />
{intl.formatMessage(i18n.downloading)}
</Button>
@@ -393,7 +407,6 @@ export const HuggingFaceModelSearch = ({ onDownloadStarted, activeDownloadIds, d
})}
</div>
)}
</div>
);
};
@@ -97,7 +97,13 @@ const i18n = defineMessages({
},
});
const VisionBadge = ({ model, intl }: { model: LocalModelResponse; intl: ReturnType<typeof useIntl> }) => {
const VisionBadge = ({
model,
intl,
}: {
model: LocalModelResponse;
intl: ReturnType<typeof useIntl>;
}) => {
if (!model.vision_capable) return null;
const mmproj = model.mmproj_status;
@@ -114,9 +120,8 @@ const VisionBadge = ({ model, intl }: { model: LocalModelResponse; intl: ReturnT
}
if (isDownloading) {
const percent = mmproj && 'progress_percent' in mmproj
? Math.round(mmproj.progress_percent)
: null;
const percent =
mmproj && 'progress_percent' in mmproj ? Math.round(mmproj.progress_percent) : null;
return (
<span className="inline-flex items-center gap-1 text-xs text-yellow-400 bg-yellow-500/10 px-2 py-0.5 rounded">
<Eye className="w-3 h-3" />
@@ -324,7 +329,9 @@ export const LocalInferenceSettings = () => {
{/* Active Downloads */}
{downloads.size > 0 && (
<div ref={downloadSectionRef}>
<h4 className="text-sm font-medium text-text-default mb-2">{intl.formatMessage(i18n.downloading)}</h4>
<h4 className="text-sm font-medium text-text-default mb-2">
{intl.formatMessage(i18n.downloading)}
</h4>
<div className="space-y-2">
{Array.from(downloads.entries()).map(([modelId, progress]) => {
if (progress.status === 'completed') return null;
@@ -397,7 +404,9 @@ export const LocalInferenceSettings = () => {
{/* Downloaded Models */}
{downloadedModels.length > 0 && (
<div>
<h4 className="text-sm font-medium text-text-default mb-2">{intl.formatMessage(i18n.downloadedModels)}</h4>
<h4 className="text-sm font-medium text-text-default mb-2">
{intl.formatMessage(i18n.downloadedModels)}
</h4>
<div className="space-y-2">
{downloadedModels.map((model) => {
const isSelected = selectedModelId === model.id;
@@ -458,7 +467,9 @@ export const LocalInferenceSettings = () => {
{/* Featured Models (not yet downloaded) */}
{displayedFeatured.length > 0 && (
<div>
<h4 className="text-sm font-medium text-text-default mb-2">{intl.formatMessage(i18n.featuredModels)}</h4>
<h4 className="text-sm font-medium text-text-default mb-2">
{intl.formatMessage(i18n.featuredModels)}
</h4>
<div className="space-y-2">
{displayedFeatured.map((model) => (
<div
@@ -523,12 +534,16 @@ export const LocalInferenceSettings = () => {
<HuggingFaceModelSearch
onDownloadStarted={handleHfDownloadStarted}
activeDownloadIds={new Set(downloads.keys())}
downloadedModelIds={new Set(models.filter(m => m.status.state === 'Downloaded').map(m => m.id))}
downloadedModelIds={
new Set(models.filter((m) => m.status.state === 'Downloaded').map((m) => m.id))
}
/>
</div>
{models.length === 0 && (
<div className="text-center py-6 text-text-muted text-sm">{intl.formatMessage(i18n.noModels)}</div>
<div className="text-center py-6 text-text-muted text-sm">
{intl.formatMessage(i18n.noModels)}
</div>
)}
<Dialog