Skip to content

Commit

Permalink
Aider part 2 (#32)
Browse files Browse the repository at this point in the history
* Added command retries

* barechatfilecontext

* Added Reset Session

* Added progress

* Added working

* Added cleanup

---------

Co-authored-by: nang-dev <[email protected]>
Co-authored-by: Himanshu <[email protected]>
  • Loading branch information
3 people authored Oct 23, 2024
1 parent ba37be1 commit 5886a84
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 149 deletions.
2 changes: 2 additions & 0 deletions core/config/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const FREE_TRIAL_MODELS: ModelDescription[] = [
];

export const defaultContextProvidersVsCode: ContextProviderWithParams[] = [
{ name: "file", params: {} },
{ name: "directory", params: {} },
{ name: "code", params: {} },
{ name: "docs", params: {} },
Expand All @@ -42,6 +43,7 @@ export const defaultContextProvidersVsCode: ContextProviderWithParams[] = [
{ name: "problems", params: {} },
{ name: "folder", params: {} },
{ name: "codebase", params: {} },
{ name: "relativefilecontext", params: {} },
];

export const defaultContextProvidersJetBrains: ContextProviderWithParams[] = [
Expand Down
6 changes: 3 additions & 3 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,9 @@ async function intermediateToFinalConfig(

// These context providers are always included, regardless of what, if anything,
// the user has configured in config.json
const DEFAULT_CONTEXT_PROVIDERS = [
new FileContextProvider({}),
new CodebaseContextProvider({}),
const DEFAULT_CONTEXT_PROVIDERS : any[] = [
// new FileContextProvider({}),
// new CodebaseContextProvider({}),
];

const DEFAULT_CONTEXT_PROVIDERS_TITLES = DEFAULT_CONTEXT_PROVIDERS.map(
Expand Down
4 changes: 3 additions & 1 deletion core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ declare global {
| "DraftIssueStep";
type ContextProviderName =
| "file"
| "diff"
| "github"
| "terminal"
Expand All @@ -471,7 +472,8 @@ declare global {
| "code"
| "docs"
| "gitlab-mr"
| "os";
| "os"
| "relativefilecontext";
type TemplateType =
| "llama2"
Expand Down
69 changes: 69 additions & 0 deletions core/context/providers/RelativeFileContextProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {
ContextItem,
ContextProviderDescription,
ContextProviderExtras,
ContextSubmenuItem,
LoadSubmenuItemsArgs,
} from "../../index.js";
import { walkDir } from "../../indexing/walkDir.js";
import {
getBasename,
getUniqueFilePath,
groupByLastNPathParts,
} from "../../util/index.js";
import { BaseContextProvider } from "../index.js";

const MAX_SUBMENU_ITEMS = 10_000;

class RelativeFileContextProvider extends BaseContextProvider {
static description: ContextProviderDescription = {
title: "relativefilecontext",
displayTitle: "Files",
description: "Add file to context.",
type: "submenu",
};

async getContextItems(
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]> {
const workspaceDirs = await extras.ide.getWorkspaceDirs();
const relativePath = this.normalizeRelativePath(query, workspaceDirs[0]);
return [
{
name: getBasename(query),
description: relativePath,
content: relativePath,
},
];
}

async loadSubmenuItems(
args: LoadSubmenuItemsArgs,
): Promise<ContextSubmenuItem[]> {
const workspaceDirs = await args.ide.getWorkspaceDirs();
const results = await Promise.all(
workspaceDirs.map((dir) => {
return walkDir(dir, args.ide);
}),
);
const files = results.flat().slice(-MAX_SUBMENU_ITEMS);
const fileGroups = groupByLastNPathParts(files, 2);

return files.map((file) => {
const relativePath = this.normalizeRelativePath(file, workspaceDirs[0]);
return {
id: file,
title: getBasename(file),
description: relativePath,
};
});
}

private normalizeRelativePath(path: string, workspaceDir: string): string {
const relativePath = path.replace(workspaceDir, "").replace(/^[\/\\]/, "");
return relativePath.replace(/\\/g, "/");
}
}

export default RelativeFileContextProvider;
5 changes: 5 additions & 0 deletions core/context/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import ProblemsContextProvider from "./ProblemsContextProvider.js";
import SearchContextProvider from "./SearchContextProvider.js";
import TerminalContextProvider from "./TerminalContextProvider.js";
import URLContextProvider from "./URLContextProvider.js";
import RelativeFileContextProvider from "./RelativeFileContextProvider.js";
import FileContextProvider from "./FileContextProvider.js";


/**
* Note: We are currently omitting the following providers due to bugs:
Expand All @@ -31,6 +34,7 @@ import URLContextProvider from "./URLContextProvider.js";
* See this issue for details: https://github.com/continuedev/continue/issues/1365
*/
const Providers: (typeof BaseContextProvider)[] = [
FileContextProvider,
DiffContextProvider,
FileTreeContextProvider,
GitHubIssuesContextProvider,
Expand All @@ -52,6 +56,7 @@ const Providers: (typeof BaseContextProvider)[] = [
CurrentFileContextProvider,
URLContextProvider,
ContinueProxyContextProvider,
RelativeFileContextProvider
];

export function contextProviderClassFromName(
Expand Down
4 changes: 3 additions & 1 deletion core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ type StepName =
| "DraftIssueStep";

type ContextProviderName =
| "file"
| "diff"
| "github"
| "terminal"
Expand All @@ -569,7 +570,8 @@ type ContextProviderName =
| "docs"
| "gitlab-mr"
| "os"
| "currentFile";
| "currentFile"
| "relativefilecontext";

type TemplateType =
| "llama2"
Expand Down
116 changes: 68 additions & 48 deletions core/llm/llms/Aider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,56 +158,74 @@ public async aiderResetSession(model: string, apiKey: string | undefined): Promi

let command: string[];

switch (model) {
case "claude-3-5-sonnet-20240620":
console.log("claude model chosen");
command = ["aider --model claude-3-5-sonnet-20240620"];
break;
case "gpt-4o":
command = ["aider --model gpt-4o"];
break;
case "pearai_model":
default:
await this.credentials.checkAndUpdateCredentials();
const accessToken = this.credentials.getAccessToken();
if (!accessToken) {
let message = "PearAI token invalid. Please try logging in or contact PearAI support."
vscode.window
.showErrorMessage(
message,
'Login To PearAI',
'Show Logs',
)
.then((selection: any) => {
if (selection === 'Login To PearAI') {
// Redirect to auth login URL
vscode.env.openExternal(
vscode.Uri.parse(
'https://trypear.ai/signin?callback=pearai://pearai.pearai/auth',
),
);
} else if (selection === 'Show Logs') {
vscode.commands.executeCommand(
'workbench.action.toggleDevTools',
);
const aiderFlags = "--no-pretty --yes-always --no-auto-commits";
const aiderCommands = [
`python -m aider ${aiderFlags}`,
`python3 -m aider ${aiderFlags}`,
`aider ${aiderFlags}`
];
let commandFound = false;

for (const aiderCommand of aiderCommands) {
try {
await execSync(`${aiderCommand} --version`, { stdio: 'ignore' });
commandFound = true;

switch (model) {
case model.includes("claude") && model:
command = [`${aiderCommand} --model ${model}`];
break;
case "gpt-4o":
command = [`${aiderCommand} --model gpt-4o`];
break;
case "pearai_model":
default:
await this.credentials.checkAndUpdateCredentials();
const accessToken = this.credentials.getAccessToken();
if (!accessToken) {
let message = "PearAI token invalid. Please try logging in or contact PearAI support."
vscode.window
.showErrorMessage(
message,
'Login To PearAI',
'Show Logs',
)
.then((selection: any) => {
if (selection === 'Login To PearAI') {
// Redirect to auth login URL
vscode.env.openExternal(
vscode.Uri.parse(
'https://trypear.ai/signin?callback=pearai://pearai.pearai/auth',
),
);
} else if (selection === 'Show Logs') {
vscode.commands.executeCommand(
'workbench.action.toggleDevTools',
);
}
});
throw new Error("User not logged in to PearAI.");
}
});
throw new Error("User not logged in to PearAI.");
command = [
aiderCommand,
"--openai-api-key",
accessToken,
"--openai-api-base",
`${SERVER_URL}/integrations/aider`,
];
break;
}
command = [
"aider",
"--openai-api-key",
accessToken,
"--openai-api-base",
`${SERVER_URL}/integrations/aider`,
];
break;
break; // Exit the loop if a working command is found
} catch (error) {
console.log(`Command ${aiderCommand} not found or errored. Trying next...`);
}
}

if (!commandFound) {
throw new Error("Aider command not found. Please ensure it's installed correctly.");
}

// disable pretty printing
command.push("--no-pretty");
command.push("--yes-always");
command.push("--no-auto-commits");


const userPath = this.getUserPath();
const userShell = this.getUserShell();
Expand Down Expand Up @@ -254,6 +272,8 @@ public async aiderResetSession(model: string, apiKey: string | undefined): Promi
env: {
...process.env,
PATH: userPath,
PYTHONIOENCODING: "utf-8",
AIDER_SIMPLE_OUTPUT: "1",
},
windowsHide: true,
});
Expand Down Expand Up @@ -343,7 +363,8 @@ public async aiderResetSession(model: string, apiKey: string | undefined): Promi
this.aiderProcess.stdin &&
!this.aiderProcess.killed
) {
this.aiderProcess.stdin.write(`${message}\n`);
const formattedMessage = message.replace(/\n+/g, " ");
this.aiderProcess.stdin.write(`${formattedMessage}\n`);
} else {
console.error("Aider process is not running");
}
Expand Down Expand Up @@ -404,7 +425,6 @@ public async aiderResetSession(model: string, apiKey: string | undefined): Promi
options: CompletionOptions,
): AsyncGenerator<ChatMessage> {
console.log("Inside Aider _streamChat");

const lastMessage = messages[messages.length - 1].content.toString();
this.sendToAiderChat(lastMessage);

Expand Down
22 changes: 16 additions & 6 deletions gui/src/components/mainInput/ContinueInputBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ContextItemsPeek from "./ContextItemsPeek";
import TipTapEditor from "./TipTapEditor";
import { useMemo } from "react";
import { defaultModelSelector } from "../../redux/selectors/modelSelectors";
import { isBareChatMode } from '../../util/bareChatMode';
import { isBareChatMode } from "../../util/bareChatMode";

const gradient = keyframes`
0% {
Expand Down Expand Up @@ -67,11 +67,19 @@ function ContinueInputBox(props: ContinueInputBoxProps) {

const active = useSelector((store: RootState) => store.state.active);
const availableSlashCommands = useSelector(selectSlashCommands);
const availableContextProviders = useSelector(
let availableContextProviders = useSelector(
(store: RootState) => store.state.config.contextProviders,
);
const bareChatMode = isBareChatMode();

const bareChatMode = isBareChatMode()
const filteredContextProviders = useMemo(() => {
return bareChatMode
? availableContextProviders.filter(
(provider) => provider.title === "relativefilecontext",
)
: availableContextProviders.filter(
(provider) => provider.title !== "relativefilecontext",
);
}, [bareChatMode, availableContextProviders]);

useWebviewListener(
"newSessionWithPrompt",
Expand Down Expand Up @@ -108,8 +116,10 @@ function ContinueInputBox(props: ContinueInputBoxProps) {
editorState={props.editorState}
onEnter={props.onEnter}
isMainInput={props.isMainInput}
availableContextProviders={bareChatMode ? undefined : availableContextProviders}
availableSlashCommands={bareChatMode ? undefined : availableSlashCommands}
availableContextProviders={filteredContextProviders}
availableSlashCommands={
bareChatMode ? undefined : availableSlashCommands
}
></TipTapEditor>
</GradientBorder>
<ContextItemsPeek contextItems={props.contextItems}></ContextItemsPeek>
Expand Down
4 changes: 1 addition & 3 deletions gui/src/components/mainInput/TipTapEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,7 @@ function TipTapEditor(props: TipTapEditorProps) {
const defaultModel = useSelector(defaultModelSelector);
const bareChatMode = isBareChatMode();
const getSubmenuContextItemsRef = useUpdatingRef(getSubmenuContextItems);
const availableContextProvidersRef = useUpdatingRef(
props.availableContextProviders,
);
const availableContextProvidersRef = useUpdatingRef(props.availableContextProviders)

const historyLengthRef = useUpdatingRef(historyLength);
const availableSlashCommandsRef = useUpdatingRef(
Expand Down
Loading

0 comments on commit 5886a84

Please sign in to comment.