Skip to content

Commit 365d1fd

Browse files
committed
add ability to use anthropic models
1 parent 097b25a commit 365d1fd

File tree

3 files changed

+155
-99
lines changed

3 files changed

+155
-99
lines changed

manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"id": "open-interpreter",
33
"name": "Open Interpreter",
4-
"version": "1.0.0",
4+
"version": "1.1.0",
55
"minAppVersion": "0.15.0",
6-
"description": "Use Open Interpreter to run operations on your vault",
6+
"description": "Use Open Interpreter to run automaticoperations on your vault",
77
"author": "Mike Bird",
88
"authorUrl": "https://www.github.com/MikeBirdTech",
99
"isDesktopOnly": true

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-interpreter-plugin",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Plugin for integrating Open Interpreter with Obsidian",
55
"main": "main.js",
66
"scripts": {

src/main.ts

Lines changed: 152 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ import {
33
Notice,
44
Modal,
55
App,
6-
TFolder,
76
Setting,
87
PluginSettingTab,
98
Platform,
9+
DropdownComponent,
10+
FileSystemAdapter,
1011
} from "obsidian";
1112
import { exec, ChildProcess, spawn } from "child_process";
12-
import * as path from "path";
1313
import * as os from "os";
1414
import * as fs from "fs/promises";
1515

1616
interface OpenInterpreterSettings {
17-
apiKey: string;
18-
anthropicApiKey: string; // New field for Anthropic API Key
19-
provider: 'OpenAI' | 'Anthropic'; // New field for Provider selection
20-
model: string; // New field for LLM Model selection
17+
openaiApiKey: string;
18+
anthropicApiKey: string;
19+
provider: "OpenAI" | "Anthropic";
20+
model: string;
2121
}
2222

2323
const DEFAULT_SETTINGS: OpenInterpreterSettings = {
24-
apiKey: "",
25-
anthropicApiKey: "", // Default value for Anthropic API Key
26-
provider: 'OpenAI', // Default provider
27-
model: 'gpt-3.5-turbo', // Default model
24+
openaiApiKey: "",
25+
anthropicApiKey: "",
26+
provider: "OpenAI", // Default provider
27+
model: "gpt-4o", // Default model
2828
};
2929

3030
class InstallationGuideModal extends Modal {
@@ -277,40 +277,10 @@ export default class OpenInterpreterPlugin extends Plugin {
277277
});
278278
}
279279

280-
private async getInterpreterProfilePath(): Promise<string> {
281-
const homedir = os.homedir();
282-
const profileDir = path.join(
283-
homedir,
284-
"Library",
285-
"Application Support",
286-
"open-interpreter",
287-
"profiles"
288-
);
289-
const profilePath = path.join(profileDir, "obsidian.py");
290-
291-
// Ensure the directory exists
292-
await fs.mkdir(profileDir, { recursive: true });
293-
294-
// Create an empty profile file if it doesn't exist
295-
if (!(await fs.stat(profilePath).catch(() => false))) {
296-
await fs.writeFile(
297-
profilePath,
298-
"# Obsidian profile for Open Interpreter\n"
299-
);
300-
}
301-
302-
return profilePath;
303-
}
304-
305280
private getVaultPath(): string | null {
306281
const adapter = this.app.vault.adapter;
307-
if (adapter && "basePath" in adapter) {
308-
return (adapter as any).basePath;
309-
}
310-
// Fallback to the previous method if basePath is not available
311-
const rootFolder = this.app.vault.getRoot();
312-
if (rootFolder instanceof TFolder) {
313-
return rootFolder.path;
282+
if (adapter instanceof FileSystemAdapter) {
283+
return adapter.getBasePath();
314284
}
315285
console.error("Could not determine vault path");
316286
return null;
@@ -330,9 +300,10 @@ export default class OpenInterpreterPlugin extends Plugin {
330300
}
331301

332302
private async executeInterpreterCommand(command: string) {
333-
const profilePath = await this.getInterpreterProfilePath();
334303
const vaultPath = this.getVaultPath();
335304

305+
console.log("Determined vault path:", vaultPath);
306+
336307
if (!vaultPath) {
337308
console.error("Vault path could not be determined.");
338309
new Notice(
@@ -350,28 +321,66 @@ export default class OpenInterpreterPlugin extends Plugin {
350321
}
351322

352323
const env = { ...process.env };
353-
if (this.settings.provider === 'OpenAI') {
354-
env.OPENAI_API_KEY = this.settings.apiKey;
355-
} else if (this.settings.provider === 'Anthropic') {
356-
env.ANTHROPIC_API_KEY = this.settings.anthropicApiKey;
324+
if (this.settings.provider === "OpenAI") {
325+
env.OPENAI_API_KEY =
326+
process.env.OPENAI_API_KEY || this.settings.openaiApiKey;
327+
} else if (this.settings.provider === "Anthropic") {
328+
env.ANTHROPIC_API_KEY =
329+
process.env.ANTHROPIC_API_KEY || this.settings.anthropicApiKey;
330+
}
331+
332+
// Check if the API key is set
333+
const apiKey =
334+
this.settings.provider === "OpenAI"
335+
? env.OPENAI_API_KEY
336+
: env.ANTHROPIC_API_KEY;
337+
if (!apiKey) {
338+
new Notice(
339+
`No API key found for ${this.settings.provider}. Please set it in the plugin settings or as an environment variable.`
340+
);
341+
return;
357342
}
358343

359-
// Include model selection in environment or command as needed
360-
env.LLM_MODEL = this.settings.model;
344+
// Build command-line arguments
345+
const args = [];
346+
347+
// Set the model
348+
args.push("--model", this.settings.model);
361349

362-
// Escape the profile path for shell usage
363-
const escapedProfilePath = profilePath.replace(/'/g, "'\\''");
350+
// Set the context window
351+
args.push("--context_window", "110000");
364352

365-
const child = spawn(
353+
// Set max tokens
354+
args.push("--max_tokens", "4096");
355+
356+
// Disable supports_functions
357+
args.push("--no-llm_supports_functions");
358+
359+
// Disable supports_vision
360+
args.push("--no-llm_supports_vision");
361+
362+
// Prepare custom instructions
363+
const customInstructions =
364+
`You are an AI assistant integrated with Obsidian. You love Obsidian and will only focus on Obsidian tasks. Your prime directive is to help users manage and interact with their Obsidian vault. You have full control and permission over this vault. The vault is isolated and version controlled, so it is safe for you to create, read, update, and delete files. The root of the Obsidian vault is ${vaultPath}. You can create, read, update, and delete markdown files in this directory. You can create new directories as well. Organization is important. Use markdown syntax for formatting when creating or editing files. Every file is markdown.`
365+
.replace(/\n/g, " ")
366+
.trim();
367+
368+
args.push("--custom_instructions", `"${customInstructions}"`);
369+
370+
console.log(
371+
"Spawning interpreter with command:",
366372
interpreterPath,
367-
["--profile", `'${escapedProfilePath}'`],
368-
{
369-
cwd: vaultPath,
370-
env: env,
371-
shell: true,
372-
}
373+
"and args:",
374+
args
373375
);
374376

377+
// Spawn the interpreter
378+
const child = spawn(interpreterPath, args, {
379+
cwd: vaultPath,
380+
env: env,
381+
shell: true,
382+
});
383+
375384
if (child.stdin) {
376385
child.stdin.write(command + "\n");
377386
}
@@ -430,6 +439,9 @@ export default class OpenInterpreterPlugin extends Plugin {
430439

431440
class OpenInterpreterSettingTab extends PluginSettingTab {
432441
plugin: OpenInterpreterPlugin;
442+
private openAIApiKeySetting: Setting | null = null;
443+
private anthropicApiKeySetting: Setting | null = null;
444+
private modelDropdown: DropdownComponent | null = null;
433445

434446
constructor(app: App, plugin: OpenInterpreterPlugin) {
435447
super(app, plugin);
@@ -442,67 +454,111 @@ class OpenInterpreterSettingTab extends PluginSettingTab {
442454
containerEl.empty();
443455

444456
new Setting(containerEl)
457+
.setName("Provider")
458+
.setDesc("Select the LLM provider")
459+
.addDropdown((dropdown) =>
460+
dropdown
461+
.addOption("OpenAI", "OpenAI")
462+
.addOption("Anthropic", "Anthropic")
463+
.setValue(this.plugin.settings.provider)
464+
.onChange(async (value) => {
465+
this.plugin.settings.provider = value as "OpenAI" | "Anthropic";
466+
await this.plugin.saveSettings();
467+
this.updateApiKeyVisibility();
468+
this.updateModelOptions();
469+
})
470+
);
471+
472+
this.openAIApiKeySetting = new Setting(containerEl)
445473
.setName("OpenAI API Key")
446474
.setDesc("Enter your OpenAI API key")
447475
.addText((text) =>
448476
text
449477
.setPlaceholder("Enter your OpenAI API key")
450-
.setValue(this.plugin.settings.apiKey)
478+
.setValue(this.plugin.settings.openaiApiKey)
451479
.onChange(async (value) => {
452-
this.plugin.settings.apiKey = value;
480+
this.plugin.settings.openaiApiKey = value;
453481
await this.plugin.saveSettings();
454482
})
455483
);
456484

457-
new Setting(containerEl)
458-
.setName("Provider")
459-
.setDesc("Select the LLM provider")
460-
.addDropdown((dropdown) =>
461-
dropdown
462-
.addOption("OpenAI", "OpenAI")
463-
.addOption("Anthropic", "Anthropic")
464-
.setValue(this.plugin.settings.provider)
485+
this.anthropicApiKeySetting = new Setting(containerEl)
486+
.setName("Anthropic API Key")
487+
.setDesc("Enter your Anthropic API key")
488+
.addText((text) =>
489+
text
490+
.setPlaceholder("Enter your Anthropic API key")
491+
.setValue(this.plugin.settings.anthropicApiKey)
465492
.onChange(async (value) => {
466-
this.plugin.settings.provider = value as 'OpenAI' | 'Anthropic';
493+
this.plugin.settings.anthropicApiKey = value;
467494
await this.plugin.saveSettings();
468-
this.display(); // Refresh the settings to show/hide relevant fields
469495
})
470496
);
471497

472-
if (this.plugin.settings.provider === 'Anthropic') {
473-
new Setting(containerEl)
474-
.setName("Anthropic API Key")
475-
.setDesc("Enter your Anthropic API key")
476-
.addText((text) =>
477-
text
478-
.setPlaceholder("Enter your Anthropic API key")
479-
.setValue(this.plugin.settings.anthropicApiKey)
480-
.onChange(async (value) => {
481-
this.plugin.settings.anthropicApiKey = value;
482-
await this.plugin.saveSettings();
483-
})
484-
);
485-
}
486-
487498
new Setting(containerEl)
488499
.setName("Model")
489500
.setDesc("Select the LLM model")
490501
.addDropdown((dropdown) => {
491-
const models = this.plugin.settings.provider === 'OpenAI'
492-
? {
493-
"gpt-3.5-turbo": "GPT-3.5 Turbo",
494-
"gpt-4": "GPT-4",
495-
}
496-
: {
497-
"claude-v1": "Claude v1",
498-
"claude-v2": "Claude v2",
499-
};
500-
dropdown.addOptions(models);
501-
dropdown.setValue(this.plugin.settings.model);
502+
this.modelDropdown = dropdown;
503+
this.updateModelOptions();
502504
dropdown.onChange(async (value) => {
503505
this.plugin.settings.model = value;
504506
await this.plugin.saveSettings();
505507
});
506508
});
509+
510+
this.updateApiKeyVisibility();
511+
}
512+
513+
private updateApiKeyVisibility() {
514+
if (this.openAIApiKeySetting && this.anthropicApiKeySetting) {
515+
if (this.plugin.settings.provider === "OpenAI") {
516+
this.openAIApiKeySetting.settingEl.style.display = "block";
517+
this.anthropicApiKeySetting.settingEl.style.display = "none";
518+
} else {
519+
this.openAIApiKeySetting.settingEl.style.display = "none";
520+
this.anthropicApiKeySetting.settingEl.style.display = "block";
521+
}
522+
}
523+
}
524+
525+
private updateModelOptions() {
526+
if (this.modelDropdown) {
527+
const models = this.getModelsForProvider(this.plugin.settings.provider);
528+
// Remove all existing options
529+
this.modelDropdown.selectEl.empty();
530+
// Add new options
531+
Object.entries(models).forEach(([value, name]) => {
532+
this.modelDropdown?.addOption(value, name);
533+
});
534+
535+
// Set the first model as default if the current model is not in the list
536+
if (!models[this.plugin.settings.model]) {
537+
this.plugin.settings.model = Object.keys(models)[0];
538+
this.plugin.saveSettings();
539+
}
540+
541+
this.modelDropdown.setValue(this.plugin.settings.model);
542+
}
543+
}
544+
545+
private getModelsForProvider(
546+
provider: "OpenAI" | "Anthropic"
547+
): Record<string, string> {
548+
switch (provider) {
549+
case "OpenAI":
550+
return {
551+
"gpt-4o": "GPT-4o",
552+
"gpt-4o-mini": "GPT-4o-mini",
553+
};
554+
case "Anthropic":
555+
return {
556+
"claude-3-5-sonnet-20241022": "Claude 3.5 Sonnet",
557+
"claude-3-opus-20240229": "Claude 3 Opus",
558+
};
559+
default:
560+
console.error(`Unknown provider: ${provider}`);
561+
return {};
562+
}
507563
}
508564
}

0 commit comments

Comments
 (0)