Welcome to the final chapter of our tutorial series!
In the previous chapter, Completion Boundaries, we built a safety system to stop the AI from performing dangerous actions (like deleting files) without your permission.
However, safety isn't just about preventing dangerous actions; it's also about preventing annoying noise.
The AI is a chatty entity. If we ask it to "predict the next command," it might reply with:
"I think you should run
npm test. Would you like me to do that?"
If we put that entire sentence into the user's command line, it would break their terminal. We want just:
npm test
Heuristic Filtering & Suppression is the quality control layer. It acts like a spam filter for the AI's internal thoughts, ensuring only high-quality, executable commands reach the user's screen.
Imagine you are focused on writing code. You want a tool that quietly hands you the screwdriver when you need it.
Instead, the tool yells: "HERE IS A SCREWDRIVER! IT IS A PHILLIPS HEAD! I HOPE THIS HELPS!"
This breaks your flow. In PromptSuggestion, a "bad" suggestion isn't just one that is wrong; it is one that is formatted like a conversation.
We need to filter out:
The filtering process happens in two stages: Pre-Generation (checking the environment) and Post-Generation (checking the text).
Before we even wake up the AI, we check if we should bother. This saves money and computing power.
We check these conditions in promptSuggestion.ts.
We shouldn't offer suggestions if the user is running a script or if the AI is "busy" waiting for a different permission.
// promptSuggestion.ts
export function getSuggestionSuppressReason(appState) {
// 1. Is the feature turned off?
if (!appState.promptSuggestionEnabled) return 'disabled';
// 2. Is the AI currently waiting for the user to approve a file edit?
if (appState.pendingWorkerRequest) return 'pending_permission';
// 3. Are we out of API credits?
if (currentLimits.status !== 'allowed') return 'rate_limit';
return null; // No reason to suppress! Go ahead.
}
Explanation:
This function returns null if everything is good. If it returns a string (like 'rate_limit'), we stop immediately. This prevents the system from annoying the user when it can't actually help.
If we pass Stage 1, the AI generates a string. Now we must inspect it. The AI might output garbage even with a perfect prompt.
We use a series of Heuristic Rules defined in shouldFilterSuggestion.
Commands are usually short. If the AI outputs a paragraph, it's talking, not suggesting.
// promptSuggestion.ts
// A simple heuristic: Users rarely type commands longer than 12 words.
const wordCount = suggestion.trim().split(/\s+/).length;
if (wordCount > 12) {
return true; // Filter this out!
}
Large Language Models love to be polite. They often start sentences with "I think" or "Here is". We use Regular Expressions (Regex) to catch these patterns.
// promptSuggestion.ts
// Common phrases AI uses when it forgets it's a CLI tool
const claudeVoiceRegex = /^(let me|i'll|i'm|i think|here's|you should)/i;
if (claudeVoiceRegex.test(suggestion)) {
logSuggestionSuppressed('claude_voice', suggestion);
return true; // Filter this out!
}
Explanation: If the suggestion is "I think you should run git status", this regex matches "I think". We catch it and block it. The user sees nothing.
Sometimes, we tell the AI: "If you don't know what to do, say nothing."
However, the AI might literally output the word: "Nothing".
// promptSuggestion.ts
const lower = suggestion.toLowerCase();
// Did the AI literally say it has no suggestion?
if (lower === 'nothing found' || lower === 'silence') {
return true;
}
To keep our code clean, we organize these rules into a list of checks. We loop through them, and if any rule says "Bad," we toss the suggestion.
// promptSuggestion.ts
export function shouldFilterSuggestion(suggestion) {
// Define our list of police officers
const filters = [
['too_many_words', () => suggestion.split(' ').length > 12],
['claude_voice', () => /^(here is|let me)/i.test(suggestion)],
['error_message', () => suggestion.includes('api error')],
['evaluative', () => /^(looks good|thanks)/i.test(suggestion)]
];
// Run the gauntlet
for (const [reason, check] of filters) {
if (check()) {
// Log why we killed it (for analytics)
logSuggestionSuppressed(reason, suggestion);
return true; // STOP!
}
}
return false; // The suggestion is clean!
}
Explanation:
This design makes it easy to add new rules. If we notice the AI starting to say "Alakazam!" before every command, we just add a new ['magic_words', ...] rule to the list.
Here is how the main engine uses these filters. This logic resides in the tryGenerateSuggestion function.
// promptSuggestion.ts
export async function tryGenerateSuggestion(...) {
// STAGE 1: Suppression
const suppressReason = getSuggestionSuppressReason(appState);
if (suppressReason) return null;
// Generate the text (using Forked Agent from Chapter 3)
const { suggestion } = await generateSuggestion(...);
// STAGE 2: Filtering
if (shouldFilterSuggestion(suggestion)) {
return null; // It was garbage, hide it.
}
// If we survived all that, show it to the user!
return { suggestion };
}
You might notice logSuggestionSuppressed in the code. We don't just delete bad suggestions; we record why they were bad.
If we see that 50% of suggestions are being filtered because of "too_many_words," that tells us we need to improve our System Prompt (Chapter 1) to tell the AI to be more concise.
Congratulations! You have completed the PromptSuggestion tutorial series.
We have built a system that:
By combining these abstractions, we create an AI interface that feels magical: it's fast, safe, helpful, and stays out of your way until you need it.
Happy coding!
Generated by Code IQ