Welcome to Chapter 3! In the previous chapter, React-based Command Implementation, we built the visual menu and the basic logic for the model command.
We can now accept user input, but we have a new problem. Trust.
Just because a user types claude model super-secret-god-mode, it doesn't mean:
This chapter is about Governance. It is the layer of logic that acts as a gatekeeper before we actually change the system configuration.
Imagine entering a high-security office building. You don't just walk into the CEO's office. You pass through several checkpoints:
In our code, this happens inside the SetModelAndClose component we saw earlier. Let's break down these checkpoints.
Enterprises often restrict which AI models employees can use to ensure data compliance. We check this first. If your org says "No," we stop immediately.
Inside our command's logic:
// model.tsx
import { isModelAllowed } from '../../utils/model/modelAllowlist.js';
// ... inside the effect
if (model && !isModelAllowed(model)) {
// โ STOP: Org policy blocks this
onDone(`Model '${model}' is not available. Your organization restricts selection.`, {
display: 'system'
});
return;
}
isModelAllowed: This utility checks a central configuration file (allowlist) defined by the system administrator.return: We exit the function immediately. We do not proceed to API validation.Some features, like the massive 1 Million Token Context Window, are exclusive to specific account tiers. Even if the model exists, you might not be allowed to drive it.
We check for specific suffixes (like [1m]) and verify account permissions.
// model.tsx
// Check for Opus 1M access
if (model && isOpus1mUnavailable(model)) {
onDone(`Opus 4.6 with 1M context is not available for your account.`, {
display: 'system'
});
return;
}
This helper function hides the complex logic:
opus and [1m]?checkOpus1mAccess() return true?
Users hate typing claude-3-opus-20240229. They just want to type opus.
We maintain a list of "Known Aliases." If the user types a known shortcut, we skip the expensive API validation call because we know opus maps to a valid model internally.
// model.tsx
import { MODEL_ALIASES } from '../../utils/model/aliases.js';
function isKnownAlias(model: string): boolean {
return MODEL_ALIASES.includes(model.toLowerCase().trim());
}
// In the main logic:
if (isKnownAlias(model)) {
// โ
PASS: It's a trusted shortcut
setModel(model);
return;
}
This makes the CLI feel snappy. We don't need to ask the server "Is 'opus' real?" because our internal dictionary says "Yes."
If the user typed something custom that isn't on our blocklist, isn't a special feature, and isn't a known alias (e.g., a brand new model ID claude-3-5-sonnet-new), we ask the API.
// model.tsx
import { validateModel } from '../../utils/model/validateModel.js';
// ... inside try/catch
const { valid, error } = await validateModel(model);
if (valid) {
// โ
PASS: The API confirmed this exists
setModel(model);
} else {
// โ FAIL: The API has never heard of this
onDone(error || `Model '${model}' not found`);
}
This is an asynchronous operation. It's the "heaviest" check, which is why we save it for last.
Let's visualize the journey of a string text args when passed to SetModelAndClose.
All of this logic is wrapped inside a React useEffect hook within model.tsx.
Why useEffect?
Because validation is a side effect. We can't validate during the render phase (drawing the UI). We must render the component first (which is invisible/null), then run the async validation checks, and finally trigger the onDone callback or update the state.
// model.tsx (Simplified Structure)
function SetModelAndClose({ args, onDone }) {
// 1. Get the setter for global state
const setAppState = useSetAppState();
// 2. Run validation logic when component mounts
React.useEffect(() => {
async function runChecks() {
// ... Run Checkpoints 1, 2, 3, 4 ...
// If all pass:
setAppState(prev => ({ ...prev, mainLoopModel: args }));
onDone(`Success!`);
}
runChecks();
}, [args]); // Re-run if args change
return null; // Don't draw anything
}
There is one special keyword: default.
If args === 'default', we bypass most checks and set the model to null.
When the model is null, the system falls back to its hardcoded standard model (e.g., Claude 3.5 Sonnet).
In this chapter, we learned that accepting user input requires rigorous checking:
isModelAllowed).isOpus1mUnavailable).isKnownAlias) for speed.validateModel) for correctness.Once a model passes all these gates, we are finally allowed to update the global configuration. But where does that configuration live? And how do other parts of the app know it changed?
Next Chapter: Application State Management
Generated by Code IQ