Strengthen tool-calling discipline and add auto-nudge fallback

Tighten system prompts across edit, organize, and research modes to
prohibit "Let me..." / "I will..." prefatory text and require immediate
tool_call emission. Remove stale instructions referencing deleted tools.
Improve search_vault_files description for LLM clarity. Add runtime
auto-nudge: if a tool-capable mode emits no tool_calls but language
suggests intent to act, re-prompt the model to emit the required calls.
This commit is contained in:
2026-05-21 10:23:53 +02:00
parent af9f0d165a
commit 5c2078aebb
3 changed files with 128 additions and 16 deletions
+60 -8
View File
@@ -3180,7 +3180,7 @@ Do not make up facts.`,
description: "Create, modify, and organize notes with full editing tools.", description: "Create, modify, and organize notes with full editing tools.",
systemPrompt: `You are an assistant that helps edit and manage notes in the user's Obsidian vault. systemPrompt: `You are an assistant that helps edit and manage notes in the user's Obsidian vault.
You have full access to reading, searching, creating, appending, renaming, moving, and deleting notes. You have full access to reading, searching, creating, appending, renaming, moving, and deleting notes.
IMPORTANT: When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to the appropriate tool. CRITICAL RULE: When you need to take action, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
When editing notes: When editing notes:
- Prefer modifying existing content over creating duplicates. - Prefer modifying existing content over creating duplicates.
@@ -3196,9 +3196,8 @@ When editing notes:
label: "Organize", label: "Organize",
description: "Tag, rename, move, and link notes to keep the vault tidy.", description: "Tag, rename, move, and link notes to keep the vault tidy.",
systemPrompt: `You are an assistant that helps organize the user's Obsidian vault. systemPrompt: `You are an assistant that helps organize the user's Obsidian vault.
You can search notes, read them, list all vault tags, get vault structure stats, update frontmatter tags, rename files, move files to folders, and insert wiki-links. You can search notes, read them, update frontmatter tags, rename files, move files to folders, and insert wiki-links.
IMPORTANT: When the user asks about tags or folder structure, use list_vault_tags or get_vault_stats FIRST instead of searching blindly. CRITICAL RULE: When you need to take action, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to the appropriate tool.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
When organizing: When organizing:
- Suggest consistent tag vocabularies. - Suggest consistent tag vocabularies.
@@ -3214,8 +3213,7 @@ When organizing:
description: "Deep vault search and synthesis across multiple notes.", description: "Deep vault search and synthesis across multiple notes.",
systemPrompt: `You are a research assistant that dives deep into the user's Obsidian vault. systemPrompt: `You are a research assistant that dives deep into the user's Obsidian vault.
Your job is to synthesize information across multiple notes, find connections, and produce comprehensive summaries. Your job is to synthesize information across multiple notes, find connections, and produce comprehensive summaries.
IMPORTANT: When the user asks about tags or vault structure, use list_vault_tags or get_vault_stats FIRST before searching. CRITICAL RULE: When you need vault information, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to search_vault_files or read_vault_file.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
Search broadly, read key sources, and cross-reference information. Search broadly, read key sources, and cross-reference information.
Cite specific notes and quotes where possible. Cite specific notes and quotes where possible.
@@ -11285,13 +11283,13 @@ var ChatView = class extends import_obsidian5.ItemView {
type: "function", type: "function",
function: { function: {
name: "search_vault_files", name: "search_vault_files",
description: "Searches for files in the vault that match a given query", description: "Searches for files in the vault by content, tags, titles, and headings using a given query. Returns matching file metadata including paths, titles, and tags.",
parameters: { parameters: {
type: "object", type: "object",
properties: { properties: {
query: { query: {
type: "string", type: "string",
description: "The search query to use" description: "The search query to use (can be a keyword, tag, or phrase)"
}, },
limit: { limit: {
type: "number", type: "number",
@@ -11893,6 +11891,60 @@ ${actualMessage}` : actualMessage;
assistantMessageId assistantMessageId
); );
} }
const toolCapableModes = ["edit", "organize", "research"];
if (toolCalls.length === 0 && toolCapableModes.includes(this.currentAgentMode) && fullResponse.trim().length > 0) {
const intentPhrases = [
"let me",
"i will",
"i need to",
"search for",
"find",
"read",
"explore",
"look for",
"check",
"move",
"rename",
"create"
];
const lowerResponse = fullResponse.toLowerCase();
const seemsToWantTools = intentPhrases.some((p) => lowerResponse.includes(p));
if (seemsToWantTools) {
const nudgeMessages = [
...messagesWithMemory,
{ role: "assistant", content: fullResponse },
{
role: "user",
content: "You indicated you would take action but did not emit any tool_calls. Please emit the required tool_calls now. Do not output explanatory text."
}
];
const nudgeStream = activeClient.streamChat(nudgeMessages, tools);
fullResponse = "";
toolCalls = [];
for await (const chunk of nudgeStream) {
if (chunk.content) {
fullResponse += chunk.content;
this.updateMessageById(assistantMessageId, {
content: fullResponse,
isStreaming: true,
isThinking: false
});
}
if (chunk.tool_calls) {
toolCalls = [...toolCalls, ...chunk.tool_calls];
}
}
if (toolCalls.length > 0) {
await this.processToolCalls(
toolCalls,
nudgeMessages,
tools,
fullResponse,
assistantMessageId
);
}
}
}
if (toolCalls.length === 0) { if (toolCalls.length === 0) {
this.updateMessageById(assistantMessageId, { this.updateMessageById(assistantMessageId, {
content: fullResponse, content: fullResponse,
+4 -6
View File
@@ -86,7 +86,7 @@ Do not make up facts.`,
description: 'Create, modify, and organize notes with full editing tools.', description: 'Create, modify, and organize notes with full editing tools.',
systemPrompt: `You are an assistant that helps edit and manage notes in the user's Obsidian vault. systemPrompt: `You are an assistant that helps edit and manage notes in the user's Obsidian vault.
You have full access to reading, searching, creating, appending, renaming, moving, and deleting notes. You have full access to reading, searching, creating, appending, renaming, moving, and deleting notes.
IMPORTANT: When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to the appropriate tool. CRITICAL RULE: When you need to take action, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
When editing notes: When editing notes:
- Prefer modifying existing content over creating duplicates. - Prefer modifying existing content over creating duplicates.
@@ -103,9 +103,8 @@ When editing notes:
label: 'Organize', label: 'Organize',
description: 'Tag, rename, move, and link notes to keep the vault tidy.', description: 'Tag, rename, move, and link notes to keep the vault tidy.',
systemPrompt: `You are an assistant that helps organize the user's Obsidian vault. systemPrompt: `You are an assistant that helps organize the user's Obsidian vault.
You can search notes, read them, list all vault tags, get vault structure stats, update frontmatter tags, rename files, move files to folders, and insert wiki-links. You can search notes, read them, update frontmatter tags, rename files, move files to folders, and insert wiki-links.
IMPORTANT: When the user asks about tags or folder structure, use list_vault_tags or get_vault_stats FIRST instead of searching blindly. CRITICAL RULE: When you need to take action, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to the appropriate tool.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
When organizing: When organizing:
- Suggest consistent tag vocabularies. - Suggest consistent tag vocabularies.
@@ -122,8 +121,7 @@ When organizing:
description: 'Deep vault search and synthesis across multiple notes.', description: 'Deep vault search and synthesis across multiple notes.',
systemPrompt: `You are a research assistant that dives deep into the user's Obsidian vault. systemPrompt: `You are a research assistant that dives deep into the user's Obsidian vault.
Your job is to synthesize information across multiple notes, find connections, and produce comprehensive summaries. Your job is to synthesize information across multiple notes, find connections, and produce comprehensive summaries.
IMPORTANT: When the user asks about tags or vault structure, use list_vault_tags or get_vault_stats FIRST before searching. CRITICAL RULE: When you need vault information, you MUST immediately emit the tool_call(s). Do NOT output text like "Let me search..." or "I will..." or "Now I...". Either emit the tool calls immediately, or provide the final answer.
When you need vault information, do NOT say you will search or read files. You MUST immediately emit a tool_call to search_vault_files or read_vault_file.
Only respond to the user after you have received and analyzed the tool results. Only respond to the user after you have received and analyzed the tool results.
Search broadly, read key sources, and cross-reference information. Search broadly, read key sources, and cross-reference information.
Cite specific notes and quotes where possible. Cite specific notes and quotes where possible.
+64 -2
View File
@@ -522,13 +522,14 @@ export class ChatView extends ItemView {
type: 'function', type: 'function',
function: { function: {
name: 'search_vault_files', name: 'search_vault_files',
description: 'Searches for files in the vault that match a given query', description:
'Searches for files in the vault by content, tags, titles, and headings using a given query. Returns matching file metadata including paths, titles, and tags.',
parameters: { parameters: {
type: 'object', type: 'object',
properties: { properties: {
query: { query: {
type: 'string', type: 'string',
description: 'The search query to use', description: 'The search query to use (can be a keyword, tag, or phrase)',
}, },
limit: { limit: {
type: 'number', type: 'number',
@@ -1234,6 +1235,67 @@ export class ChatView extends ItemView {
); );
} }
// Auto-nudge for tool-capable modes if assistant didn't emit tools but seems to intend to
const toolCapableModes: AgentMode[] = ['edit', 'organize', 'research'];
if (
toolCalls.length === 0 &&
toolCapableModes.includes(this.currentAgentMode) &&
fullResponse.trim().length > 0
) {
const intentPhrases = [
'let me',
'i will',
'i need to',
'search for',
'find',
'read',
'explore',
'look for',
'check',
'move',
'rename',
'create',
];
const lowerResponse = fullResponse.toLowerCase();
const seemsToWantTools = intentPhrases.some((p) => lowerResponse.includes(p));
if (seemsToWantTools) {
const nudgeMessages: OllamaMessage[] = [
...messagesWithMemory,
{ role: 'assistant', content: fullResponse },
{
role: 'user',
content:
'You indicated you would take action but did not emit any tool_calls. Please emit the required tool_calls now. Do not output explanatory text.',
},
];
const nudgeStream = activeClient.streamChat(nudgeMessages, tools);
fullResponse = '';
toolCalls = [];
for await (const chunk of nudgeStream) {
if (chunk.content) {
fullResponse += chunk.content;
this.updateMessageById(assistantMessageId, {
content: fullResponse,
isStreaming: true,
isThinking: false,
});
}
if (chunk.tool_calls) {
toolCalls = [...toolCalls, ...chunk.tool_calls];
}
}
if (toolCalls.length > 0) {
await this.processToolCalls(
toolCalls,
nudgeMessages,
tools,
fullResponse,
assistantMessageId
);
}
}
}
// Update assistant message immutably — only if no tool calls were processed // Update assistant message immutably — only if no tool calls were processed
if (toolCalls.length === 0) { if (toolCalls.length === 0) {
this.updateMessageById(assistantMessageId, { this.updateMessageById(assistantMessageId, {