Simplify tool call nudging and refine action detection
Replace the 3-attempt retry loop with a single nudge when the model explicitly mentioned taking action. Remove misleading nudges for models that never expressed intent, which wasted round-trips and confused responses. Also streamline the userWantsVaultOps phrase list to remove weak triggers like "ok", "yes", and "please", and add fallback content for empty responses.
This commit is contained in:
@@ -11837,7 +11837,7 @@ ${writePreviews.map((a) => `- ${a.description}`).join("\n")}`,
|
||||
);
|
||||
} else {
|
||||
this.updateMessageById(assistantMessageId, {
|
||||
content: followUpContent || fullResponse,
|
||||
content: followUpContent || fullResponse || "(No response)",
|
||||
isStreaming: false,
|
||||
isThinking: false
|
||||
});
|
||||
@@ -12182,39 +12182,29 @@ ${actualMessage}` : actualMessage;
|
||||
if (isToolCapable && toolCalls.length === 0) {
|
||||
if (modelMentionedActions || userWantsVaultOps) {
|
||||
shouldFallbackToReadTools = true;
|
||||
const priorResponse = fullResponse;
|
||||
fullResponse = "";
|
||||
this.updateMessageById(assistantMessageId, {
|
||||
content: "",
|
||||
isStreaming: false,
|
||||
isThinking: false
|
||||
});
|
||||
let attempts = 0;
|
||||
const maxAttempts = 3;
|
||||
let currentMessages = [...messagesWithMemory];
|
||||
let currentResponse = "";
|
||||
while (attempts < maxAttempts && toolCalls.length === 0) {
|
||||
attempts++;
|
||||
this.showActivityIndicator(
|
||||
attempts === 1 ? "Thinking\u2026" : `Retrying (${attempts}/${maxAttempts})\u2026`
|
||||
);
|
||||
if (modelMentionedActions) {
|
||||
this.showActivityIndicator("Thinking\u2026");
|
||||
const nudgeMessages = [
|
||||
...currentMessages,
|
||||
...currentResponse.trim() ? [{ role: "assistant", content: currentResponse }] : [],
|
||||
...messagesWithMemory,
|
||||
...priorResponse.trim() ? [{ role: "assistant", content: priorResponse }] : [],
|
||||
{
|
||||
role: "user",
|
||||
content: attempts === 1 ? "You indicated you would take action but did not emit any tool_calls. Emit the required tool_calls now. Do not output explanatory text." : "You still have not emitted any tool_calls. Remember: when you need vault information, you MUST call tools immediately. Emit the tool_calls now. No text."
|
||||
content: "You indicated you would take action but did not emit any tool_calls. Emit the required tool_calls now. Do not output explanatory text."
|
||||
}
|
||||
];
|
||||
try {
|
||||
const nudgeStream = activeClient.streamChat(nudgeMessages, tools);
|
||||
currentResponse = "";
|
||||
let nudgeResponse = "";
|
||||
for await (const chunk of nudgeStream) {
|
||||
if (chunk.content) {
|
||||
currentResponse += chunk.content;
|
||||
}
|
||||
if (chunk.tool_calls) {
|
||||
toolCalls = [...toolCalls, ...chunk.tool_calls];
|
||||
}
|
||||
if (chunk.content) nudgeResponse += chunk.content;
|
||||
if (chunk.tool_calls) toolCalls = [...toolCalls, ...chunk.tool_calls];
|
||||
}
|
||||
if (toolCalls.length > 0) {
|
||||
this.showActivityIndicator("Using tools\u2026");
|
||||
@@ -12222,27 +12212,23 @@ ${actualMessage}` : actualMessage;
|
||||
toolCalls,
|
||||
nudgeMessages,
|
||||
tools,
|
||||
currentResponse,
|
||||
nudgeResponse,
|
||||
assistantMessageId
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
break;
|
||||
}
|
||||
currentMessages = nudgeMessages;
|
||||
}
|
||||
if (toolCalls.length === 0) {
|
||||
const autoToolCalls = this.buildAutomaticReadToolCalls(actualMessage, tools);
|
||||
if (autoToolCalls.length > 0) {
|
||||
this.showActivityIndicator("Using tools\u2026");
|
||||
toolCalls = autoToolCalls;
|
||||
fullResponse = "";
|
||||
await this.processToolCalls(
|
||||
autoToolCalls,
|
||||
messagesWithMemory,
|
||||
tools,
|
||||
fullResponse,
|
||||
"",
|
||||
assistantMessageId
|
||||
);
|
||||
}
|
||||
@@ -12361,25 +12347,15 @@ ${actualMessage}` : actualMessage;
|
||||
"files",
|
||||
"continue",
|
||||
"go ahead",
|
||||
"start",
|
||||
"proceed",
|
||||
"do it",
|
||||
"execute",
|
||||
"run",
|
||||
"proceed",
|
||||
"next",
|
||||
"now",
|
||||
"yes",
|
||||
"ok",
|
||||
"okay",
|
||||
"sure",
|
||||
"please",
|
||||
"step",
|
||||
"implement",
|
||||
"apply",
|
||||
"merge",
|
||||
"clean",
|
||||
"fix",
|
||||
"update",
|
||||
"implement",
|
||||
"apply"
|
||||
"update"
|
||||
];
|
||||
return operationPhrases.some((phrase) => lower.includes(phrase));
|
||||
}
|
||||
|
||||
+22
-51
@@ -1092,7 +1092,7 @@ export class ChatView extends ItemView {
|
||||
);
|
||||
} else {
|
||||
this.updateMessageById(assistantMessageId, {
|
||||
content: followUpContent || fullResponse,
|
||||
content: followUpContent || fullResponse || '(No response)',
|
||||
isStreaming: false,
|
||||
isThinking: false,
|
||||
});
|
||||
@@ -1520,6 +1520,7 @@ export class ChatView extends ItemView {
|
||||
shouldFallbackToReadTools = true;
|
||||
|
||||
// Suppress the model's "Let me..." text — clear it from the DOM immediately
|
||||
const priorResponse = fullResponse;
|
||||
fullResponse = '';
|
||||
this.updateMessageById(assistantMessageId, {
|
||||
content: '',
|
||||
@@ -1527,43 +1528,27 @@ export class ChatView extends ItemView {
|
||||
isThinking: false,
|
||||
});
|
||||
|
||||
// Try aggressive retry loop first (hidden from user)
|
||||
let attempts = 0;
|
||||
const maxAttempts = 3;
|
||||
let currentMessages: OllamaMessage[] = [...messagesWithMemory];
|
||||
let currentResponse = '';
|
||||
|
||||
while (attempts < maxAttempts && toolCalls.length === 0) {
|
||||
attempts++;
|
||||
this.showActivityIndicator(
|
||||
attempts === 1 ? 'Thinking…' : `Retrying (${attempts}/${maxAttempts})…`
|
||||
);
|
||||
|
||||
// Build nudge messages — skip empty assistant content to avoid API issues
|
||||
// Single nudge — only when the model actually expressed intent to act.
|
||||
// Lying to models that never mentioned action ("you said you would...") confuses
|
||||
// them and wastes a full LLM round-trip without benefit.
|
||||
if (modelMentionedActions) {
|
||||
this.showActivityIndicator('Thinking…');
|
||||
const nudgeMessages: OllamaMessage[] = [
|
||||
...currentMessages,
|
||||
...(currentResponse.trim()
|
||||
? [{ role: 'assistant' as const, content: currentResponse }]
|
||||
: []),
|
||||
...messagesWithMemory,
|
||||
...(priorResponse.trim() ? [{ role: 'assistant' as const, content: priorResponse }] : []),
|
||||
{
|
||||
role: 'user',
|
||||
content:
|
||||
attempts === 1
|
||||
? 'You indicated you would take action but did not emit any tool_calls. Emit the required tool_calls now. Do not output explanatory text.'
|
||||
: 'You still have not emitted any tool_calls. Remember: when you need vault information, you MUST call tools immediately. Emit the tool_calls now. No text.',
|
||||
'You indicated you would take action but did not emit any tool_calls. Emit the required tool_calls now. Do not output explanatory text.',
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
const nudgeStream = activeClient.streamChat(nudgeMessages, tools);
|
||||
currentResponse = '';
|
||||
let nudgeResponse = '';
|
||||
for await (const chunk of nudgeStream) {
|
||||
if (chunk.content) {
|
||||
currentResponse += chunk.content;
|
||||
}
|
||||
if (chunk.tool_calls) {
|
||||
toolCalls = [...toolCalls, ...chunk.tool_calls];
|
||||
}
|
||||
if (chunk.content) nudgeResponse += chunk.content;
|
||||
if (chunk.tool_calls) toolCalls = [...toolCalls, ...chunk.tool_calls];
|
||||
}
|
||||
|
||||
if (toolCalls.length > 0) {
|
||||
@@ -1572,31 +1557,27 @@ export class ChatView extends ItemView {
|
||||
toolCalls,
|
||||
nudgeMessages,
|
||||
tools,
|
||||
currentResponse,
|
||||
nudgeResponse,
|
||||
assistantMessageId
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// Stream failed during retry — stop retrying and fall back to automatic tools
|
||||
break;
|
||||
// Stream failed — fall through to auto tool calls
|
||||
}
|
||||
}
|
||||
|
||||
currentMessages = nudgeMessages;
|
||||
}
|
||||
|
||||
// If retries all failed, force automatic read tools immediately
|
||||
// Auto tool calls: fire immediately when the user's request implies vault operations
|
||||
// and the model (with or without nudging) still hasn't called any tools.
|
||||
if (toolCalls.length === 0) {
|
||||
const autoToolCalls = this.buildAutomaticReadToolCalls(actualMessage, tools);
|
||||
if (autoToolCalls.length > 0) {
|
||||
this.showActivityIndicator('Using tools…');
|
||||
toolCalls = autoToolCalls;
|
||||
fullResponse = '';
|
||||
await this.processToolCalls(
|
||||
autoToolCalls,
|
||||
messagesWithMemory,
|
||||
tools,
|
||||
fullResponse,
|
||||
'',
|
||||
assistantMessageId
|
||||
);
|
||||
}
|
||||
@@ -1733,25 +1714,15 @@ export class ChatView extends ItemView {
|
||||
'files',
|
||||
'continue',
|
||||
'go ahead',
|
||||
'start',
|
||||
'proceed',
|
||||
'do it',
|
||||
'execute',
|
||||
'run',
|
||||
'proceed',
|
||||
'next',
|
||||
'now',
|
||||
'yes',
|
||||
'ok',
|
||||
'okay',
|
||||
'sure',
|
||||
'please',
|
||||
'step',
|
||||
'implement',
|
||||
'apply',
|
||||
'merge',
|
||||
'clean',
|
||||
'fix',
|
||||
'update',
|
||||
'implement',
|
||||
'apply',
|
||||
];
|
||||
return operationPhrases.some((phrase) => lower.includes(phrase));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user