Welcome to the final chapter of the ExitPlanModeTool tutorial!
In the previous chapter, Chapter 4: Prompt Engineering, we taught the AI exactly how and when to use the tool using natural language instructions.
Now, we have a fully functional tool. The AI can write a plan, submit it, and change its internal state. But there is one problem: The User Experience.
When the AI "presses the button," what does the human user actually see in their terminal?
Imagine driving a car where the dashboard is covered with duct tape. You press the "Sport Mode" button. The engine might have changed, but without a light on the dashboard, you aren't sure.
In our CLI (Command Line Interface), we don't want to just dump raw JSON text like { "success": true }. We want a beautiful, readable status update.
This chapter is about building the Dashboard. We use a library called Ink (which is React for the terminal) to render different visual components based on what happened inside the tool.
We need to display two distinct states:
Usually, React is used for websites. However, we use it to render text in the terminal.
<div />, we use <Box />.<span />, we use <Text />.This allows us to create structured, colored, and dynamic layouts inside the black command prompt window.
Before we look at the code, let's look at how the data flows from the tool to the screen.
renderToolResultMessage
We define a function that takes the output from our tool and decides what to show.
Sometimes, things go wrong, or the plan is empty. We want a simple, quiet message.
// UI.tsx
const { plan, filePath } = output
const isEmpty = !plan || plan.trim() === ''
if (isEmpty) {
return (
<Box flexDirection="column" marginTop={1}>
<Box flexDirection="row">
<Text color={getModeColor('plan')}>{BLACK_CIRCLE}</Text>
<Text> Exited plan mode</Text>
</Box>
</Box>
)
}
isEmpty. If true, we return a simple <Box> with a colored circle and the text "Exited plan mode". This confirms the action without clutter.Remember Chapter 3: Teammate Approval Protocol? If the user is a junior agent, they might be waiting for approval. We need to clearly show this status.
// UI.tsx
const awaitingLeaderApproval = output.awaitingLeaderApproval
if (awaitingLeaderApproval) {
return (
<Box flexDirection="column" marginTop={1}>
<Box flexDirection="row">
<Text color={getModeColor('plan')}>{BLACK_CIRCLE}</Text>
<Text> Plan submitted for team lead approval</Text>
</Box>
{/* ... See next block for details ... */}
</Box>
)
}
awaitingLeaderApproval. If true, the headline changes to "Plan submitted..." instead of "Approved".
Inside that previous if block, we add more details so the user knows why nothing is happening.
// Inside the waiting block...
<MessageResponse>
<Box flexDirection="column">
{filePath && <Text dimColor>Plan file: {displayPath}</Text>}
<Text dimColor>Waiting for team lead to review and approve...</Text>
</Box>
</MessageResponse>
dimColor (grey text) to show secondary information. This tells the user, "Sit tight, your manager has the file."If the plan wasn't empty, and we aren't waiting for a boss, then the user (or the tool) has successfully approved the plan. This is the default return.
// UI.tsx (The default return)
return (
<Box flexDirection="column" marginTop={1}>
<Box flexDirection="row">
<Text color={getModeColor('plan')}>{BLACK_CIRCLE}</Text>
<Text> User approved Claude's plan</Text>
</Box>
{/* ... Plan details below ... */}
</Box>
)
Finally, strictly for the Success state, we show the user the plan that was just finalized, so they have a record of it.
// Inside the success block...
<MessageResponse>
<Box flexDirection="column">
{filePath && (
<Text dimColor>Plan saved to: {displayPath}</Text>
)}
<Markdown>{plan}</Markdown>
</Box>
</MessageResponse>
<Markdown> component to render the actual text of the plan. This makes headers bold and lists bulleted, right inside the terminal.In this final chapter, we learned how to visualize the result of our tool.
isEmpty and awaitingLeaderApproval to decide which "Dashboard Light" to turn on.Congratulations! You have walked through the entire lifecycle of creating a complex AI capability.
You now understand the anatomy of an advanced AI Agent tool!
Generated by Code IQ