Agentic workflows with AI Agents
Learn how to use the AI Agent command to create persistent, interactive Agentic workflows.
Introduction
The AI Agent command allows you to create and interact with persistent AI agents that maintain conversation history across multiple interactions. Each agent can be customized with specific personalities, knowledge domains, and behavioral traits through a system prompt, while maintaining context and memory of previous interactions through a thread ID system.
When to use an AI Agent
An AI Agent is an excellent choice in two key scenarios:
-
When you need ongoing conversations where the agent:
- Maintains memory of previous interactions
- Responds in a natural, human-like way
- Builds context over time
-
When you need autonomous task completion where the agent:
- Thinks independently
- Works from high-level objectives
- Selects and uses appropriate tools
- Solves complex problems
The promise of AI Agents is their ability to handle complex tasks with minimal instruction. While the most challenging aspect of building an agent is typically providing it with the right tools, Pinkfish makes this straightforward - you can simply build automations as tools. So Pinkfish is an ideal platform for developing sophisticated AI Agents.
When not to use an AI Agent
In many cases, you don’t need an AI Agent.
For example, if you want to create an automation that:
- Receives an inbound SMS or email
- Processes that message in some way
- Responds to the user
This is a simple automation that receives an input, processes it, and responds using the same channel. An AI Agent is overkill. In the case above, even if you need some kind of “agentic” behavior in your processing step, like delivering a human-like response, you could simply build a step that makes a call to one of the LLMs and returns the response. If you don’t expect your user to followup in conversation, then you don’t need an AI Agent.
Similarly, avoid using AI Agents when:
- Interfacing with critical systems
- Zero-error tolerance is required
- You need deterministic, testable outcomes
In these cases, build a simple multi-step automation. Pinkfish excels at helping you build automations with deterministic outcomes. If you don’t need the flexibility of an AI Agent, you can build a simple automation that works the same way every time.
Pro Tip
The more leeway you give your agent to make decisions, prepare its own task list, and select its own tools, the more autonomous your agent will become. However, it’ll also be more likely to make mistakes. So you’ll want to balance the level of autonomy you give your agent with the level of accuracy you need (or the amount of testing you want to do). The more complex your agent, the more testing you’ll need to do.
Basic Usage
Create and interact with an AI agent using the /ai-agent
command followed by the required fields:
Slash Command Structure
Call the AI Agent using the slash command:
Field Definitions
1. systemPrompt
This is the living breathing heart of your agent.
- Defines the agent’s personality, knowledge, and behavior
- Can include:
- Name and identity
- Area of expertise
- Behavioral traits
- Response style
- Limitations and constraints
- Available tasks and tools (see below)
- Pro tip: upload your agent prompt as a file to the automation and then retrieve it in step one. This will make editing and replacing your prompt very easy. Whenever you have an update, delete the previous agent prompt file and re-upload a new version.
2. userMessage
- The most recent message from the user
- Can be a question, command, or conversation continuation (an SMS, email, chat message, etc.)
- The agent will respond based on this input and previous context
- If you are creating some kind of worker agent that doesn’t respond to user messages, you would set this field to be your command to your worker agent. Eg: “Start analytics jobId: 1234567890”
- Pro tip: use “test inputs” to test your agent with different inputs.
3. threadId
The threadId is a unique identifier for tracking a conversation over time. Your threadId could simply be the user’s phone number or email address.
The most important thing is that you get the threadId back in the response from the user. For this reason, using a phone number or email address is the simplest solution. If you are using these channels, the sender’s phone number or email address is already unique and will be sent by the user with every message. The downside to using a phone number or email address is that the thread will be locked into that user. So if the user cc’s other people and they reply, the sender email will change and you’ll lose the thread.
If you don’t supply a threadId one will be created for you and returned with the response. You’ll want to get this Id and use it for the ongoing conversation. For this reason it’s optional. Just don’t forget to put the generated Id somewhere into your response to the user such that they include it in their response (see email example below).
Typical Setup
You create your AI Agent just like any other automation. A typical AI Agent automation consists of three steps:
- organizing your inputs
- calling the agent
- responding to the user
Here’s a sample:
Step 1: Get your inputs and files sorted
Step 2: Call the agent
Step 3: Respond to the user on the same channel as the inbound message (email example here with threadId included in the response)
Here is a screenshot of a three step automation that follows the model above. You can see in this example that I’ve put the agent prompt in a file and attached the file to the automation (and retrieved it as part of step 1). In step3 shown below, I’m sending out the agent’s response via email using Sendgrid.
AI Agent Examples
- Customer Service Agent
- Sales Development Agent
- Sales Analytics Agent
Advanced Prompting
The examples above show very simple agent prompts. Simple prompts will work for simple conversations. However, you can create a detailed agent prompt that guides your agent to perform designated tasks in a specific order, with specific steps, and with tools that you have created on Pinkfish.
Although many formats may work with the agent framework, here is a template that we’ve tested and that works reliably.
Example of the template filled out
Note that where we have FILL IN, you should not fill in the details - that is a note for the LLM to fill in that detail. However, you should replace YOUR_TRIGGER_API_KEY and YOUR_TRIGGER_ID with your Pinkfish trigger API keys and trigger IDs.
Note that if you are familiar with LLM tool calling and wondering why we don’t follow the standard tool calling format, it’s because we’ve found that the format above works better with the agent framework (it picks the correct tools more often and ignores tools when they’re not needed).
Tools
One of the most powerful features of the AI Agent framework is the ability use tools. A tool is just a regular Pinkfish automation where something is done and results returned. On Pinkfish, creating new custom tools (automations) is super easy and fast, as you know. When you’ve got a tool automation built, add an API Trigger to it and give the API details to your AI Agent using the template above.
You can create tools to give your agents all kinds of super powers. Some ideas are:
- Document search - answer questions from PDFs or other documents
- Document processing - receiving documents from the user and processing them in some interesting way
- Visualization creation - generate charts, graphs, and other visual representations of data
- Answering questions from websites using scraping
- Answering questions about recent news using Perplexity
- Searching for flights or hotels using the flights / hotels tool
- Translating, transcribing, or summarizing
- Image analysis - extracting text, objects, and insights from uploaded images
- Database querying - answering questions by searching structured databases
- Calendar management - scheduling and organizing events and meetings
- Form filling - automatically completing forms based on provided information
- Financial analysis - processing and analyzing financial data and reports
- Social media monitoring - tracking and analyzing social media trends
- Legal document review - analyzing contracts and legal documents
- Medical record analysis - processing and summarizing medical information
- Academic research - searching and summarizing scholarly articles
- Market research - gathering and analyzing competitive intelligence
- So so much more…
Note that when you get a response from an API Trigger call, it will return results from all of the steps. That payload is more than the agent needs (no need to confuse the agent with an overload of content). So the agent framework is setup to search for a step result that has the variable “selectedResult”. So be sure to output a selectedResult from one of your steps (usually the last one).
Here is a screenshot of the selectedResult variable in the step output for a tool that scrapes ticketing websites.
Message History Format
Unless you specify a messageHistory, the framework will automatically create a message history for you. It will look like this:
You can review messageHistory in the datastore UI feature. Or you can retrieve it using the following prompt:
Testing
Testing AI Agents is the toughest part of developing an agent because it could do so many different things depending on the inputs and depending on how you’ve written the prompt. One small change in the prompt could cause the agent to behave differently. So you’ll want to test with a variety of inputs and see how the agent responds.
You can use the Test Inputs
feature to run through various scenarios quickly.
After setting your test input, run your automation. You’ll see the results in the UI.
Sending and Responding to Inputs
While you can set test inputs to test your agent, generally, you’ll want to send inputs to your agent by some other channel, such as:
- SMS (see: SMS Triggers)
- Slack
- Web chat
- API (see: API Triggers)
- Whatever you can imagine
And then you’ll want to respond to the agent’s output in the same way.
Advanced Usage: Long-Term Memory
I saved this for very last because it’s an advanced feature that you can happily ignore. In normal operation, your agent will remember about 20 previous interactions from the thread message history. We may tweak this from time to time if we’re seeing that 20 is not sufficient, but it’s a nice easy default that you don’t have to worry about too much.
But what if you want your agent to remember interactions across threads or to never forget something about a user. Perhaps a user never wants to be contacted via SMS. Your agent should be able to remember that - no matter how long ago the user said it.
For this use case, your agent supports long term memory! You can store an item in long term memory for a given user. And then when you run your agent, just tell it to use its memory.
First, let’s look at creating and managing memories.
Creating a memory
Getting memories for a user
You can see a user’s memories in the Datastore UI - or you can retrieve them using a prompt:
Compiled:true will show the list of memories as they will be seen by your agent. When false, it’ll give you the listing of datastore items for that user. If you ever want to update or delete a memory, you’ll need the full listing details (the sortField in particular)
Updating memories for a user
The sortField will be a timestamp that you can retrieve using the get memories method. In combination, the key and sortField are the unique identifiers for each memory.
Deleting memories for a user
You can delete memories using the Datastore UI or via a prompt.
User Ids
I’ve been talking about user ids for long term memory, but how the heck do you get a userId? Simple, you make it up. It could be “123” or it could be the user’s email address or phone number (easier).
Using memory with your agent
To make your agent aware of memories for a given user, just send in the userId and useMemory flag. In the prompt below, you can see I added two additional parameters at the end to let the agent know that we want to use memory for this interaction. With a prompt like this, your agent will pull in all of the memories for this user and use them in consideration when preparing its plan of action or response.
Group memories
If you wanted to store common or group memories that are shared across multiple users, you could use the userId as a kind of group Id. In this case, you would create a user Id like “GroupXYZ” - and send that into the agent prompt whenever you have a member of that group interacting with the agent. In this way, the agent will pull back this list of common memories for any interaction where you set this Id.
Debugging
Outside of running your agent with multiple inputs and observing the outputs, there’s a lot of information that you’ll see in the information that is returned from the AI Agent call.
Here’s a sample output from an AI Agent call.
message
just tells you that the agent operated successfully (or with an error)output
is where you’ll find the agent’s final responseexecutionLog
is chock full of info about the agent’s processing of the incoming query. I’ll often just drop this whole array into Claude and ask it what happened or what went wrong - or does it have the info I wanted it to have. Here you have the full log of what was sent to the LLM and what the LLM sent in reply. The AI Agent has a 5 call circuit breaker to prevent infinte or extreme looping. You’ll see that as the iteration count. You’ll also see any errors in execution or tool calling.finalMessageHistory
shows the final compiled message history for this threadId its a nice way to quick see what was in the thread previously and what was added as a result of this call.threadId
is just what it sounds like.inputs
just echos out what you sent to it. The only exception is that if you didn’t send in a threadId, it’ll show the thread Id that it made up here as well.
Overriding messageHistory
You can override the messageHistory by providing a custom messageHistory in your request. This parameter is useful if you want to debug a particular sequence of messages without running through the entire conversation bit by bit.