Retool Agentic Workflow with Agent
The following lab demonstrates how to build an agentic workflow that at its heart uses an Agent to examine a support ticket and extract information relevant to the customer experience and issue that needs to be resolved.
Requirements
- Retool Agents (Public Beta)
- Retool Workflows + Multi-step function
Steps
In this example we will leverage an agent to extracting relevant content from support tickets to that a workflow can perform appropriate routing. This includes the issue type (lost bag | missed flight | change flight), traveler type (frequent flyer | standard traveler), and sentiment (positive | negative). The agent results are formatted and returned to the workflow for appropriate routing.
Architecturally, the following diagram shows the Retool Workflows integrating with Retool Agent and LLM provider.

In the image above we start with:
- A Parent Workflow that receives the traveler support issue. It initiates an Agent Workflow, providing the ticket details.
- The Agent Workflow takes the support issue, uses a multi-step function and code block to initiate the New England Air Agent. This agent executes asynchronously and the Agent Workflow polls to see when the agent is complete and extracts the Agent results.
- The New England Air Agent uses a reasoning model (e.g. OpenAI, Anthropic) to interact and extract traveler issue, traveler type, and sentiment.
- The Agent Workflow receives information that the Agent is complete and collects the response.
- The Parent Workflow receives the Agent Workflow response and uses this information to perform intelligent routing.
To begin this lab we are going to work our way from the Agent. We will then develop the Agent Workflow and finish off with the Parent Workflow.
Create Agent
In the first step we develop an Agent that is able to take ticket samples and extract the issue type, traveler type, and sentiment.
- Select Retool Home > Agents(Beta) > New Agent > Start from scratch.
- Enter a name
New England Airlines Agent
, specify the airplane icon, and a colorblue
.

- Next we want to use the Configuration Assistant to prompt what the agent will perform and prescriptively create Tools.
I need you to examine a support ticket's content for routing the ticket appropriately.
Tickets may or may not include information such as traveler type (frequent flyer | standard traveler)
and issue type (lost baggage | missed flight | change flight). In addition we would like to determine
the sentiment of the support ticket (positive | negative). Please return the results of this analysis in JSON format only, with no explanation for example:
{"traveler_type":"frequent_flyer", "issue_type":"lost_baggage","sentiment":"negative"}

- The above prompt will identify a singular tool that will be used to perform the analysis and return a result.
- Select Finish Up to create the tool.
- In Function Generator provide the following prompt:
Create a tool that can process the ticket_content and extract content from the ticket such as traveler type (frequent flyer | standard traveler), issue type (lost baggage | missed flight | change flight), and sentiment of the support ticket (positive | negative). Please return the results of this analysis in JSON format, for example:
{"traveler_type":"frequent_flyer", "issue_type":"lost_baggage","sentiment":"negative"}
- Function generator will recommend the following for the tool:

- Selecting
Accept and Overwrite
will create a completed tool as shown in the following image.

- You can provide various
ticket_content
examples and Test Function to see if results categorize the traveler, issue and sentiment. The following is a sample ticket:
"I have missed my flight and need someone to help me! Your plane was late due to mechanical failure and I am an exclusive frequent flyer on Air New England! This shouldn't be happening. Maybe I should switch to Nantucket Air!"
- Selecting Test Function, will run the Tool and you can examine the result against different tickets. The following image shows the example provided:

- Once satisified, select Done to save the Function logic.
- Select Save to capture the final tool.

Create Agent Workflow
With the agent completed, we develop a workflow that invokes the agent, polls for the results, and results a JSON payload. The following image shows the completed workflow that we will build:

Be aware that Agents when invoked can take 10-20+ seconds to complete. Due to this, when using Workflows, increasing the timeout settings when invoking an Agent or Workflow may be required. The samples below used 30s timeout settings.
Multi-step function to get Agent logs
We will first create a multi-step function in Workflows to get the Agent logs by passing in the agentRunId
.
- Select Functions > +
- Rename function to
getAgentLogs
. - Select + Add parameter and create
agentRunId
andagentId
. - Select Type set to
Multi-step
.

- For the function steps, a param block with
agentRunId
andagentId
is setup by default. - Next we add a Retool Agents block. Set the Agent to
New England Airlines agent
created in the previous section.- Set Input Mode to
JSON
. - Specify in the Agent Inputs text area:
{
"action" : "getLogs",
"agentRunId" : {{ params.agentRunId }}
} - Set Input Mode to
- Finally we have a Response block. The Return body is set to:
requestAgentLogs.data
The following image shows the completed multi-step function.

Agent Workflow
Now we will move to finishing off the Agent Workflow by adding an Invoke Agent block and connecting it to the startTrigger.
- Rename the block to
invokeAirlineAgent
. - Agent set to
New England Airlines agent
. - Input mode kept at
JSON
. - Agent inputs is set to:
{
"action": "invoke",
"messages": [
{
"role": "user",
"content": {{ startTrigger.data.ticket }}
}
]
}
- Next select the circle on the upper right of the invokeAirlineAgent block and create a Code block, named
pollForAgentLogs
.
This code block will use the multi-step function created previously and polling to pull in the agent response. Within the code block enter the following sample.
// Defines the polling interval (500ms), the max number of attempts (30), and the statuses that indicate the agent is still running (PENDING, IN_PROGRESS).
const SLEEP_DURATION_IN_MS = 500;
const MAX_ITERATIONS = 30;
const AGENT_PENDING_STATUSES = ["PENDING", "IN_PROGRESS"];
// A utility function that returns a promise which resolves after 500ms (used for pausing between polls).
const sleep = () => new Promise(resolve => setTimeout(resolve, SLEEP_DURATION_IN_MS));
// Extracts the agentId and agentRunId from the invokeAgent block. Initializes latestAgentStatus as "PENDING". latestAgentLogs will store the last retrieved logs, and iterations tracks the number of attempts.
const { agentId, agentRunId } = invokeAirlineAgent.data;
let latestAgentStatus = "PENDING"; // Initial assumption
let latestAgentLogs;
let iterations = 1;
// Keeps polling as long as the agent is in a pending state and hasn’t exceeded the maximum attempts.
while (AGENT_PENDING_STATUSES.includes(latestAgentStatus) && iterations <= MAX_ITERATIONS) {
console.log(`Beginning iteration ${iterations}/${MAX_ITERATIONS}`);
try {
// Call the multi-step function
const agentLogs = await getAgentLogs(agentRunId, agentId);
console.log({ agentLogs });
latestAgentStatus = agentLogs.data.status;
latestAgentLogs = agentLogs;
} catch (err) {
throw new Error(`Failed to fetch agent logs on iteration ${iterations}: ${err.message}`);
}
// If still pending, wait before the next iteration. If not, exit the loop early.
if (AGENT_PENDING_STATUSES.includes(latestAgentStatus)) {
await sleep();
} else {
break;
}
iterations += 1;
}
// If the status is still not complete after 30 tries, throw an error.
if (AGENT_PENDING_STATUSES.includes(latestAgentStatus)) {
throw new Error(`Agent status is still ${latestAgentStatus} after 30 polling ${MAX_ITERATIONS} attempts.`);
}
// Return the agent response.
return latestAgentLogs;
- Finally we have a Response block that returns the status, resultText, and fullLogsResponse.
{
status: pollForAgentLogs.data?.data?.status,
resultText: pollForAgentLogs.data?.data?.resultText,
fullLogsResponse: pollForAgentLogs.data
}
This should result in the following workflow:

Create Parent Routing Workflow
In this step, we create the parent workflow that will initiate the Agent workflow and take the results to then intelligently route to either an escalated path or standard path. Below is an image of the completed workflow we will build:

Invoke Agent Workflow
To invoke the Agent workflow, we use a Workflow block.
- Create a workflow block by selecting startTrigger circle, specify Workflow block.
- Within the Workflow block, rename it to
invokeAgentWorkflowWithAgent
. - Update the block to the following settings:
- Select Workflow:
Frequent Flyer Agent Workflow with Agent
- Run until
Finished
- Parameters set to Raw
{{startTrigger.data}}
- Select Workflow:
Extract JSON from Agent Workflow response
Next we want to take the Agent workflow result and format into JSON
- Add a Code block to the right of the invokeAgentWorkflowWithAgent and name it
extractJSON
. - Paste the following JavaScript code:
let agentResponse = invokeAgentWorkflowWithAgent.data.resultText;
console.log(agentResponse);
const jsonPayload = JSON.parse(agentResponse.replace(/'/g, '"'));
return jsonPayload;
Route support ticket using Agent workflow response
Once the results are returned to the parent workflow, we have a JSON object that we can branch on through defining different conditional statements.
- Add a Branch block to the right of extractJSON.
- For the If path, enter the following JavaScript code, note the use of toLowerCase() to resolve issues with inputs that come in different cases from LLM.
extractJSON.data.traveler_type.toLowerCase() == "frequent_flyer" && extractJSON.data.sentiment.toLowerCase() == "negative"
Below is the completed workflow:

NOTE: If you run into routing issues, confirm what is being returned by the Agent JSON response. The attributes (e.g., traveler_type, sentiment) that you are performing a conditional check on must equal the names of the these attributes along with the corresponding values (e.g., frequent_flyer, negative).
Print results for escalatedPath or standardPath
Next we want to print for the escalatedPath and standardPath.
- Add a Code block to the right of the routeSupportRequest and rename to
escalatedPath
. - Enter the following code:
let response = "Escalating this request to make sure your frequent flyer experience is positive. We will contact you regarding " + extractJSON.data.issue_type + ".";
return response;
- Add a Code block to the right of the routeSupportRequest and rename to
standardPath
. - Enter the following code:
let response = "That you for informing us about " + extractJSON.data.issue_type + ". We will be contacting you as soon as our agent is available";
return response;
Here is a closer view of the workflow blocks:

Completed Examples
You can import the following examples and compare with what you have built.
Summary
This lab demonstrates the use of a Retool Agent / LLM reasoning being used to route support tickets within Retool Workflows.