Welcome back! In Chapter 2: Custom Tip Overrides, we learned how to force the system to show specific messages.
However, for most users, we don't want to force messages. We want the system to be smart. We want it to "know" what the user is doing and offer help that makes sense right now.
This brings us to the Contextual Relevance Engine.
In Chapter 1, we created a registry full of tips. But if we just pick a random tip, we might look foolish.
Imagine a user working on a Windows computer, writing Python code.
We need a logic layer that acts like a Bouncer at a Club.
Let's solve a specific problem. We have a tip suggesting a "Frontend Design Plugin."
The Rule:
.html or .css file..python or .sql file.
To achieve this, we use the isRelevant function inside our Tip Object.
To build this engine, we rely on three specific signals.
These are things that rarely change during a session.
These change every time the user presses a key or runs a command.
index.html)
The engine expects a simple true (Show it!) or false (Hide it!).
Let's look at how we write this logic inside a tip. We define an async function called isRelevant.
Here is a tip that should only appear for Mac users.
{
id: 'paste-images-mac',
content: async () => 'Use Cmd+V to paste images',
// The Bouncer Logic
isRelevant: async () => {
// Check our helper function for the platform
return getPlatform() === 'macos'
}
}
If getPlatform() returns 'windows', isRelevant becomes false, and the user never sees this tip.
Now let's look at our "Frontend Helper" use case. The isRelevant function receives a context argument containing details about the current state.
{
id: 'frontend-design-plugin',
content: async () => 'Try the frontend-design plugin!',
// context contains information about the current file
isRelevant: async (context) => {
// A Regex to look for .html or .css
const isFrontendFile = /\.(html|css|htm)$/i
// Check if the current file matches
return isFrontendFile.test(context.filePath)
}
}
How does the system process these checks? It happens every time the application requests tips.
Let's look at tipRegistry.ts to see the engine in action.
First, we define what information is available to the tips.
// type definitions (simplified)
export type TipContext = {
// The file currently being edited/read
readFileState?: FileState
// Tools currently active (like npm, git)
bashTools?: Set<string>
}
getRelevantTips)This is the heart of the engine. It takes the list of all tips and filters them.
export async function getRelevantTips(context?: TipContext): Promise<Tip[]> {
// 1. Load all potential tips
const tips = [...externalTips]
// 2. Run the "Bouncer" check for ALL tips in parallel
// This results in an array like [true, false, true, false...]
const isRelevantResults = await Promise.all(
tips.map(tip => tip.isRelevant(context))
)
// 3. Keep only the tips that returned 'true'
const allowedTips = tips.filter((_, index) => isRelevantResults[index])
// ... (History checking happens next)
return allowedTips
}
Sometimes the checks involve multiple steps. Look at this example from the source code regarding VS Code Commands.
We only want to tell the user to install the code command if:
{
id: 'vscode-command-install',
// ... content ...
async isRelevant() {
// Check 1: Must be VS Code terminal
if (!isSupportedVSCodeTerminal()) return false
// Check 2: Must be Mac
if (getPlatform() !== 'macos') return false
// Check 3: Is it already installed?
// If installed, we return false (don't show tip)
return !(await isVSCodeInstalled())
},
}
This ensures we don't annoy users by telling them to install something they already have!
The Contextual Relevance Engine is the filter that makes our tips feel intelligent.
However, even if a tip is relevant (e.g., "Use Cmd+V"), we shouldn't show it every single time the user opens the app. That would be annoying.
We need a memory system to remember: "I already told them this yesterday."
Next Chapter: Session History Tracking
Generated by Code IQ