Skip to content

Shared Config for non-YAML config options #3839

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

Merged
merged 20 commits into from
Jan 31, 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
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export class StreamTransformPipeline {
const timeoutValue = await Telemetry.getValueForFeatureFlag(
PosthogFeatureFlag.AutocompleteTimeout,
);
// helper.options.showWhateverWeHaveAtXMs ?? DEFAULT_AUTOCOMPLETE_OPTS.showWhateverWeHaveAtXMs

lineGenerator = showWhateverWeHaveAtXMs(lineGenerator, timeoutValue!);

Expand Down
34 changes: 17 additions & 17 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,14 @@ import {
defaultSlashCommandsVscode,
} from "./default";
import { getSystemPromptDotFile } from "./getSystemPromptDotFile";
// import { isSupportedLanceDbCpuTarget } from "./util";
import { useHub } from "../control-plane/env";
import { localPathToUri } from "../util/pathToUri";
import { modifyContinueConfigWithSharedConfig } from "./sharedConfig";
import { validateConfig } from "./validation.js";

function resolveSerializedConfig(filepath: string): SerializedContinueConfig {
export function resolveSerializedConfig(
filepath: string,
): SerializedContinueConfig {
let content = fs.readFileSync(filepath, "utf8");
const config = JSONC.parse(content) as unknown as SerializedContinueConfig;
if (config.env && Array.isArray(config.env)) {
Expand Down Expand Up @@ -111,11 +113,10 @@ function loadSerializedConfig(
overrideConfigJson: SerializedContinueConfig | undefined,
ide: IDE,
): ConfigResult<SerializedContinueConfig> {
const configPath = getConfigJsonPath(ideType);
let config: SerializedContinueConfig = overrideConfigJson!;
if (!config) {
try {
config = resolveSerializedConfig(configPath);
config = resolveSerializedConfig(getConfigJsonPath(ideType));
} catch (e) {
throw new Error(`Failed to parse config.json: ${e}`);
}
Expand All @@ -135,16 +136,6 @@ function loadSerializedConfig(
config.allowAnonymousTelemetry = true;
}

// Deprecated getChatTitles property should be accounted for
// This is noted in docs
if (
config.ui &&
"getChatTitles" in config.ui &&
config.ui.getChatTitles === false
) {
config.disableSessionTitles = true;
}

if (ideSettings.remoteConfigServerUrl) {
try {
const remoteConfigJson = resolveSerializedConfig(
Expand Down Expand Up @@ -583,6 +574,7 @@ async function finalToBrowserConfig(
experimental: final.experimental,
docs: final.docs,
tools: final.tools,
tabAutocompleteOptions: final.tabAutocompleteOptions,
usePlatform: await useHub(ide.getIdeSettings()),
};
}
Expand Down Expand Up @@ -767,7 +759,7 @@ async function buildConfigTsandReadConfigJs(ide: IDE, ideType: IdeType) {
return readConfigJs();
}

async function loadFullConfigNode(
async function loadContinueConfigFromJson(
ide: IDE,
workspaceConfigs: ContinueRcJson[],
ideSettings: IdeSettings,
Expand Down Expand Up @@ -799,8 +791,16 @@ async function loadFullConfigNode(
serialized.systemMessage = systemPromptDotFile;
}

// Apply shared config
// TODO: override several of these values with user/org shared config
const sharedConfig = new GlobalContext().getSharedConfig();
const withShared = modifyContinueConfigWithSharedConfig(
serialized,
sharedConfig,
);

// Convert serialized to intermediate config
let intermediate = await serializedToIntermediateConfig(serialized, ide);
let intermediate = await serializedToIntermediateConfig(withShared, ide);

// Apply config.ts to modify intermediate config
const configJsContents = await buildConfigTsandReadConfigJs(ide, ideType);
Expand Down Expand Up @@ -877,6 +877,6 @@ async function loadFullConfigNode(
export {
finalToBrowserConfig,
intermediateToFinalConfig,
loadFullConfigNode,
loadContinueConfigFromJson,
type BrowserSerializedContinueConfig,
};
212 changes: 212 additions & 0 deletions core/config/migrateSharedConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import * as fs from "fs";

import * as JSONC from "comment-json";

import { IDE, SerializedContinueConfig } from "..";
import { SharedConfigSchema } from "./sharedConfig";
import { GlobalContext } from "../util/GlobalContext";
import { editConfigJson } from "../util/paths";
import { resolveSerializedConfig } from "./load";
import { deduplicateArray } from "../util";

/*
This migration function eliminates deprecated values from the json file
And writes them to the shared config
*/
export function migrateJsonSharedConfig(filepath: string, ide: IDE): void {
const globalContext = new GlobalContext();
const currentSharedConfig = globalContext.getSharedConfig(); // for merging security concerns

try {
let config = resolveSerializedConfig(filepath);
const shareConfigUpdates: SharedConfigSchema = {};

let effected = false;

const { allowAnonymousTelemetry, ...withoutAllowTelemetry } = config;
if (allowAnonymousTelemetry !== undefined) {
if (currentSharedConfig.allowAnonymousTelemetry !== false) {
// safe merge for security
shareConfigUpdates.allowAnonymousTelemetry = allowAnonymousTelemetry;
}
config = withoutAllowTelemetry;
effected = true;
}

const { disableIndexing, ...withoutDisableIndexing } = config;
if (disableIndexing !== undefined) {
if (currentSharedConfig.disableIndexing !== true) {
// safe merge for security
shareConfigUpdates.disableIndexing = disableIndexing;
}
config = withoutDisableIndexing;
effected = true;
}

const { disableSessionTitles, ...withoutDisableSessionTitles } = config;
if (config.disableSessionTitles !== undefined) {
if (currentSharedConfig.disableSessionTitles !== true) {
// safe merge for security
shareConfigUpdates.disableSessionTitles = config.disableSessionTitles;
}
config = withoutDisableSessionTitles;
effected = true;
}

const { tabAutocompleteOptions, ...withoutAutocompleteOptions } = config;
if (tabAutocompleteOptions !== undefined) {
let migratedAutocomplete = { ...tabAutocompleteOptions };

const { useCache, ...withoutUseCache } = migratedAutocomplete;
if (useCache !== undefined) {
shareConfigUpdates.useAutocompleteCache = useCache;
migratedAutocomplete = withoutUseCache;
effected = true;
}

const { multilineCompletions, ...withoutMultiline } =
migratedAutocomplete;
if (multilineCompletions !== undefined) {
shareConfigUpdates.useAutocompleteMultilineCompletions =
multilineCompletions;
migratedAutocomplete = withoutMultiline;
effected = true;
}

const { disableInFiles, ...withoutDisableInFiles } = migratedAutocomplete;
if (disableInFiles !== undefined) {
if (currentSharedConfig.disableAutocompleteInFiles !== undefined) {
// safe merge for security
shareConfigUpdates.disableAutocompleteInFiles = deduplicateArray(
[
...currentSharedConfig.disableAutocompleteInFiles,
...disableInFiles,
],
(a, b) => a === b,
);
} else {
shareConfigUpdates.disableAutocompleteInFiles = disableInFiles;
}
shareConfigUpdates.disableAutocompleteInFiles = disableInFiles;
migratedAutocomplete = withoutDisableInFiles;
effected = true;
}

if (Object.keys(migratedAutocomplete).length > 0) {
config = {
...withoutAutocompleteOptions,
tabAutocompleteOptions: migratedAutocomplete,
};
} else {
config = withoutAutocompleteOptions;
}
}

const { experimental, ...withoutExperimental } = config;
if (experimental !== undefined) {
let migratedExperimental = { ...experimental };

const { useChromiumForDocsCrawling, ...rest10 } = migratedExperimental;
if (useChromiumForDocsCrawling !== undefined) {
shareConfigUpdates.useChromiumForDocsCrawling =
useChromiumForDocsCrawling;
migratedExperimental = rest10;
effected = true;
}

const { promptPath, ...withoutPromptPath } = migratedExperimental;
if (promptPath !== undefined) {
shareConfigUpdates.promptPath = promptPath;
migratedExperimental = withoutPromptPath;
effected = true;
}

const { readResponseTTS, ...withoutReadTTS } = migratedExperimental;
if (readResponseTTS !== undefined) {
shareConfigUpdates.readResponseTTS = readResponseTTS;
migratedExperimental = withoutReadTTS;
effected = true;
}

if (Object.keys(migratedExperimental).length > 0) {
config = {
...withoutExperimental,
experimental: migratedExperimental,
};
} else {
config = withoutExperimental;
}
}

const { ui, ...withoutUI } = config;
if (ui !== undefined) {
let migratedUI = { ...ui };

const { codeBlockToolbarPosition, ...withoutToolbarPosition } =
migratedUI;
if (codeBlockToolbarPosition !== undefined) {
shareConfigUpdates.codeBlockToolbarPosition = codeBlockToolbarPosition;
migratedUI = withoutToolbarPosition;
effected = true;
}

const { fontSize, ...withoutFontSize } = migratedUI;
if (fontSize !== undefined) {
shareConfigUpdates.fontSize = fontSize;
migratedUI = withoutFontSize;
effected = true;
}

const { codeWrap, ...withoutCodeWrap } = migratedUI;
if (codeWrap !== undefined) {
shareConfigUpdates.codeWrap = codeWrap;
migratedUI = withoutCodeWrap;
effected = true;
}

const { displayRawMarkdown, ...withoutMD } = migratedUI;
if (displayRawMarkdown !== undefined) {
shareConfigUpdates.displayRawMarkdown = displayRawMarkdown;
migratedUI = withoutMD;
effected = true;
}

const { showChatScrollbar, ...withoutShowChatScrollbar } = migratedUI;
if (showChatScrollbar !== undefined) {
shareConfigUpdates.showChatScrollbar = showChatScrollbar;
migratedUI = withoutShowChatScrollbar;
effected = true;
}

// Ancient param to overwrite disableSessionTitles
if ("getChatTitles" in migratedUI) {
const { getChatTitles, ...withoutChatTitles } = migratedUI;
if (getChatTitles === false) {
shareConfigUpdates.disableSessionTitles = true;
migratedUI = withoutChatTitles;
effected = true;
}
}

if (Object.keys(migratedUI).length > 0) {
config = {
...withoutUI,
ui: migratedUI,
};
} else {
config = withoutUI;
}
}

if (effected) {
new GlobalContext().updateSharedConfig(shareConfigUpdates);
editConfigJson(() => config);
void ide.showToast(
"warning",
"Migrated deprecated Continue JSON settings. Edit in the Settings Page",
);
}
} catch (e) {
throw new Error(`Migration: Failed to parse config.json: ${e}`);
}
}
16 changes: 12 additions & 4 deletions core/config/profile/doLoadConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import { ControlPlaneClient } from "../../control-plane/client.js";
import { getControlPlaneEnv } from "../../control-plane/env.js";
import { TeamAnalytics } from "../../control-plane/TeamAnalytics.js";
import ContinueProxy from "../../llm/llms/stubs/ContinueProxy";
import { getConfigYamlPath } from "../../util/paths";
import { getConfigJsonPath, getConfigYamlPath } from "../../util/paths";
import { Telemetry } from "../../util/posthog";
import { TTS } from "../../util/tts";
import { loadFullConfigNode } from "../load";
import { loadContinueConfigFromJson } from "../load";
import { loadContinueConfigFromYaml } from "../yaml/loadYaml";
import { PlatformConfigMetadata } from "./PlatformProfileLoader";
import { migrateJsonSharedConfig } from "../migrateSharedConfig";

export default async function doLoadConfig(
ide: IDE,
Expand All @@ -40,13 +41,20 @@ export default async function doLoadConfig(
const ideSettings = await ideSettingsPromise;
const workOsAccessToken = await controlPlaneClient.getAccessToken();

// Migrations for old config files
// Removes
const configJsonPath = getConfigJsonPath(ideInfo.ideType);
if (fs.existsSync(configJsonPath)) {
migrateJsonSharedConfig(configJsonPath, ide);
}

const configYamlPath = getConfigYamlPath(ideInfo.ideType);

let newConfig: ContinueConfig | undefined;
let errors: ConfigValidationError[] | undefined;
let configLoadInterrupted = false;

if (fs.existsSync(configYamlPath) || overrideConfigYaml) {
if (overrideConfigYaml || fs.existsSync(configYamlPath)) {
const result = await loadContinueConfigFromYaml(
ide,
workspaceConfigs.map((c) => JSON.stringify(c)),
Expand All @@ -63,7 +71,7 @@ export default async function doLoadConfig(
errors = result.errors;
configLoadInterrupted = result.configLoadInterrupted;
} else {
const result = await loadFullConfigNode(
const result = await loadContinueConfigFromJson(
ide,
workspaceConfigs,
ideSettings,
Expand Down
Loading
Loading