Welcome to the final chapter of our TaskListTool journey!
In the previous chapter, Chapter 4: Task Execution & Logic, we built the engine of our tool. We successfully fetched data from the database, cleaned it up, and returned a structured list of tasks.
However, we have a small communication problem.
In Chapter 4, our tool returned data that looked like this:
{
"tasks": [
{ "id": "101", "subject": "Buy Milk", "status": "todo", "blockedBy": [] },
{ "id": "102", "subject": "Walk Dog", "status": "done", "blockedBy": [] }
]
}
While this JSON format is perfect for computers, it is verbose. If we have 50 tasks, that JSON file becomes huge.
{}, quotes "", and repeated field names ("subject":) wastes money and memory.We need a translator that takes that "Spreadsheet" (JSON) and turns it into a "Quick Memo" (Text) for the AI.
The Goal: We want the AI to see this instead:
#101 [todo] Buy Milk
#102 [done] Walk Dog
This is concise, readable, and saves money. To do this, we use a function called mapToolResultToToolResultBlockParam.
We will write this logic inside TaskListTool.ts. It takes the output from Chapter 4 and reformats it.
If the user has no tasks, we shouldn't send an empty blank space. We should explicitly tell the AI, "There is nothing here."
mapToolResultToToolResultBlockParam(content, toolUseID) {
// 'content' is the JSON output from Chapter 4
const { tasks } = content as Output
if (tasks.length === 0) {
return {
tool_use_id: toolUseID,
type: 'tool_result',
content: 'No tasks found',
}
}
// ... formatting continues
Explanation:
content: This is the data object { tasks: [...] } returned by our call() function.'No tasks found'.Now, let's format a single task. We want to combine the ID, Status, and Subject into one line.
// We loop through every task in the list
const lines = tasks.map(task => {
// Check if there is an owner
const owner = task.owner ? ` (${task.owner})` : ''
// Start building the string
let line = `#${task.id} [${task.status}] ${task.subject}${owner}`
// ... blocker logic continues below
Explanation:
tasks.map(...): We run a function on every task to transform it.owner: We use a ternary operator. If task.owner exists, we format it like (Alice). If not, we make it an empty string.line: We use template literals (backticks) to glue the pieces together.If a task is blocked, that is critical information. We need to append it to the line.
// ... inside the map loop
const blocked =
task.blockedBy.length > 0
? ` [blocked by ${task.blockedBy.map(id => `#${id}`).join(', ')}]`
: '' // If no blockers, add nothing
// Return the full text line
return line + blocked
})
Explanation:
task.blockedBy.length.[blocked by #101, #102].We now have an array of strings (lines). We need to join them into one big paragraph to send to the AI.
// ... after the map loop finishes
return {
tool_use_id: toolUseID,
type: 'tool_result',
// Join all lines with a 'newline' character (\n)
content: lines.join('\n'),
}
},
Explanation:
lines.join('\n'): This takes our list of strings and puts them one after another, separated by a line break.tool_use_id: We must pass this back so the AI knows which question we are answering.Let's visualize the entire journey of a user's request, combining everything we have learned in this project.
Here is the complete implementation of the function inside TaskListTool.ts.
// ... inside TaskListTool object
mapToolResultToToolResultBlockParam(content, toolUseID) {
const { tasks } = content as Output
// 1. Handle Empty State
if (tasks.length === 0) {
return { tool_use_id: toolUseID, type: 'tool_result', content: 'No tasks found' }
}
// 2. Format Lines
const lines = tasks.map(task => {
const owner = task.owner ? ` (${task.owner})` : ''
const blocked = task.blockedBy.length > 0
? ` [blocked by ${task.blockedBy.map(id => `#${id}`).join(', ')}]`
: ''
return `#${task.id} [${task.status}] ${task.subject}${owner}${blocked}`
})
// 3. Return Text
return {
tool_use_id: toolUseID,
type: 'tool_result',
content: lines.join('\n'),
}
},
Congratulations! You have built a fully functional AI Tool from scratch.
Let's recap what we built:
You now have a tool that is safe, smart, logical, and communicative. You can use these principles to build tools for anythingβchecking weather, querying databases, or controlling smart home devices.
Happy Coding!
Generated by Code IQ