Welcome back! In Chapter 1: User Message Routing, we built our "Switchboard" to decide which component handles a message.
Now, we face a new problem: Information Overload.
Imagine you ask the AI to "Find all references to User in the codebase."
To do this, the AI might:
If we displayed all this raw data in the chat, you would have to scroll for minutes just to find the AI's final answer. The chat becomes unusable.
We need a way to summarize data. Instead of showing the raw content of 50 files, we want to show a single line:
"Read 3 files, searched for 'User'"
This concept is handled by two main components in our project:
Let's look at a concrete example. The AI reads a file named utils.ts.
Read utils.ts (500 lines).Here is how the system processes high-volume data into a summary.
The component AttachmentMessage.tsx handles discrete pieces of data. It takes a raw data object and turns it into a readable one-liner.
Just like our Router in Chapter 1, this component looks at the type of the data.
// AttachmentMessage.tsx
export function AttachmentMessage({ attachment }) {
// Check what kind of data this is
switch (attachment.type) {
case 'directory':
return <Line>Listed directory {attachment.displayPath}</Line>;
case 'file':
// ... logic for files ...
// ... other cases ...
}
}
Explanation: The component is a simple list of instructions. If the data is a directory listing, print "Listed directory".
If the attachment is a file, we don't show the code. We calculate metadata (like line counts or file size) and display that instead.
case 'file':
return (
<Line>
Read <Text bold>{attachment.displayPath}</Text> (
{attachment.content.type === 'text'
? `${attachment.content.file.numLines} lines`
: formatFileSize(attachment.content.file.originalSize)}
)
</Line>
);
Explanation:
displayPath) in bold.numLines).
Sometimes, actions happen in a batch. The component CollapsedReadSearchContent.tsx is responsible for aggregating these counters.
Instead of rendering text immediately, this component receives a message object that contains counters (integers) for different activities.
// CollapsedReadSearchContent.tsx
export function CollapsedReadSearchContent({ message }) {
// Destructure the raw counts from the message object
const {
searchCount,
readCount,
listCount,
bashCount
} = message;
// ... Logic to build the summary string ...
}
Explanation: The system has already done the counting for us. We just need to grab variables like readCount (e.g., equals 5) and searchCount (e.g., equals 1).
We want to construct a natural English sentence like "Searched for 'foo', read 2 files". We do this by building an array of text parts.
const parts = []; // We will push text fragments here
if (searchCount > 0) {
parts.push(
<Text>Searched {searchCount} patterns</Text>
);
}
if (readCount > 0) {
// Add a comma if we already have parts
if (parts.length > 0) parts.push(<Text>, </Text>);
parts.push(
<Text>Read {readCount} files</Text>
);
}
Explanation:
searchCount is greater than 0. If so, add "Searched X patterns".readCount. If we already added search text, we add a comma , first for grammar.The final render simply joins these parts together.
return (
<Box flexDirection="row">
<Text dimColor>
{parts}
{/* Visual cue that this can be opened */}
<Text> โฆ </Text>
<CtrlOToExpand />
</Text>
</Box>
);
Explanation:
parts: Our constructed sentence ("Searched 1 pattern, read 2 files").โฆ: Indicates there is more content hidden.<CtrlOToExpand />: A helper component telling the user they can press Ctrl+O to see the full raw logs if they really need to.In this chapter, we covered Data Summarization:
readCount, searchCount) into a readable, natural language sentence.By acting as a "Compression Layer," we ensure the user sees the flow of the AI's work without drowning in the details.
However, simply summarizing text isn't always enough. Sometimes, the AI is "thinking" or planning complex tasks. In the next chapter, we will see how we represent the AI's internal thought process.
Next Chapter: Cognitive Visualization
Generated by Code IQ