fix: better filename resolution, choosing another agent works
This commit is contained in:
+1
-1
@@ -4,6 +4,6 @@
|
||||
"version": "0.1.0",
|
||||
"minAppVersion": "1.5.0",
|
||||
"description": "Send the current note to a Beaver agent via the markdown frontend.",
|
||||
"author": "Beaver",
|
||||
"author": "h",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
||||
+30
-36
@@ -1,42 +1,36 @@
|
||||
import { App, FuzzySuggestModal } from "obsidian";
|
||||
|
||||
export class AgentPickerModal extends FuzzySuggestModal<string> {
|
||||
private agents: string[];
|
||||
private resolve: (agent: string | null) => void;
|
||||
private resolved = false;
|
||||
|
||||
constructor(
|
||||
app: App,
|
||||
agents: string[],
|
||||
resolve: (agent: string | null) => void,
|
||||
) {
|
||||
super(app);
|
||||
this.agents = agents;
|
||||
this.resolve = resolve;
|
||||
this.setPlaceholder("Pick a Beaver agent…");
|
||||
}
|
||||
|
||||
getItems(): string[] {
|
||||
return this.agents;
|
||||
}
|
||||
|
||||
getItemText(item: string): string {
|
||||
return item;
|
||||
}
|
||||
|
||||
onChooseItem(item: string): void {
|
||||
this.resolved = true;
|
||||
this.resolve(item);
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
super.onClose();
|
||||
if (!this.resolved) this.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
export function pickAgent(app: App, agents: string[]): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
new AgentPickerModal(app, agents, resolve).open();
|
||||
let resolved = false;
|
||||
const settle = (value: string | null) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
resolve(value);
|
||||
};
|
||||
|
||||
const Picker = class extends FuzzySuggestModal<string> {
|
||||
getItems(): string[] {
|
||||
return agents;
|
||||
}
|
||||
getItemText(item: string): string {
|
||||
return item;
|
||||
}
|
||||
onChooseItem(item: string): void {
|
||||
settle(item);
|
||||
}
|
||||
onClose(): void {
|
||||
super.onClose();
|
||||
// onClose fires BEFORE onChooseItem in Obsidian's modal pipeline,
|
||||
// so we can't resolve null synchronously here — it'd race the
|
||||
// legitimate pick and steal the slot. Defer to the next tick so
|
||||
// onChooseItem (if any) settles first; if no pick happened
|
||||
// (Escape / click-away), this fires and we resolve null.
|
||||
setTimeout(() => settle(null), 0);
|
||||
}
|
||||
};
|
||||
const modal = new Picker(app);
|
||||
modal.setPlaceholder("Pick a Beaver agent…");
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
|
||||
+26
-2
@@ -84,8 +84,12 @@ export default class BeaverPlugin extends Plugin {
|
||||
}
|
||||
|
||||
private async runDifferent(file: TFile): Promise<void> {
|
||||
try {
|
||||
const agents = await this.getAgents();
|
||||
if (!agents) return;
|
||||
if (!agents) {
|
||||
new Notice("Beaver: couldn't fetch agents (see console)", 6000);
|
||||
return;
|
||||
}
|
||||
if (agents.length === 0) {
|
||||
new Notice("Beaver: no agents available");
|
||||
return;
|
||||
@@ -93,6 +97,9 @@ export default class BeaverPlugin extends Plugin {
|
||||
const picked = await pickAgent(this.app, agents);
|
||||
if (!picked) return;
|
||||
await this.dispatch(file, picked);
|
||||
} catch (err) {
|
||||
this.notifyError("send-different", err);
|
||||
}
|
||||
}
|
||||
|
||||
private async getAgents(): Promise<string[] | null> {
|
||||
@@ -113,6 +120,9 @@ export default class BeaverPlugin extends Plugin {
|
||||
}
|
||||
|
||||
private async dispatch(file: TFile, agent: string): Promise<void> {
|
||||
const filename = this.gatewayFilename(file);
|
||||
if (!filename) return;
|
||||
|
||||
const { editor, view } = this.findEditorFor(file);
|
||||
const content = editor
|
||||
? editor.getValue()
|
||||
@@ -122,7 +132,7 @@ export default class BeaverPlugin extends Plugin {
|
||||
let response: ChatResponse;
|
||||
try {
|
||||
response = await sendChat(this.settings, {
|
||||
filename: file.path,
|
||||
filename,
|
||||
content,
|
||||
agent,
|
||||
});
|
||||
@@ -149,6 +159,20 @@ export default class BeaverPlugin extends Plugin {
|
||||
new Notice(`Beaver: ${agent} replied`);
|
||||
}
|
||||
|
||||
private gatewayFilename(file: TFile): string | null {
|
||||
const subpath = this.settings.vaultSubpath;
|
||||
if (!subpath) return file.path;
|
||||
const prefix = subpath + "/";
|
||||
if (file.path === subpath || file.path.startsWith(prefix)) {
|
||||
return file.path.slice(prefix.length);
|
||||
}
|
||||
new Notice(
|
||||
`Beaver: file ${file.path} is outside the configured vault subpath (${subpath})`,
|
||||
8000,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
private findEditorFor(file: TFile): {
|
||||
editor: Editor | null;
|
||||
view: MarkdownView | null;
|
||||
|
||||
@@ -5,13 +5,19 @@ import type BeaverPlugin from "./main";
|
||||
export interface BeaverSettings {
|
||||
baseUrl: string;
|
||||
token: string;
|
||||
vaultSubpath: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: BeaverSettings = {
|
||||
baseUrl: "http://localhost:62993",
|
||||
token: "",
|
||||
vaultSubpath: "",
|
||||
};
|
||||
|
||||
export function normalizeSubpath(raw: string): string {
|
||||
return raw.trim().replace(/^\/+|\/+$/g, "");
|
||||
}
|
||||
|
||||
export class BeaverSettingsTab extends PluginSettingTab {
|
||||
plugin: BeaverPlugin;
|
||||
|
||||
@@ -51,6 +57,22 @@ export class BeaverSettingsTab extends PluginSettingTab {
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Vault subpath")
|
||||
.setDesc(
|
||||
"Folder in this Obsidian vault that maps to the gateway's vault root. " +
|
||||
"Leave empty if the two vault roots match. Example: `💬 чаты`.",
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("")
|
||||
.setValue(this.plugin.settings.vaultSubpath)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.vaultSubpath = normalizeSubpath(value);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Test connection")
|
||||
.setDesc("Calls GET /agents and reports the count.")
|
||||
|
||||
Reference in New Issue
Block a user