import { AlertTriangleIcon, CpuIcon, Loader2Icon, RotateCcwIcon, SparklesIcon, } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { apiFetch } from "../hooks/use-api"; import { CollectionEgressCheckPanel } from "./CollectionEgressCheckPanel"; import { CollectionEgressPolicyEditor, type CollectionEgressPolicy, } from "./CollectionEgressPolicyEditor"; import { EgressAuditPanel } from "./EgressAuditPanel"; import { Button } from "./ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "./ui/dialog"; import { Input } from "./ui/input"; const MODEL_ROLES = ["embed", "rerank", "expand", "gen"] as const; type ModelRole = (typeof MODEL_ROLES)[number]; type ModelSource = "override" | "preset" | "default"; const ROLE_LABELS: Record = { embed: "Embedding", rerank: "Reranker", expand: "Query Expansion", gen: "Answer Model", }; const ROLE_NOTES: Record = { embed: "Drives vector search and embedding backlog for this collection.", rerank: "Scores candidate passages/documents after retrieval.", expand: "Generates lexical and semantic expansion variants for harder queries.", gen: "Used for collection-targeted answer generation flows.", }; export interface CollectionModelDetails { activePresetId?: string; chunkCount: number; documentCount: number; effectiveModels?: Record; include?: string[]; modelSources?: Record; models?: Partial>; name: string; path: string; pattern?: string; egressPolicy?: { schemaVersion: "1.0"; collection: string; configuredPolicy: "local_only" | "lan" | "remote" | null; effectivePolicy: "local_only" | "lan" | "remote"; source: "explicit" | "config_default"; revision: number; version: string; } | null; } interface UpdateCollectionResponse { collection: CollectionModelDetails; success: boolean; } interface CollectionModelDialogProps { availableCollections?: readonly string[]; collection: CollectionModelDetails | null; onOpenChange: (open: boolean) => void; onSaved: () => void; open: boolean; } function normalizeValue(value: string | undefined): string { return value?.trim() ?? ""; } const CODE_EMBED_RECOMMENDATION = "hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"; const CODE_PATH_HINTS = [ "/src", "/lib", "/app", "/apps", "/packages", "/server", "/services", ] as const; const CODE_EXT_HINTS = [ ".ts", ".tsx", ".js", ".jsx", ".go", ".rs", ".py", ".swift", ".c", ] as const; function collectionLooksCodeHeavy(collection: CollectionModelDetails): boolean { const path = collection.path.toLowerCase(); if ( CODE_PATH_HINTS.some( (hint) => path.endsWith(hint) || path.includes(`${hint}/`) ) ) { return true; } const includeValues = collection.include ?? []; if ( includeValues.some((value) => CODE_EXT_HINTS.some((ext) => value.includes(ext)) ) ) { return true; } const pattern = collection.pattern?.toLowerCase() ?? ""; return CODE_EXT_HINTS.some( (ext) => pattern.includes(ext) || pattern.includes(ext.replace(".", "")) ); } export function CollectionModelDialog({ availableCollections = [], collection, onOpenChange, onSaved, open, }: CollectionModelDialogProps) { const [draft, setDraft] = useState>({ embed: "", rerank: "", expand: "", gen: "", }); const [error, setError] = useState(null); const [saving, setSaving] = useState(false); const [policyDraft, setPolicyDraft] = useState("local_only"); const [relaxationConfirmed, setRelaxationConfirmed] = useState(false); const showCodeRecommendation = collection !== null && collectionLooksCodeHeavy(collection) && collection.effectiveModels?.embed !== CODE_EMBED_RECOMMENDATION; useEffect(() => { if (!open || !collection) { return; } setDraft({ embed: collection.models?.embed ?? "", rerank: collection.models?.rerank ?? "", expand: collection.models?.expand ?? "", gen: collection.models?.gen ?? "", }); setError(null); setSaving(false); setPolicyDraft(collection.egressPolicy?.effectivePolicy ?? "local_only"); setRelaxationConfirmed(false); }, [collection, open]); const patch = useMemo(() => { if (!collection) { return {}; } const nextPatch: Partial> = {}; for (const role of MODEL_ROLES) { const original = normalizeValue(collection.models?.[role]); const current = normalizeValue(draft[role]); if (original === current) { continue; } nextPatch[role] = current.length === 0 ? null : current; } return nextPatch; }, [collection, draft]); const originalPolicy = collection?.egressPolicy?.effectivePolicy ?? "local_only"; const policyChanged = policyDraft !== originalPolicy; const policyOrder = { local_only: 0, lan: 1, remote: 2 } as const; const policyRelaxed = policyChanged && policyOrder[policyDraft] > policyOrder[originalPolicy]; const hasChanges = Object.keys(patch).length > 0 || policyChanged; const embedChanged = Object.hasOwn(patch, "embed"); const handleSave = async () => { if (!collection || !hasChanges) { return; } setSaving(true); setError(null); if (policyChanged) { const state = collection.egressPolicy; const { error: policyError } = await apiFetch( `/api/collections/${encodeURIComponent(collection.name)}/egress-policy`, { method: "PUT", body: JSON.stringify({ policy: policyDraft, confirmation: policyRelaxed && state && relaxationConfirmed ? { collection: state.collection, currentPolicy: state.effectivePolicy, currentRevision: state.revision, targetPolicy: policyDraft, acknowledged: true, } : undefined, }), } ); if (policyError) { setSaving(false); setError(policyError); return; } } const requestError = Object.keys(patch).length > 0 ? ( await apiFetch( `/api/collections/${encodeURIComponent(collection.name)}`, { method: "PATCH", body: JSON.stringify({ models: patch }), } ) ).error : null; setSaving(false); if (requestError) { setError(requestError); return; } onSaved(); onOpenChange(false); }; return ( {/* Header */}
Collection models preset: {collection?.activePresetId ?? "unknown"}
{collection?.name ?? "Collection"} Override model roles for one collection without changing the active preset for the rest of the workspace.

Path

{collection?.path}

{/* Scrollable model roles */}
{ setPolicyDraft(policy); setRelaxationConfirmed(false); }} policy={policyDraft} relaxed={policyRelaxed} revision={collection?.egressPolicy?.revision ?? 0} source={collection?.egressPolicy?.source ?? "config_default"} /> {collection ? ( ) : null} {MODEL_ROLES.map((role) => { const source = collection?.modelSources?.[role] ?? "preset"; const effectiveValue = collection?.effectiveModels?.[role] ?? ""; const draftValue = draft[role]; const isOverride = source === "override"; return (
{/* Left: role info */}

{ROLE_LABELS[role]}

{ROLE_NOTES[role]}

{/* Right: controls */}
{/* Source + effective model */}
{isOverride ? "override" : "inherits"} effective

{effectiveValue}

{/* Code embed recommendation */} {role === "embed" && showCodeRecommendation ? ( ) : null} {/* Input + reset */}
setDraft((current) => ({ ...current, [role]: event.target.value, })) } placeholder="Leave empty to inherit from preset" value={draftValue} />
); })}
{/* Warnings */} {collection && embedChanged && collection.documentCount > 0 ? (

Re-index needed after save

{collection.documentCount} docs / {collection.chunkCount}{" "} chunks will need re-embedding for the new model.

) : null} {error ? (
{error}
) : null}
{/* Footer — always visible */}
); }