I had the opportunity to attend the Winter Tech Forum (WTF) in Crested Butte, CO last week and I had a blast! As a remote worker, it was an excellent opportunity to engage and interact with an awesome group of 30ish attendees.
This unconf or open space conference is setup with sessions most mornings and workshops or free time in the afternoon, but on Wednesday it's a hack day with the sharing of results in the evening.
All of this wouldn't happen without Bruce Eckel, who also graciously opened his home to sessions and hacking on code.
Hacking on AI
While many of the groups sought out implementing layers over the Model Context Protocol, I decided to explore agents and Apps Script (aka tool calling in a loop given a prompt).
Understanding the Agent Loop
At the heart of my project is the agent loop, a process that enables AI to reason and act autonomously. Here’s a breakdown of the steps:
- Initial Prompt and Instructions: It all starts with a user prompt and system instructions, setting the stage for the AI's task.
- Tool Definitions: We define the tools the agent can use, such as searching Gmail or creating draft replies.
- Vertex AI Tool Calls: Vertex AI is called to determine which tool(s) should be used based on the prompt.
- Tool Execution: The selected tool is executed, performing the necessary action.
- Context Update: The tool's results are added back to the context, allowing the AI to learn and adapt.
-
Looping: This process repeats until all required tools are called or a
doNothing()
function is triggered, indicating the task is complete.
I encountered a fascinating challenge during this process: occasional redundant tool calls. Specifically, the createDraftReply()
function was sometimes invoked multiple times within different loops. The shortcut solution was to simply remove this from the available function calls once it had been done. I also had success by asking Gemini to plan before doing anything else.
Exploring the Gmail API with searchGmail
One of the key tools I exposed was the searchGmail
function, which leverages the Gmail API. This function allows the agent to search for related Gmail threads and messages using a flexible query syntax. Here's a glimpse of the JSON definition:
{
"name": "searchGmail",
"description": "Search for related Gmail threads and messages. The Gmail query syntax is described here: https://developers.google.com/gmail/api/guides/query. Here are some examples: 'in:inbox after:2025-01-01', 'subject:invoice', ...",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Gmail search query"
}
},
"required": ["query"]
}
}
This tool empowers the AI to find relevant information within Gmail, enabling more context-aware actions.
Tool Calling and Zod Validation
To manage the tool-calling process, I iterated through the Vertex AI response, identifying function calls and their arguments. Here’s a snippet of the code:
const functionReponsePart: FunctionResponsePart[] =
content.parts
.filter(isFunctionCallPart)
.map((part) => {
const name = part.functionCall.name;
const args = part.functionCall.args;
if (name === "doNothing") {
isDone = true;
}
// ...
I also used Zod for runtime type checking (and generating the tool schemas for Vertex), ensuring the arguments passed to the functions were valid. Interestingly, I never encountered a validation failure, which speaks to the reliability of Vertex AI's output.
const { fn, schema } = FUNCTIONS[name];
const content = fn(schema.parse(args), {
thread,
threadId: thread.getId(),
});
return {
functionResponse: {
name,
response: {
content,
},
},
};
Example Output
To illustrate the agent’s capabilities, here’s an example of the tool calls made when processing an email:
Meeting Agenda - Calling applyLabels with {"labelNames":["Tech"]}
Meeting Agenda - Calling markAsImportant with {"important":false}
Meeting Agenda - Calling createDraftReply with {"reply":"Sounds good!"}
Meeting Agenda - Calling searchGmail with {"query":"from:Justin Poehnelt (Google Docs) subject:Meeting Agenda"}
Meeting Agenda - Calling doNothing with {}
This demonstrates how the agent can perform a sequence of actions, from labeling emails to creating draft replies, all driven by AI.
Apps Script Code
The code for this is available on GitHub at https://github.com/jpoehnelt/apps-script/tree/main/projects/apps-script-agent.
Some things to note:
- I'm using esbuild to bundle my code.
- I'm using @google/clasp to push to Apps Script.
Everything Apps Script
This repository is a monorepo containing tools, projects, and more related to Apps Script.
Let me know if you have any questions on the code!
I'm going back to Winter Tech Forum
Attending this week long event was the best tech related experience I have had in what seems like forever. The atmosphere was one of support, vulnerability, and community growth. Bruce and the veterans of this event were incredibly welcoming to newcomers, no matter our background.
As I reflect back on this experience, I know that I will be doing everything I can to make this an annual retreat for my own well-being and personal growth!
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more