get_active_note tool

Returns the path + content of the currently focused note, or null
fields when no note is active. Read-only; mobile-safe.

Closes #48.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Mike Thicke 2026-05-25 20:11:13 -04:00
parent a4703596fb
commit b458d07e37
2 changed files with 64 additions and 0 deletions

View file

@ -0,0 +1,29 @@
import { describe, expect, it, vi } from "vitest";
import { App, TFile } from "obsidian";
import { getActiveNoteTool } from "@/agent/tools/vault/get_active_note";
import type CoIntelligencePlugin from "@/CoIntelligencePlugin";
import type { ToolExecutionContext } from "@/agent/types";
function makeCtx(app: App): ToolExecutionContext {
return { app, plugin: {} as CoIntelligencePlugin, toolCallId: "c" };
}
describe("getActiveNoteTool", () => {
it("returns nulls when no active file", async () => {
const app = new App();
app.workspace.getActiveFile = vi.fn().mockReturnValue(null);
const out = await getActiveNoteTool.execute({}, makeCtx(app));
expect(out).toEqual({ path: null, content: null });
});
it("returns path + content for an active file", async () => {
const file = new TFile();
file.path = "Active.md";
const app = new App();
app.workspace.getActiveFile = vi.fn().mockReturnValue(file);
app.vault.cachedRead = vi.fn().mockResolvedValue("body");
const out = await getActiveNoteTool.execute({}, makeCtx(app));
expect(out).toEqual({ path: "Active.md", content: "body" });
});
});

View file

@ -0,0 +1,35 @@
import { z } from "zod";
import type { CoiTool } from "@/agent/types";
const inputSchema = z.object({});
type Input = z.infer<typeof inputSchema>;
interface Output {
path: string | null;
content: string | null;
}
/**
* `get_active_note` returns the path and content of the note the user has
* focused in Obsidian. Returns nulls when no note is active (e.g. a non-file
* pane is focused). Read-only; no approval.
*/
export const getActiveNoteTool: CoiTool<Input, Output> = {
name: "get_active_note",
description:
"Get the path and content of the note the user is currently viewing in Obsidian, or nulls if no note is active.",
inputSchema,
requiresApproval: false,
scope: "vault",
platforms: ["desktop", "mobile"],
async execute(_input, { app }) {
const file = app.workspace.getActiveFile();
if (!file) {
return { path: null, content: null };
}
const content = await app.vault.cachedRead(file);
return { path: file.path, content };
},
};