Welcome back! In Forked Agent Execution, we learned how to spawn a "Sous-Chef" (a sub-agent) to observe our main AI and write a summary.
However, we have a small problem. We can't just throw the entire raw conversation history at the Sous-Chef. The Main Agent might be in the middle of a messy operation.
In this chapter, we will learn about Transcript Sanitization.
Imagine you want to take a photograph of your friend jumping into a pool to post on Instagram (the Summary).
If you show the "Messy Shot" to people, they won't say "Cool pool party." They will ask, "Is your friend okay?"
In our AI system:
readFile), but the system hasn't finished reading the file yet.If we send this "Messy Shot" to our summarizer, it gets confused. Instead of summarizing the work, it might say: "I am waiting for a file to load" or "I see a half-finished command."
Transcript Sanitization is the digital photo editor that removes the blurry parts before we show the image to the summarizer.
The Transcript is the log of every single message, thought, and tool call the Main Agent has made since it started the task. It grows constantly.
A "Pending State" happens when the AI says: "I want to run npm test", but the computer hasn't responded with the test results yet. This looks like an open bracket [ without a closing bracket ].
This is the process of retrieving the transcript and actively filtering out these incomplete interactions. We want to show the summarizer only the history that has settled.
We perform this cleaning process inside our runSummary loop (which we built in Chapter 1).
First, we need to grab the latest logs from the storage. We use the agentId to find the correct session.
import { getAgentTranscript } from '../../utils/sessionStorage.js'
// Inside runSummary...
const transcript = await getAgentTranscript(agentId)
// Safety check: Do we have enough data to summarize?
if (!transcript || transcript.messages.length < 3) {
console.log("Not enough data yet...")
return
}
This is the core of this chapter. We pass the raw messages through a filter function.
import { filterIncompleteToolCalls } from '../../tools/AgentTool/runAgent.js'
// Remove the "blurry" parts
const cleanMessages = filterIncompleteToolCalls(transcript.messages)
console.log(`Raw: ${transcript.messages.length}, Clean: ${cleanMessages.length}`)
In Forked Agent Execution, we talked about the "Ingredients" (parameters) for our Sous-Chef. Now we replace the old, stale ingredients with our fresh, clean ones.
// Create a new parameter object for the fork
const forkParams: CacheSafeParams = {
...baseParams, // Keep the system prompts/settings
forkContextMessages: cleanMessages, // INSERT CLEAN DATA HERE
}
Now, when we call runForkedAgent, it sees a perfectly tidy history.
Let's visualize exactly what happens when the timer ticks.
Let's look at how the filterIncompleteToolCalls function conceptually works. You don't need to write this (it's part of the core), but it helps to understand it.
The function looks at the end of the conversation list.
If the answer to #3 is "No" (because the tool is still running), then the Assistant's message is "dangling." The sanitizer cuts it off.
// Conceptual logic of the filter
export function filterIncompleteToolCalls(messages: Message[]): Message[] {
const lastMsg = messages[messages.length - 1]
// If the last thing happening is a tool call...
if (lastMsg.type === 'assistant' && hasToolCall(lastMsg)) {
// ...and there is no result following it...
// REMOVE IT.
return messages.slice(0, -1)
}
return messages
}
If we didn't do this, the Forked Agent would receive the tool call (e.g., list_files) but see no files listed.
It might hallucinate and say:
"I listed the files and found nothing." (Incorrect!)
With sanitization, it sees the history before the tool call and says:
"I have decided to list the files." (Correct!)
Let's verify where this fits in our agentSummary.ts file.
// agentSummary.ts inside runSummary()
try {
// 1. Get the raw history
const transcript = await getAgentTranscript(agentId)
// 2. Clean it up
const cleanMessages = filterIncompleteToolCalls(transcript.messages)
// 3. Prepare the fork
const forkParams = { ...baseParams, forkContextMessages: cleanMessages }
// 4. Run the fork (As seen in Chapter 2)
await runForkedAgent({ cacheSafeParams: forkParams, ... })
} catch (e) {
// Handle errors...
}
You have now mastered Transcript Sanitization.
You learned that:
Now our Sous-Chef has a clean kitchen and fresh ingredients. But wait! Even though the history is clean, the Sous-Chef itself still has access to knives and fire (Tools). We need to make sure the summarizer doesn't accidentally delete your project while trying to summarize it.
In the next chapter, we will learn how to lock down the kitchen.
Next Chapter: Tool Governance (Denial)
Generated by Code IQ