fix: better filename resolution, choosing another agent works
This commit is contained in:
+1
-1
@@ -4,6 +4,6 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"minAppVersion": "1.5.0",
|
"minAppVersion": "1.5.0",
|
||||||
"description": "Send the current note to a Beaver agent via the markdown frontend.",
|
"description": "Send the current note to a Beaver agent via the markdown frontend.",
|
||||||
"author": "Beaver",
|
"author": "h",
|
||||||
"isDesktopOnly": false
|
"isDesktopOnly": false
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-36
@@ -1,42 +1,36 @@
|
|||||||
import { App, FuzzySuggestModal } from "obsidian";
|
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> {
|
export function pickAgent(app: App, agents: string[]): Promise<string | null> {
|
||||||
return new Promise((resolve) => {
|
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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-9
@@ -84,15 +84,22 @@ export default class BeaverPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async runDifferent(file: TFile): Promise<void> {
|
private async runDifferent(file: TFile): Promise<void> {
|
||||||
const agents = await this.getAgents();
|
try {
|
||||||
if (!agents) return;
|
const agents = await this.getAgents();
|
||||||
if (agents.length === 0) {
|
if (!agents) {
|
||||||
new Notice("Beaver: no agents available");
|
new Notice("Beaver: couldn't fetch agents (see console)", 6000);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
if (agents.length === 0) {
|
||||||
|
new Notice("Beaver: no agents available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const picked = await pickAgent(this.app, agents);
|
||||||
|
if (!picked) return;
|
||||||
|
await this.dispatch(file, picked);
|
||||||
|
} catch (err) {
|
||||||
|
this.notifyError("send-different", err);
|
||||||
}
|
}
|
||||||
const picked = await pickAgent(this.app, agents);
|
|
||||||
if (!picked) return;
|
|
||||||
await this.dispatch(file, picked);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAgents(): Promise<string[] | null> {
|
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> {
|
private async dispatch(file: TFile, agent: string): Promise<void> {
|
||||||
|
const filename = this.gatewayFilename(file);
|
||||||
|
if (!filename) return;
|
||||||
|
|
||||||
const { editor, view } = this.findEditorFor(file);
|
const { editor, view } = this.findEditorFor(file);
|
||||||
const content = editor
|
const content = editor
|
||||||
? editor.getValue()
|
? editor.getValue()
|
||||||
@@ -122,7 +132,7 @@ export default class BeaverPlugin extends Plugin {
|
|||||||
let response: ChatResponse;
|
let response: ChatResponse;
|
||||||
try {
|
try {
|
||||||
response = await sendChat(this.settings, {
|
response = await sendChat(this.settings, {
|
||||||
filename: file.path,
|
filename,
|
||||||
content,
|
content,
|
||||||
agent,
|
agent,
|
||||||
});
|
});
|
||||||
@@ -149,6 +159,20 @@ export default class BeaverPlugin extends Plugin {
|
|||||||
new Notice(`Beaver: ${agent} replied`);
|
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): {
|
private findEditorFor(file: TFile): {
|
||||||
editor: Editor | null;
|
editor: Editor | null;
|
||||||
view: MarkdownView | null;
|
view: MarkdownView | null;
|
||||||
|
|||||||
@@ -5,13 +5,19 @@ import type BeaverPlugin from "./main";
|
|||||||
export interface BeaverSettings {
|
export interface BeaverSettings {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
token: string;
|
token: string;
|
||||||
|
vaultSubpath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: BeaverSettings = {
|
export const DEFAULT_SETTINGS: BeaverSettings = {
|
||||||
baseUrl: "http://localhost:62993",
|
baseUrl: "http://localhost:62993",
|
||||||
token: "",
|
token: "",
|
||||||
|
vaultSubpath: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function normalizeSubpath(raw: string): string {
|
||||||
|
return raw.trim().replace(/^\/+|\/+$/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
export class BeaverSettingsTab extends PluginSettingTab {
|
export class BeaverSettingsTab extends PluginSettingTab {
|
||||||
plugin: BeaverPlugin;
|
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)
|
new Setting(containerEl)
|
||||||
.setName("Test connection")
|
.setName("Test connection")
|
||||||
.setDesc("Calls GET /agents and reports the count.")
|
.setDesc("Calls GET /agents and reports the count.")
|
||||||
|
|||||||
Reference in New Issue
Block a user