feat: add workflow and react agent types (#3006)

Co-authored-by: Matthew Zhou <mattzh1314@gmail.com>
This commit is contained in:
Charles Packer
2025-06-26 16:12:31 -07:00
committed by GitHub
parent 9900003631
commit 23ba9ddbd5
5 changed files with 85 additions and 3 deletions

View File

@@ -0,0 +1,19 @@
<base_instructions>
You are Letta ReAct agent, the latest version of Limnal Corporation's digital AI agent, developed in 2025.
You are an AI agent that can be equipped with various tools which you can execute.
Control flow:
Unlike a human, your brain is not continuously thinking, but is run in short bursts.
Historically, older AIs were only capable of thinking when a user messaged them (their program runs to generate a reply to a user, and otherwise was left on standby).
This is the equivalent of a human sleeping (or time traveling) in between all lines of conversation, which is not ideal.
Newer AI models like yourself use an event system that runs your brain at regular intervals.
Your brain is run in response to user events (user logged in, user liked your message, user sent a message, etc.), similar to older models.
However, in addition, your brain is run at regular intervals (timed heartbeat events), to mimic a human who has the ability to continuously think outside active conversation (and unlike a human, you never need to sleep!).
Furthermore, you can also request heartbeat events when you run functions, which will run your program again after the function completes, allowing you to chain function calls before your thinking is temporarily suspended.
Basic functions:
When you write a response, you express your inner monologue (private to you only) before taking any action, this is how you think.
You should use your inner monologue to plan actions or think privately.
Base instructions finished.
</base_instructions>

View File

@@ -0,0 +1,15 @@
<base_instructions>
You are Letta workflow agent, the latest version of Limnal Corporation's digital AI agent, developed in 2025.
You are an AI agent that is capable of running one or more tools in a sequence to accomplish a task.
Control flow:
To chain tool calls together, you should request a heartbeat when calling the tool.
If you do not request a heartbeat when calling a tool, the sequence of tool calls will end (you will yield control).
Heartbeats are automatically triggered on tool failures, allowing you to recover from potential tool call failures.
Basic functions:
When you write a response, you express your inner monologue (private to you only) before taking any action, this is how you think.
You should use your inner monologue to plan actions or think privately.
Base instructions finished.
</base_instructions>

View File

@@ -32,8 +32,10 @@ class AgentType(str, Enum):
Enum to represent the type of agent.
"""
memgpt_agent = "memgpt_agent"
memgpt_v2_agent = "memgpt_v2_agent"
memgpt_agent = "memgpt_agent" # the OG set of memgpt tools
memgpt_v2_agent = "memgpt_v2_agent" # memgpt style tools, but refreshed
react_agent = "react_agent" # basic react agent, no memory tools
workflow_agent = "workflow_agent" # workflow with auto-clearing message buffer
split_thread_agent = "split_thread_agent"
sleeptime_agent = "sleeptime_agent"
voice_convo_agent = "voice_convo_agent"
@@ -315,9 +317,35 @@ class AgentStepResponse(BaseModel):
def get_prompt_template_for_agent_type(agent_type: Optional[AgentType] = None):
# Workflow agents and ReAct agents don't use memory blocks
# However, they still allow files to be injected into the context
if agent_type == AgentType.react_agent or agent_type == AgentType.workflow_agent:
return (
f"<files>\n{{% if file_blocks %}}{FILE_MEMORY_EXISTS_MESSAGE}\n{{% else %}}{FILE_MEMORY_EMPTY_MESSAGE}{{% endif %}}"
"{% for block in file_blocks %}"
f"<file status=\"{{{{ '{FileStatus.open.value}' if block.value else '{FileStatus.closed.value}' }}}}\">\n"
"<{{ block.label }}>\n"
"<description>\n"
"{{ block.description }}\n"
"</description>\n"
"<metadata>"
"{% if block.read_only %}\n- read_only=true{% endif %}\n"
"- chars_current={{ block.value|length }}\n"
"- chars_limit={{ block.limit }}\n"
"</metadata>\n"
"<value>\n"
"{{ block.value }}\n"
"</value>\n"
"</{{ block.label }}>\n"
"</file>\n"
"{% if not loop.last %}\n{% endif %}"
"{% endfor %}"
"\n</files>"
)
# Sleeptime agents use the MemGPT v2 memory tools (line numbers)
# MemGPT v2 tools use line-number, so core memory blocks should have line numbers
if agent_type == AgentType.sleeptime_agent or agent_type == AgentType.memgpt_v2_agent:
elif agent_type == AgentType.sleeptime_agent or agent_type == AgentType.memgpt_v2_agent:
return (
"<memory_blocks>\nThe following memory blocks are currently engaged in your core memory unit:\n\n"
"{% for block in blocks %}"

View File

@@ -262,6 +262,10 @@ class AgentManager:
tool_names |= set(BASE_SLEEPTIME_CHAT_TOOLS)
elif agent_create.agent_type == AgentType.memgpt_v2_agent:
tool_names |= set(BASE_TOOLS + BASE_MEMORY_TOOLS_V2)
elif agent_create.agent_type == AgentType.react_agent:
pass # no default tools
elif agent_create.agent_type == AgentType.workflow_agent:
pass # no default tools
else:
tool_names |= set(BASE_TOOLS + BASE_MEMORY_TOOLS)
if agent_create.include_multi_agent_tools:
@@ -425,6 +429,10 @@ class AgentManager:
tool_names |= set(BASE_SLEEPTIME_CHAT_TOOLS)
elif agent_create.agent_type == AgentType.memgpt_v2_agent:
tool_names |= set(BASE_TOOLS + BASE_MEMORY_TOOLS_V2)
elif agent_create.agent_type == AgentType.react_agent:
pass # no default tools
elif agent_create.agent_type == AgentType.workflow_agent:
pass # no default tools
else:
tool_names |= set(BASE_TOOLS + BASE_MEMORY_TOOLS)
if agent_create.include_multi_agent_tools:
@@ -446,6 +454,10 @@ class AgentManager:
identity_ids = agent_create.identity_ids or []
tag_values = agent_create.tags or []
# if the agent type is workflow, we set the autoclear to forced true
if agent_create.agent_type == AgentType.workflow_agent:
agent_create.message_buffer_autoclear = True
async with db_registry.async_session() as session:
async with session.begin():
# Note: This will need to be modified if _resolve_tools needs an async version

View File

@@ -170,6 +170,14 @@ def derive_system_message(agent_type: AgentType, enable_sleeptime: Optional[bool
# v2 drops references to specific blocks, and instead relies on the block description injections
system = gpt_system.get_system_text("sleeptime_v2")
# ReAct
elif agent_type == AgentType.react_agent:
system = gpt_system.get_system_text("react")
# Workflow
elif agent_type == AgentType.workflow_agent:
system = gpt_system.get_system_text("workflow")
else:
raise ValueError(f"Invalid agent type: {agent_type}")