5.4 KiB
Fetch Models Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add an "Aktualisieren" button next to the model dropdown in settings that fetches the 3 newest Claude models from the Anthropic API and repopulates the dropdown.
Architecture: ClaudeClient gains a fetchModels() method (reusing existing requestUrl/headers patterns). SettingsTab captures the DropdownComponent and ButtonComponent references, wires the button to call fetchModels, and rebuilds the dropdown on success.
Tech Stack: TypeScript, Obsidian plugin API (requestUrl, Setting, DropdownComponent, ButtonComponent, Notice), Anthropic Models API (GET /v1/models)
File Map
| File | Change |
|---|---|
src/ClaudeClient.ts |
Add fetchModels(apiKey) method |
src/SettingsTab.ts |
Update imports; refactor "Modell" Setting to capture dropdown + add button |
Task 1: Add fetchModels to ClaudeClient
Files:
-
Modify:
src/ClaudeClient.ts -
Step 1: Add the method after the
chat()method
In src/ClaudeClient.ts, add after line 86 (after chat()'s closing brace):
/** Fetch the 3 newest Claude models from the Anthropic Models API. */
async fetchModels(apiKey: string): Promise<{ id: string; name: string }[]> {
const response = await requestUrl({
url: "https://api.anthropic.com/v1/models",
method: "GET",
headers: this.headers(apiKey),
throw: false,
});
if (response.status >= 400) {
throw new Error(`API Error ${response.status}: ${response.text}`);
}
const data: { id: string; created: number }[] = response.json.data ?? [];
if (data.length === 0) {
throw new Error("No models returned");
}
return data
.sort((a, b) => b.created - a.created)
.slice(0, 3)
.map((m) => ({ id: m.id, name: m.id }));
}
- Step 2: Verify build passes
npm run build
Expected: no TypeScript errors, main.js written successfully.
- Step 3: Commit
git add src/ClaudeClient.ts
git commit -m "feat: add fetchModels to ClaudeClient"
Task 2: Update SettingsTab — imports and model setting
Files:
-
Modify:
src/SettingsTab.ts:1(import line) -
Modify:
src/SettingsTab.ts:151-160(the "Modell" Setting block) -
Step 1: Extend the import from
"obsidian"
Replace the current import line 1:
import { App, PluginSettingTab, Setting } from "obsidian";
With:
import { App, ButtonComponent, DropdownComponent, Notice, PluginSettingTab, Setting } from "obsidian";
- Step 2: Replace the "Modell" Setting block
Replace lines 151–160:
new Setting(containerEl)
.setName("Modell")
.setDesc("Welches Claude-Modell verwenden?")
.addDropdown((drop) => {
for (const m of MODELS) drop.addOption(m.id, m.name);
drop.setValue(this.plugin.settings.model).onChange(async (value) => {
this.plugin.settings.model = value;
await this.plugin.saveSettings();
});
});
With:
let modelDrop: DropdownComponent;
let refreshBtn: ButtonComponent;
new Setting(containerEl)
.setName("Modell")
.setDesc("Welches Claude-Modell verwenden?")
.addDropdown((drop) => {
modelDrop = drop;
for (const m of MODELS) drop.addOption(m.id, m.name);
drop.setValue(this.plugin.settings.model).onChange(async (value) => {
this.plugin.settings.model = value;
await this.plugin.saveSettings();
});
})
.addButton((btn) => {
refreshBtn = btn;
btn.setButtonText("Aktualisieren").onClick(async () => {
const prev = modelDrop.getValue();
refreshBtn.setDisabled(true);
refreshBtn.setButtonText("...");
try {
const models = await this.plugin.claude.fetchModels(this.plugin.settings.apiKey);
modelDrop.selectEl.empty();
for (const m of models) modelDrop.addOption(m.id, m.name);
modelDrop.setValue(prev);
this.plugin.settings.model = modelDrop.getValue();
await this.plugin.saveSettings();
} catch (err) {
new Notice("Modelle konnten nicht geladen werden: " + (err as Error).message);
} finally {
refreshBtn.setDisabled(false);
refreshBtn.setButtonText("Aktualisieren");
}
});
});
- Step 3: Verify build passes
npm run build
Expected: no TypeScript errors, main.js written successfully.
- Step 4: Manual smoke test in Obsidian
- Copy
main.js,manifest.json,styles.cssto.obsidian/plugins/memex-chat/in your vault - Reload the plugin (or restart Obsidian)
- Open Settings → Memex Chat
- Confirm the "Modell" row has a dropdown and an "Aktualisieren" button
- With a valid API key set, click "Aktualisieren" — button should show "...", then restore; dropdown should show 3 model IDs
- With no API key, click "Aktualisieren" — a Notice should appear with an error message; dropdown should be unchanged
- Step 5: Commit
git add src/SettingsTab.ts
git commit -m "feat: add Aktualisieren button to fetch models from API"