Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: disable indexing for unsupported CPUs #3551

Merged
merged 5 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import CustomLLMClass from "../llm/llms/CustomLLM";
import FreeTrial from "../llm/llms/FreeTrial";
import { LLMReranker } from "../llm/llms/llm";
import TransformersJsEmbeddingsProvider from "../llm/llms/TransformersJsEmbeddingsProvider";
import { slashCommandFromPromptFileV1 } from "../promptFiles/v1/slashCommandFromPromptFile";
import { getAllPromptFiles } from "../promptFiles/v2/getPromptFiles";
import { allTools } from "../tools";
import { copyOf } from "../util";
import { GlobalContext } from "../util/GlobalContext";
Expand All @@ -61,15 +63,14 @@ import {
getEsbuildBinaryPath,
} from "../util/paths";

import { slashCommandFromPromptFileV1 } from "../promptFiles/v1/slashCommandFromPromptFile";
import { getAllPromptFiles } from "../promptFiles/v2/getPromptFiles";
import {
defaultContextProvidersJetBrains,
defaultContextProvidersVsCode,
defaultSlashCommandsJetBrains,
defaultSlashCommandsVscode,
} from "./default";
import { getSystemPromptDotFile } from "./getSystemPromptDotFile";
import { isSupportedLanceDbCpuTarget } from "./util";
import { ConfigValidationError, validateConfig } from "./validation.js";

export interface ConfigResult<T> {
Expand Down Expand Up @@ -112,6 +113,7 @@ function loadSerializedConfig(
ideSettings: IdeSettings,
ideType: IdeType,
overrideConfigJson: SerializedContinueConfig | undefined,
ide: IDE,
): ConfigResult<SerializedContinueConfig> {
const configPath = getConfigJsonPath(ideType);
let config: SerializedContinueConfig = overrideConfigJson!;
Expand Down Expand Up @@ -174,6 +176,10 @@ function loadSerializedConfig(
? [...defaultSlashCommandsVscode]
: [...defaultSlashCommandsJetBrains];

if (!isSupportedLanceDbCpuTarget(ide)) {
config.disableIndexing = true;
}

return { config, errors, configLoadInterrupted: false };
}

Expand Down Expand Up @@ -767,6 +773,7 @@ async function loadFullConfigNode(
ideSettings,
ideType,
overrideConfigJson,
ide,
);

if (!serialized || configLoadInterrupted) {
Expand Down
86 changes: 86 additions & 0 deletions core/config/util.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { execSync } from "child_process";
import os from "os";

import {
ContextProviderWithParams,
ContinueConfig,
IDE,
ILLM,
ModelDescription,
ModelRoles,
} from "../";
import { GlobalContext } from "../util/GlobalContext";
import { editConfigJson } from "../util/paths";

function stringify(obj: any, indentation?: number): string {
Expand Down Expand Up @@ -96,3 +101,84 @@ export function getModelByRole<T extends keyof ModelRoles>(

return matchingModel;
}

/**
* This check is to determine if the user is on an unsupported CPU
* target for our Lance DB binaries.
*
* See here for details: https://github.com/continuedev/continue/issues/940
*/
export function isSupportedLanceDbCpuTarget(ide: IDE) {
const CPU_FEATURES_TO_CHECK = ["avx2", "fma"] as const;

const globalContext = new GlobalContext();
const globalContextVal = globalContext.get("isSupportedLanceDbCpuTarget");

// If we've already checked the CPU target, return the cached value
if (globalContextVal !== undefined) {
return globalContextVal;
}

const arch = os.arch();
const platform = os.platform();

// This check only applies to x64
//https://github.com/lancedb/lance/issues/2195#issuecomment-2057841311
if (arch !== "x64") {
globalContext.update("isSupportedLanceDbCpuTarget", true);
return true;
}

try {
const cpuFlags = (() => {
switch (platform) {
case "darwin":
return execSync("sysctl -n machdep.cpu.features")
.toString()
.toLowerCase();
case "linux":
return execSync("cat /proc/cpuinfo").toString().toLowerCase();
case "win32":
return execSync("wmic cpu get caption /format:list")
.toString()
.toLowerCase();
default:
return "";
}
})();

const isSupportedLanceDbCpuTarget = cpuFlags
? CPU_FEATURES_TO_CHECK.every((feature) => cpuFlags.includes(feature))
: true;

// If it's not a supported CPU target, and it's the first time we are checking,
// show a toast to inform the user that we are going to disable indexing.
if (!isSupportedLanceDbCpuTarget) {
// We offload our async toast to `showUnsupportedCpuToast` to prevent making
// our config loading async upstream of `isSupportedLanceDbCpuTarget`
void showUnsupportedCpuToast(ide);
}

globalContext.update(
"isSupportedLanceDbCpuTarget",
isSupportedLanceDbCpuTarget,
);

return isSupportedLanceDbCpuTarget;
} catch (error) {
// If we can't determine CPU features, default to true
return true;
}
}

async function showUnsupportedCpuToast(ide: IDE) {
const shouldOpenLink = await ide.showToast(
"warning",
"Codebase indexing is disabled due to CPU incompatibility",
"Learn more",
);

if (shouldOpenLink) {
void ide.openUrl("https://github.com/continuedev/continue/pull/3551");
}
}
1 change: 1 addition & 0 deletions core/util/GlobalContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type GlobalContextType = {
hasDismissedConfigTsNoticeJetBrains: boolean;
hasAlreadyCreatedAPromptFile: boolean;
showConfigUpdateToast: boolean;
isSupportedLanceDbCpuTarget: boolean;
};

/**
Expand Down
19 changes: 11 additions & 8 deletions gui/src/components/indexing/DocsIndexingStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ function DocsIndexingStatus({ docConfig }: IndexingStatusViewerProps) {
if (!status) {
return 0;
}
return Math.min(100, Math.max(0, status.progress * 100));
return Math.min(100, Math.max(0, status.progress * 100)).toFixed(0);
}, [status?.progress]);

const Icon = STATUS_TO_ICON[status?.status];
const showProgressPercentage = progressPercentage !== "100";

if (hasDeleted) return null;

Expand Down Expand Up @@ -116,20 +117,22 @@ function DocsIndexingStatus({ docConfig }: IndexingStatusViewerProps) {
<div className="text-xs text-stone-500">Pending...</div>
) : (
<div className="flex flex-row items-center gap-1 text-stone-500">
<span className="text-xs">{progressPercentage.toFixed(0)}%</span>
{showProgressPercentage && (
<span className="text-xs">{progressPercentage}%</span>
)}
{status?.status !== "indexing" ? (
<TrashIcon
className="h-4 w-4 cursor-pointer text-stone-500 hover:brightness-125"
onClick={onDelete}
/>
) : null}
{Icon ? (
<Icon
className={`inline-block h-4 w-4 text-stone-500 ${
status?.status === "indexing" ? "animate-spin-slow" : ""
}`}
></Icon>
) : null}
{status?.status !== "indexing" ? (
<TrashIcon
className="h-4 w-4 cursor-pointer text-stone-500"
onClick={onDelete}
/>
) : null}
</div>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions gui/src/components/indexing/DocsIndexingStatuses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ function DocsIndexingStatuses() {
return (
<div className="flex flex-col gap-1">
<div className="flex flex-row items-center justify-between">
<h3 className="mb-1 mt-0 text-xl">@docs indexes</h3>
<h3 className="mb-0 mt-0 text-xl">@docs indexes</h3>
{configDocs.length ? (
<SecondaryButton
className="flex h-7 flex-col items-center justify-center"
className="!my-0 flex h-7 flex-col items-center justify-center"
onClick={() => {
dispatch(setShowDialog(true));
dispatch(setDialogMessage(<AddDocsDialog />));
Expand Down
2 changes: 1 addition & 1 deletion gui/src/pages/More/IndexingProgress/IndexingProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function IndexingProgress() {
}

return (
<div className="mt-6 flex flex-col">
<div className="mt-4 flex flex-col">
<div className="mb-0 flex justify-between text-sm">
<IndexingProgressTitleText update={update} />
{update.status !== "loading" && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ const STATUS_TO_ICON: Record<IndexingProgressUpdate["status"], any> = {
};

function IndexingProgressIndicator({ update }: IndexingProgressIndicatorProps) {
const progressPercentage = getProgressPercentage(update.progress);
const progressPercentage = getProgressPercentage(update.progress).toFixed(0);
const Icon = STATUS_TO_ICON[update.status];
const animateIcon = update.status === "indexing";
const showProgress = update.status !== "disabled";
const showProgress =
update.status !== "disabled" && progressPercentage !== "100";

return (
<div className="flex items-center justify-between gap-1 text-stone-500">
{showProgress && (
<span className="text-xs">{progressPercentage.toFixed(0)}%</span>
)}
{showProgress && <span className="text-xs">{progressPercentage}%</span>}

{Icon && (
<div className="flex items-center">
Expand Down
14 changes: 12 additions & 2 deletions gui/src/pages/More/More.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ import MoreHelpRow from "./MoreHelpRow";
import IndexingProgress from "./IndexingProgress";
import DocsIndexingStatuses from "../../components/indexing/DocsIndexingStatuses";
import PageHeader from "../../components/PageHeader";
import { useAppDispatch } from "../../redux/hooks";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { saveCurrentSession } from "../../redux/thunks/session";

function MorePage() {
useNavigationListener();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const ideMessenger = useContext(IdeMessengerContext);
const disableIndexing = useAppSelector(
(state) => state.config.config.disableIndexing,
);

return (
<div className="overflow-y-scroll">
Expand All @@ -34,8 +37,15 @@ function MorePage() {
Local embeddings of your codebase
</span>
</div>
<IndexingProgress />
{disableIndexing ? (
<div className="pb-2 pt-5 text-center font-semibold">
Indexing is disabled
</div>
) : (
<IndexingProgress />
)}
</div>

<div className="flex flex-col py-5">
<DocsIndexingStatuses />
</div>
Expand Down
Loading