In the previous chapter, Persistent Disk Storage, we learned how to act as a "Diligent Archivist," safely storing massive amounts of log data into files on the hard drive.
However, we now face a new problem. Our "CEO" (the Artificial Intelligence or the API User) needs to understand what happened in those logs. But AI models have a Token Limit (a limit on how much text they can read at once). If we try to feed a 500-page log file into an AI to ask "Why did this fail?", the AI will crash or reject the request because the input is too large.
We need a way to summarize the data before sending it. Welcome to Output Formatting and Truncation.
Imagine you are an Executive Summary Writer. The CEO (the AI) is extremely busy. They do not have timeβand physically cannot hold the paperβto read a 10,000-line transcript of a software installation.
If the installation failed, the CEO only cares about the last few lines, because that is usually where the error message prints.
Your job is to:
"The AI needs to analyze a task failure." The task generated 5MB of text. The AI context window only allows for roughly 30KB. We must intelligently shorten the text to fit the window while preserving the critical error information at the end.
To solve this, we use a utility layer that enforces three rules:
This functionality is exposed through a single, simple function: formatTaskOutput.
You simply pass the raw (potentially huge) string and the Task ID into the formatter.
import { formatTaskOutput } from './outputFormatting';
const hugeLog = "...[1 million characters]... Error: File not found.";
const taskId = "task-123";
// Format it for the AI
const result = formatTaskOutput(hugeLog, taskId);
Explanation: The formatter takes the heavy input and prepares it.
The function returns an object telling you what happened.
console.log(result.wasTruncated); // true
console.log(result.content);
Output:
[Truncated. Full output: /tmp/task-123.output]
... Error: File not found.
Explanation: Notice the header. It points to the file path we created in Persistent Disk Storage. The AI now knows: "I am looking at a partial view, but the full file exists at this path."
Let's visualize the decision process of the "Executive Summary Writer."
The logic is contained in outputFormatting.ts. Let's break down the code to see how it calculates the cut.
First, we determine how big the "summary" is allowed to be. We check environment variables, but keep it within safe bounds (defaults to 32,000 characters).
export function getMaxTaskOutputLength(): number {
return validateBoundedIntEnvVar(
'TASK_MAX_OUTPUT_LENGTH', // Env var name
process.env.TASK_MAX_OUTPUT_LENGTH,
32_000, // Default
160_000, // Absolute Hard Limit
).effective
}
Explanation: We use a validator helper. It ensures the user doesn't set a limit that is too small (useless) or too big (crashes the AI).
This is the core logic. It decides if we need to cut, and where to cut.
export function formatTaskOutput(output: string, taskId: string) {
const maxLen = getMaxTaskOutputLength()
// Scenario A: The output fits perfectly. Do nothing.
if (output.length <= maxLen) {
return { content: output, wasTruncated: false }
}
// Scenario B: It's too big. We need to truncate.
// ... (continue to next block)
Explanation: This is the efficiency check. If the log is short, we return it immediately.
If we must truncate, we calculate exactly how much space the "Pointer Header" takes, subtract that from our limit, and fill the rest with the log's tail.
// 1. Create the pointer header
const filePath = getTaskOutputPath(taskId)
const header = `[Truncated. Full output: ${filePath}]\n\n`
// 2. How much space is left for actual content?
const availableSpace = maxLen - header.length
// 3. Keep only the END of the string
const truncated = output.slice(-availableSpace)
// 4. Stitch them together
return { content: header + truncated, wasTruncated: true }
}
Explanation:
getTaskOutputPath(taskId): Retrieves the path managed by the storage layer.output.slice(-availableSpace): The negative number tells JavaScript to start counting from the end of the string. This ensures we keep the most recent logs.In this chapter, we learned:
Congratulations! You have completed the Task Project tutorial series. Let's recap the journey of a task through our system:
You now have a complete understanding of how to build a robust, persistent, and AI-ready task management system!
Generated by Code IQ