Welcome to the final chapter of our ConfigTool tutorial!
We have a fully functional tool. It can read, write, validate, and save settings. However, there is one problem: it is invisible.
If the AI changes a setting and the tool runs silently, the user (you) won't know if it worked, if it failed, or if it's still thinking. We need to close the loop with Visual Feedback Components.
Imagine driving a modern car. You press the button for "Sport Mode."
Without that light, you would have to guess if the button worked.
In ConfigTool, the Visual Feedback Components act as that dashboard light. They handle the communication between the code (which is invisible) and the Command Line Interface (CLI) that the user sees.
We use a library called Ink (React for the CLI) to render text. We classify feedback into three distinct states:
By splitting these up, the user follows the story of the operation.
We define these visual components in UI.tsx. Let's look at how we handle the different stages of a command.
When the AI decides to call the tool, we show a message immediately. This tells the user, "Hey, I'm working on this!"
We use renderToolUseMessage.
// inside UI.tsx
export function renderToolUseMessage(input: Partial<Input>) {
// 1. If we are just READING a setting
if (input.value === undefined) {
return <Text dimColor>Getting {input.setting}</Text>;
}
// 2. If we are WRITING a setting
return <Text dimColor>
Setting {input.setting} to {jsonStringify(input.value)}
</Text>;
}
Explanation:
theme), we print "Getting theme".theme, dark), we print "Setting theme to 'dark'".dimColor (grey text) because this is background info, not the main result.
Once the logic (from Chapter 3) finishes, we need to report what happened. We use renderToolResultMessage.
// inside UI.tsx
if (content.operation === 'get') {
// We just read a value
return <MessageResponse>
<Text>
<Text bold>{content.setting}</Text> = {jsonStringify(content.value)}
</Text>
</MessageResponse>;
}
Explanation: This renders a clean output like theme = "dark".
If we actually modified a file, the message looks slightly different to emphasize the change.
return <MessageResponse>
<Text>
Set <Text bold>{content.setting}</Text> to{' '}
<Text bold>{jsonStringify(content.newValue)}</Text>
</Text>
</MessageResponse>;
Explanation: This renders: Set theme to "dark". The bold text helps the user scan the log quickly to see what changed.
If the Registry or Validation Logic rejects the request, we must show it clearly in red.
// inside UI.tsx
if (!content.success) {
return <MessageResponse>
{/* "error" color usually renders as Red in terminals */}
<Text color="error">Failed: {content.error}</Text>
</MessageResponse>;
}
Explanation: If the AI tries to set the theme to "Pizza", this component catches the success: false flag and prints "Failed: Invalid option" in red text.
How do these components fit into the actual flow of the application? Let's visualize the lifecycle of a single command.
You might have noticed jsonStringify in the code examples. Why do we need that?
In programming, true (boolean) and "true" (string) are different.
Set verbose to true vs Set theme to true (hard to tell the type).Set verbose to true (boolean) vs Set theme to "true" (string).import { jsonStringify } from '../../utils/slowOperations.js';
// It wraps strings in quotes, but keeps numbers/booleans raw
// Example: "dark" -> '"dark"'
// Example: true -> 'true'
Why this matters: It reduces confusion. The user knows exactly what data type was saved to the configuration file.
We have now built the entire ConfigTool system!
supportedSettings.ts).global vs settings).Here is what the final output looks like in the terminal when an AI Agent uses our tool.
User: "Please turn on verbose mode."
Terminal Output:
(dim) Setting verbose to true...
Set verbose to true
User: "Set the theme to neon-green."
Terminal Output:
(dim) Setting theme to "neon-green"...
(red) Failed: Invalid value. Options are: dark, light, dracula
Visual Feedback Components are the bridge between machine logic and human understanding. By providing clear "Intent" messages (what I'm doing) and "Result" messages (what I did), we build trust with the user. They never have to wonder if the AI actually clicked the button.
Congratulations! You have completed the ConfigTool tutorial series. You now understand how to build a robust, safe, and user-friendly configuration management tool for AI agents.
Generated by Code IQ