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

Nate/platform #3724

Merged
merged 50 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3c5c830
update config-yaml schema
sestinj Dec 30, 2024
0a3763a
load remote yaml from platform
sestinj Dec 30, 2024
00f1218
make ContinueProxy work with platform
sestinj Dec 31, 2024
87f94b3
export LLMConfig type
sestinj Jan 1, 2025
5caf3e6
fix autocomplete through platform
sestinj Jan 1, 2025
8915a53
fix chat extra body properties
sestinj Jan 2, 2025
fcdc63e
configJson to configYaml converter
sestinj Jan 6, 2025
af3e2f3
add docs to configYaml schema
sestinj Jan 6, 2025
b01a97e
useOnboarding in getControlPlaneSessionInfo
sestinj Jan 7, 2025
a57b5ef
platform onboarding card
sestinj Jan 7, 2025
3acffa4
assistants toggle
sestinj Jan 8, 2025
1ed8174
update launch.json
sestinj Jan 8, 2025
185f0c5
Merge branch 'main' into nate/platform
sestinj Jan 8, 2025
80f1c11
use thunks for cycling profile id
sestinj Jan 8, 2025
e700715
remove unnecessary continue for teams popup
sestinj Jan 9, 2025
4d638ee
return a promise from login()
sestinj Jan 10, 2025
0228b89
Merge branch 'main' into nate/platform
sestinj Jan 11, 2025
d629294
usePlatform flag based on ~/.continue/.use_platform
sestinj Jan 11, 2025
acefabd
make model/assistant selectors scrollable
sestinj Jan 11, 2025
f3c0bc3
hide overflow x in assistant select
sestinj Jan 11, 2025
c755c83
ellipsis in assistant selector
sestinj Jan 12, 2025
1b1167e
bump version
sestinj Jan 12, 2025
fd38706
no workspace-specific config.yaml
sestinj Jan 12, 2025
8e25d9c
update config.yaml
sestinj Jan 14, 2025
aa8de1a
better platform profile loading
sestinj Jan 14, 2025
558bbde
use_platform env
sestinj Jan 14, 2025
fe19e14
config.yaml loading fixes
sestinj Jan 14, 2025
8a204a4
Merge branch 'main' into nate/platform
sestinj Jan 14, 2025
37ea55f
update package.json
sestinj Jan 14, 2025
0e263cd
update package-lock
sestinj Jan 14, 2025
aadec12
update package-locks again
sestinj Jan 14, 2025
a5ff93e
update package-lock
sestinj Jan 14, 2025
4ee6059
update config-types and config-yaml
sestinj Jan 15, 2025
bcf6846
update imports
sestinj Jan 15, 2025
c959617
link warning button to platform package page
sestinj Jan 15, 2025
82bbbc5
tests for LLM classes
sestinj Jan 15, 2025
69185b3
run e2e tests a second time with config.yaml
sestinj Jan 15, 2025
d75a9f7
update import ordering
sestinj Jan 15, 2025
ef09279
matrix
sestinj Jan 15, 2025
0dc8f33
e2e test system message
sestinj Jan 15, 2025
2cc8b75
rules e2e test
sestinj Jan 15, 2025
256868e
tool call tests
sestinj Jan 16, 2025
bfa2d65
Merge branch 'main' into nate/platform
sestinj Jan 16, 2025
8c72887
fix o1 streaming in the other place too
sestinj Jan 16, 2025
65d4050
and there
sestinj Jan 16, 2025
65d3600
terminal context provider test
sestinj Jan 16, 2025
776ef9e
fix test
sestinj Jan 16, 2025
dc6ba67
address tests feedback
sestinj Jan 16, 2025
18824ef
fix failing test
sestinj Jan 16, 2025
6254d03
pass system message through to yaml models
sestinj Jan 16, 2025
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
28 changes: 16 additions & 12 deletions .github/workflows/pr_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

install-gui:
needs: [ install-root, install-core ]
needs: [install-root, install-core]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -157,7 +157,7 @@ jobs:
npx tsc --noEmit

binary-checks:
needs: [ install-root, install-core ]
needs: [install-root, install-core]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -193,7 +193,7 @@ jobs:
npx tsc --noEmit

install-vscode:
needs: [ install-root, install-core ]
needs: [install-root, install-core]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -274,10 +274,15 @@ jobs:
run: |
cd core
npm test
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}

vscode-get-test-file-matrix:
runs-on: ubuntu-latest
needs: [ install-root, install-vscode ]
needs: [install-root, install-vscode]
outputs:
test_file_matrix: ${{ steps.vscode-get-test-file-matrix.outputs.test_file_matrix }}
steps:
Expand Down Expand Up @@ -306,7 +311,7 @@ jobs:

vscode-package-extension:
runs-on: ubuntu-latest
needs: [ install-vscode, install-core ]
needs: [install-vscode, install-core]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down Expand Up @@ -338,7 +343,7 @@ jobs:

vscode-download-e2e-dependencies:
runs-on: ubuntu-latest
needs: [ install-vscode, install-core ]
needs: [install-vscode, install-core]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down Expand Up @@ -370,7 +375,7 @@ jobs:
path: extensions/vscode/e2e/storage

vscode-e2e-tests:
name: ${{ matrix.test_file }}"
name: ${{ matrix.test_file }} (${{ matrix.command }})
needs:
[
vscode-download-e2e-dependencies,
Expand All @@ -384,6 +389,7 @@ jobs:
fail-fast: false
matrix:
test_file: ${{ fromJson(needs.vscode-get-test-file-matrix.outputs.test_file_matrix) }}
command: ["e2e:ci:run", "e2e:ci:run-yaml"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down Expand Up @@ -432,7 +438,7 @@ jobs:
- name: Run e2e tests
run: |
cd extensions/vscode
TEST_FILE="${{ matrix.test_file }}" npm run e2e:ci:run
TEST_FILE="${{ matrix.test_file }}" npm run ${{ matrix.command }}

env:
DISPLAY: :99
Expand All @@ -445,7 +451,7 @@ jobs:
path: extensions/vscode/e2e/storage/screenshots

gui-tests:
needs: [ install-gui, install-core ]
needs: [install-gui, install-core]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -476,7 +482,7 @@ jobs:
npm test

jetbrains-tests:
needs: [ install-root, core-checks ]
needs: [install-root, core-checks]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -573,5 +579,3 @@ jobs:
name: jb-failure-report
path: |
${{ github.workspace }}/extensions/intellij/build/reports


2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
"outFiles": ["${workspaceFolder}/extensions/vscode/out/extension.js"],
"preLaunchTask": "vscode-extension:build",
"env": {
// "CONTROL_PLANE_ENV": "local",
"CONTINUE_GLOBAL_DIR": "${workspaceFolder}/extensions/.continue-debug"
// "staging" for the preview deployment "CONTINUE_GLOBAL_DIR": "${workspaceFolder}/extensions/.continue-debug"
// "local" for entirely local development of control plane/proxy
// "CONTROL_PLANE_ENV": "staging"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion binary/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/config/ConfigHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe.skip("Test the ConfigHandler and E2E config loading", () => {
expect(profiles[0].id).toBe("local");

const currentProfile = testConfigHandler.currentProfile;
expect(currentProfile.profileId).toBe("local");
expect(currentProfile.profileDescription.id).toBe("local");
});

test("should load the default config successfully", async () => {
Expand Down
99 changes: 80 additions & 19 deletions core/config/ConfigHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ import Ollama from "../llm/llms/Ollama.js";
import { GlobalContext } from "../util/GlobalContext.js";
import { getConfigJsonPath } from "../util/paths.js";

import { ConfigResult } from "./load.js";
import { ConfigResult } from "@continuedev/config-yaml";
import { pathToFileURL } from "url";
import { controlPlaneEnv } from "../control-plane/env.js";
import { usePlatform } from "../control-plane/flags.js";
import {
LOCAL_ONBOARDING_CHAT_MODEL,
ONBOARDING_LOCAL_MODEL_TITLE,
} from "./onboarding.js";
import ControlPlaneProfileLoader from "./profile/ControlPlaneProfileLoader.js";
import LocalProfileLoader from "./profile/LocalProfileLoader.js";
import PlatformProfileLoader from "./profile/PlatformProfileLoader.js";
import {
ProfileDescription,
ProfileLifecycleManager,
} from "./ProfileLifecycleManager.js";
import { pathToFileURL } from "url";

export type { ProfileDescription };

Expand Down Expand Up @@ -57,7 +60,7 @@ export class ConfigHandler {
writeLog,
);
this.profiles = [new ProfileLifecycleManager(localProfileLoader)];
this.selectedProfileId = localProfileLoader.profileId;
this.selectedProfileId = localProfileLoader.description.id;

// Always load local profile immediately in case control plane doesn't load
try {
Expand All @@ -77,39 +80,40 @@ export class ConfigHandler {

get currentProfile() {
return (
this.profiles.find((p) => p.profileId === this.selectedProfileId) ??
this.fallbackProfile
this.profiles.find(
(p) => p.profileDescription.id === this.selectedProfileId,
) ?? this.fallbackProfile
);
}

get inactiveProfiles() {
return this.profiles.filter((p) => p.profileId !== this.selectedProfileId);
return this.profiles.filter(
(p) => p.profileDescription.id !== this.selectedProfileId,
);
}

async openConfigProfile(profileId?: string) {
let openProfileId = profileId || this.selectedProfileId;
if (openProfileId === "local") {
await this.ide.openFile(pathToFileURL(getConfigJsonPath()).toString());
} else {
await this.ide.openUrl(
"https://app.continue.dev/",
// `https://app.continue.dev/workspaces/${openProfileId}/chat`,
);
await this.ide.openUrl(`${controlPlaneEnv.APP_URL}${openProfileId}`);
}
}

private async fetchControlPlaneProfiles() {
private async loadPlatformProfiles() {
// Get the profiles and create their lifecycle managers
this.controlPlaneClient
.listWorkspaces()
.then(async (workspaces) => {
.listAssistants()
.then(async (assistants) => {
this.profiles = this.profiles.filter(
(profile) => profile.profileId === "local",
(profile) => profile.profileDescription.id === "local",
);
workspaces.forEach((workspace) => {
const profileLoader = new ControlPlaneProfileLoader(
workspace.id,
workspace.name,
assistants.forEach((assistant) => {
const profileLoader = new PlatformProfileLoader(
assistant.configResult,
assistant.ownerSlug,
assistant.packageSlug,
this.controlPlaneClient,
this.ide,
this.ideSettingsPromise,
Expand Down Expand Up @@ -141,10 +145,67 @@ export class ConfigHandler {
}
})
.catch((e) => {
console.error(e);
console.error("Failed to list assistants: ", e);
});
}

private platformProfilesRefreshInterval: NodeJS.Timeout | undefined;

private async fetchControlPlaneProfiles() {
if (usePlatform()) {
clearInterval(this.platformProfilesRefreshInterval);
await this.loadPlatformProfiles();
this.platformProfilesRefreshInterval = setInterval(
this.loadPlatformProfiles.bind(this),
PlatformProfileLoader.RELOAD_INTERVAL,
);
} else {
this.controlPlaneClient
.listWorkspaces()
.then(async (workspaces) => {
this.profiles = this.profiles.filter(
(profile) => profile.profileDescription.id === "local",
);
workspaces.forEach((workspace) => {
const profileLoader = new ControlPlaneProfileLoader(
workspace.id,
workspace.name,
this.controlPlaneClient,
this.ide,
this.ideSettingsPromise,
this.writeLog,
this.reloadConfig.bind(this),
);
this.profiles.push(new ProfileLifecycleManager(profileLoader));
});

this.notifyProfileListeners(
this.profiles.map((profile) => profile.profileDescription),
);

// Check the last selected workspace, and reload if it isn't local
const workspaceId = await this.getWorkspaceId();
const lastSelectedWorkspaceIds =
this.globalContext.get("lastSelectedProfileForWorkspace") ?? {};
const selectedWorkspaceId = lastSelectedWorkspaceIds[workspaceId];
if (selectedWorkspaceId) {
this.selectedProfileId = selectedWorkspaceId;
await this.loadConfig();
} else {
// Otherwise we stick with local profile, and record choice
lastSelectedWorkspaceIds[workspaceId] = this.selectedProfileId;
this.globalContext.update(
"lastSelectedProfileForWorkspace",
lastSelectedWorkspaceIds,
);
}
})
.catch((e) => {
console.error(e);
});
}
}

async setSelectedProfile(profileId: string) {
this.selectedProfileId = profileId;
const result = await this.loadConfig();
Expand Down
27 changes: 7 additions & 20 deletions core/config/ProfileLifecycleManager.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { ConfigResult, ConfigValidationError } from "@continuedev/config-yaml";
import {
BrowserSerializedContinueConfig,
ContinueConfig,
IContextProvider,
} from "../index.js";

import { ConfigResult, finalToBrowserConfig } from "./load.js";
import { finalToBrowserConfig } from "./load.js";
import { IProfileLoader } from "./profile/IProfileLoader.js";

export interface ProfileDescription {
title: string;
id: string;
errors: ConfigValidationError[] | undefined;
}

export class ProfileLifecycleManager {
Expand All @@ -19,19 +21,8 @@ export class ProfileLifecycleManager {

constructor(private readonly profileLoader: IProfileLoader) {}

get profileId() {
return this.profileLoader.profileId;
}

get profileTitle() {
return this.profileLoader.profileTitle;
}

get profileDescription(): ProfileDescription {
return {
title: this.profileTitle,
id: this.profileId,
};
return this.profileLoader.description;
}

clearConfig() {
Expand Down Expand Up @@ -71,14 +62,10 @@ export class ProfileLifecycleManager {
result.config.contextProviders = (
result.config.contextProviders ?? []
).concat(additionalContextProviders);

this.savedConfigResult = result;
resolve(result);
} else if (result.errors) {
reject(
`Error in config.json: ${result.errors.map((item) => item.message).join(" | ")}`,
);
}

this.savedConfigResult = result;
resolve(result);
});

// Wait for the config promise to resolve
Expand Down
13 changes: 5 additions & 8 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import {
getEsbuildBinaryPath,
} from "../util/paths";

import { ConfigResult, ConfigValidationError } from "@continuedev/config-yaml";
import { usePlatform } from "../control-plane/flags";
import {
defaultContextProvidersJetBrains,
defaultContextProvidersVsCode,
Expand All @@ -70,13 +72,7 @@ import {
} from "./default";
import { getSystemPromptDotFile } from "./getSystemPromptDotFile";
// import { isSupportedLanceDbCpuTarget } from "./util";
import { ConfigValidationError, validateConfig } from "./validation.js";

export interface ConfigResult<T> {
config: T | undefined;
errors: ConfigValidationError[] | undefined;
configLoadInterrupted: boolean;
}
import { validateConfig } from "./validation.js";

function resolveSerializedConfig(filepath: string): SerializedContinueConfig {
let content = fs.readFileSync(filepath, "utf8");
Expand Down Expand Up @@ -229,7 +225,7 @@ function isModelDescription(
return (llm as ModelDescription).title !== undefined;
}

function isContextProviderWithParams(
export function isContextProviderWithParams(
contextProvider: CustomContextProvider | ContextProviderWithParams,
): contextProvider is ContextProviderWithParams {
return (contextProvider as ContextProviderWithParams).name !== undefined;
Expand Down Expand Up @@ -582,6 +578,7 @@ function finalToBrowserConfig(
experimental: final.experimental,
docs: final.docs,
tools: final.tools,
usePlatform: usePlatform(),
};
}

Expand Down
Loading
Loading