2026-05-14 09:08:45 +00:00
|
|
|
import type ChainManager from "@/LLMProviders/chainManager";
|
2025-10-11 04:38:50 +00:00
|
|
|
import MemoryManager from "@/LLMProviders/memoryManager";
|
|
|
|
|
import { ModelAdapterFactory } from "@/LLMProviders/chainRunner/utils/modelAdapter";
|
|
|
|
|
import { buildAgentPromptDebugReport } from "@/LLMProviders/chainRunner/utils/promptDebugService";
|
|
|
|
|
import { ToolRegistry } from "@/tools/ToolRegistry";
|
|
|
|
|
import { ChatMessage } from "@/types/message";
|
|
|
|
|
import { initializeBuiltinTools } from "@/tools/builtinTools";
|
|
|
|
|
import { getSettings } from "@/settings/model";
|
|
|
|
|
import { UserMemoryManager } from "@/memory/UserMemoryManager";
|
2026-05-14 04:40:26 +00:00
|
|
|
import type { App } from "obsidian";
|
|
|
|
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
2025-10-11 04:38:50 +00:00
|
|
|
|
|
|
|
|
interface HeadlessApp {
|
|
|
|
|
vault: {
|
|
|
|
|
getRoot: () => { name: string };
|
|
|
|
|
getAbstractFileByPath: (path: string) => null;
|
|
|
|
|
read: (file: unknown) => Promise<string>;
|
|
|
|
|
getMarkdownFiles: () => unknown[];
|
|
|
|
|
getAllLoadedFiles: () => unknown[];
|
|
|
|
|
adapter: {
|
|
|
|
|
mkdir: (path: string) => Promise<void>;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
metadataCache: {
|
|
|
|
|
getFirstLinkpathDest: () => null;
|
|
|
|
|
getFileCache: () => null;
|
|
|
|
|
};
|
|
|
|
|
workspace: {
|
|
|
|
|
getActiveFile: () => null;
|
|
|
|
|
getLeaf: () => { openFile: () => Promise<void> };
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a minimal Obsidian app stub suitable for CLI usage.
|
|
|
|
|
*
|
|
|
|
|
* The autonomous agent only needs vault lookups and metadata cache reads, so this
|
|
|
|
|
* provides no-op implementations that satisfy those expectations.
|
|
|
|
|
*/
|
|
|
|
|
function createHeadlessApp(): HeadlessApp {
|
|
|
|
|
return {
|
|
|
|
|
vault: {
|
|
|
|
|
getRoot: () => ({ name: "root" }),
|
|
|
|
|
getAbstractFileByPath: () => null,
|
|
|
|
|
read: async () => "",
|
|
|
|
|
getMarkdownFiles: () => [],
|
|
|
|
|
getAllLoadedFiles: () => [],
|
|
|
|
|
adapter: {
|
|
|
|
|
mkdir: async () => {
|
|
|
|
|
/* no-op */
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
metadataCache: {
|
|
|
|
|
getFirstLinkpathDest: () => null,
|
|
|
|
|
getFileCache: () => null,
|
|
|
|
|
},
|
|
|
|
|
workspace: {
|
|
|
|
|
getActiveFile: () => null,
|
|
|
|
|
getLeaf: () => ({
|
|
|
|
|
openFile: async () => {
|
|
|
|
|
/* no-op */
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format a plain user message into the ChatMessage shape used by the agent.
|
|
|
|
|
*
|
|
|
|
|
* @param message - Raw user text to analyse.
|
|
|
|
|
* @returns Minimal chat message.
|
|
|
|
|
*/
|
|
|
|
|
function buildChatMessage(message: string): ChatMessage {
|
|
|
|
|
return {
|
|
|
|
|
message,
|
|
|
|
|
originalMessage: message,
|
|
|
|
|
sender: "user",
|
|
|
|
|
timestamp: null,
|
|
|
|
|
isVisible: true,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate the annotated prompt debug report for a given user input.
|
|
|
|
|
*
|
|
|
|
|
* @param args - CLI arguments (expects the user prompt as the concatenated string).
|
|
|
|
|
*/
|
|
|
|
|
export async function run(args: string[]): Promise<void> {
|
|
|
|
|
const userInput = args.join(" ").trim();
|
|
|
|
|
|
|
|
|
|
if (!userInput) {
|
|
|
|
|
console.error('Usage: npm run prompt:debug -- "your message here"');
|
|
|
|
|
process.exitCode = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const app = createHeadlessApp();
|
2026-05-13 08:14:47 +00:00
|
|
|
// eslint-disable-next-line obsidianmd/no-global-this -- node-only debug script, no window available
|
2026-05-13 05:24:17 +00:00
|
|
|
(global as unknown as { app: unknown }).app = app;
|
2025-10-11 04:38:50 +00:00
|
|
|
|
|
|
|
|
initializeBuiltinTools();
|
|
|
|
|
|
|
|
|
|
const registry = ToolRegistry.getInstance();
|
|
|
|
|
const settings = getSettings();
|
|
|
|
|
const enabledToolIds = new Set(settings.autonomousAgentEnabledToolIds || []);
|
|
|
|
|
const availableTools = registry.getEnabledTools(enabledToolIds, false);
|
|
|
|
|
|
2026-01-27 02:35:27 +00:00
|
|
|
// Generate simple tool descriptions (native tool calling handles schema via bindTools)
|
|
|
|
|
const toolDescriptions = availableTools
|
|
|
|
|
.map((tool) => `${tool.name}: ${tool.description}`)
|
|
|
|
|
.join("\n");
|
2025-10-11 04:38:50 +00:00
|
|
|
|
|
|
|
|
const memoryManager = MemoryManager.getInstance();
|
2026-05-14 04:40:26 +00:00
|
|
|
const userMemoryManager = new UserMemoryManager(app as unknown as App);
|
2025-10-11 04:38:50 +00:00
|
|
|
const chainContext = {
|
|
|
|
|
memoryManager,
|
|
|
|
|
userMemoryManager,
|
2026-05-14 09:08:45 +00:00
|
|
|
} as unknown as ChainManager;
|
2025-10-11 04:38:50 +00:00
|
|
|
|
2026-05-14 04:40:26 +00:00
|
|
|
const adapter = ModelAdapterFactory.createAdapter({
|
|
|
|
|
modelName: "gpt-4",
|
|
|
|
|
} as unknown as BaseChatModel);
|
2025-10-11 04:38:50 +00:00
|
|
|
const report = await buildAgentPromptDebugReport({
|
|
|
|
|
chainManager: chainContext,
|
|
|
|
|
adapter,
|
|
|
|
|
availableTools,
|
|
|
|
|
toolDescriptions,
|
|
|
|
|
userMessage: buildChatMessage(userInput),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log(report.annotatedPrompt);
|
|
|
|
|
}
|