Is your feature request related to a problem? Please describe.
I am building a durable research agent using temporalio.contrib.openai_agents.
The agent uses custom tools that perform external I/O, such as:
- Web search through Firecrawl or similar services
- HTTP API calls
- Database access
- Object storage or messaging operations
The integration makes it possible to run the OpenAI Agents Runner inside a Temporal Workflow while routing model invocations through Temporal Activities.
However, custom function tools that perform external I/O still require several separate steps:
- Define the operation as a Temporal Activity
- Wrap the Activity using
openai_agents.workflow.activity_as_tool(...)
- Configure Activity timeouts and retry policies
- Register the Activity explicitly with the Worker
For example:
@activity.defn
async def search_web(query: str) -> str:
return await firecrawl.search(query)
search_tool = openai_agents.workflow.activity_as_tool(
search_web,
start_to_close_timeout=timedelta(seconds=30),
retry_policy=RetryPolicy(
maximum_attempts=3,
),
)
agent = Agent(
name="Researcher",
tools=[search_tool],
)
This is manageable for one tool, but becomes repetitive when an agent has many external tools.
It is also easy for developers to accidentally use a regular OpenAI Agents @function_tool for an operation that performs network or database I/O:
@function_tool
async def search_web(query: str) -> str:
return await firecrawl.search(query)
Because the tool appears valid from the OpenAI Agents SDK perspective, it may not be obvious that it can execute inside the Workflow rather than through an Activity.
This creates two problems:
- A developer-experience gap between normal OpenAI Agents SDK code and the Temporal integration
- A safety risk where non-deterministic or external I/O is accidentally executed inside a Workflow
I understand that the SDK cannot reliably inspect an arbitrary Python function and determine whether it performs I/O. I also understand that Activities require explicit operational semantics such as timeouts, retries, cancellation behavior, and task queues.
The request is therefore not necessarily to convert every function tool into an Activity automatically, but to provide a clearer and less repetitive abstraction for durable tools.
Describe the solution you'd like
I would like the integration to provide an explicit first-class abstraction for an OpenAI Agent tool backed by a Temporal Activity.
For example:
@openai_agents.activity_tool(
start_to_close_timeout=timedelta(seconds=30),
retry_policy=RetryPolicy(
maximum_attempts=3,
),
)
async def search_web(query: str) -> str:
return await firecrawl.search(query)
The resulting object could be used directly as an Agent tool:
agent = Agent(
name="Researcher",
tools=[search_web],
)
Ideally, this abstraction would:
- Define or expose the underlying Temporal Activity
- Produce an OpenAI Agents-compatible tool
- Preserve the function name, description, and input schema
- Allow Activity options such as timeout, retry policy, heartbeat timeout, and task queue
- Reduce duplication between Activity definitions and Agent tool definitions
- Make the execution boundary explicit to readers of the code
If automatic Worker registration is not desirable, the decorated tool could expose its Activity separately:
worker = Worker(
client,
task_queue="research-agent",
workflows=[ResearchWorkflow],
activities=[
search_web.activity,
],
)
Another useful addition would be an optional strict mode for Workflow-local function tools.
For example:
OpenAIAgentsPlugin(
workflow_function_tools="reject",
)
With this enabled, passing a regular FunctionTool to an Agent running inside a Workflow could fail with an actionable error such as:
FunctionTool 'search_web' will execute inside the Workflow.
Use activity_as_tool() or @activity_tool for tools that perform
network, database, filesystem, or other external I/O.
Explicitly mark the tool as deterministic if Workflow-local execution
is intentional.
A deterministic local tool could then be explicitly allowed:
@openai_agents.workflow_tool
@function_tool
def calculate_score(value: int) -> int:
return value * 2
The exact API names are only suggestions. The main goals are:
- Make Activity-backed Agent tools first-class
- Reduce the boilerplate required for each custom tool
- Prevent accidental external I/O inside Workflows
- Clearly distinguish deterministic Workflow-local tools from durable external tools
Additional context
A common production agent loop looks like this:
Temporal Workflow
└── OpenAI Agents Runner
├── Model invocation Activity
├── Web search Activity
├── Page scraping Activity
├── Database Activity
└── Model invocation Activity
The existing model integration already provides a convenient abstraction for durable model invocations.
Custom tools are often the next major source of external I/O, retries, rate limits, timeouts, and partial failures. Making Activity-backed tools equally explicit and ergonomic would make the integration easier to adopt for production agents.
This is especially relevant for research agents using services such as Firecrawl, Tavily, or custom search APIs. Search and scraping should generally be separate Activity boundaries so they can have independent retries, timeouts, observability, and failure handling.
Clearer documentation would also help. In particular, it would be useful to state prominently that:
- Model invocations are routed through Temporal Activities by the integration
- Hosted tools may execute as part of the model invocation
- Regular custom function tools are not automatically converted into Activities
- Custom tools performing external I/O should be wrapped with
activity_as_tool()
- Workflow-local function tools should only contain deterministic logic
I would also appreciate guidance on whether this can be implemented entirely in temporalio.contrib.openai_agents, or whether a more general pluggable tool-execution hook would be required from the OpenAI Agents SDK.
Is your feature request related to a problem? Please describe.
I am building a durable research agent using
temporalio.contrib.openai_agents.The agent uses custom tools that perform external I/O, such as:
The integration makes it possible to run the OpenAI Agents
Runnerinside a Temporal Workflow while routing model invocations through Temporal Activities.However, custom function tools that perform external I/O still require several separate steps:
openai_agents.workflow.activity_as_tool(...)For example:
This is manageable for one tool, but becomes repetitive when an agent has many external tools.
It is also easy for developers to accidentally use a regular OpenAI Agents
@function_toolfor an operation that performs network or database I/O:Because the tool appears valid from the OpenAI Agents SDK perspective, it may not be obvious that it can execute inside the Workflow rather than through an Activity.
This creates two problems:
I understand that the SDK cannot reliably inspect an arbitrary Python function and determine whether it performs I/O. I also understand that Activities require explicit operational semantics such as timeouts, retries, cancellation behavior, and task queues.
The request is therefore not necessarily to convert every function tool into an Activity automatically, but to provide a clearer and less repetitive abstraction for durable tools.
Describe the solution you'd like
I would like the integration to provide an explicit first-class abstraction for an OpenAI Agent tool backed by a Temporal Activity.
For example:
The resulting object could be used directly as an Agent tool:
Ideally, this abstraction would:
If automatic Worker registration is not desirable, the decorated tool could expose its Activity separately:
Another useful addition would be an optional strict mode for Workflow-local function tools.
For example:
With this enabled, passing a regular
FunctionToolto an Agent running inside a Workflow could fail with an actionable error such as:A deterministic local tool could then be explicitly allowed:
The exact API names are only suggestions. The main goals are:
Additional context
A common production agent loop looks like this:
The existing model integration already provides a convenient abstraction for durable model invocations.
Custom tools are often the next major source of external I/O, retries, rate limits, timeouts, and partial failures. Making Activity-backed tools equally explicit and ergonomic would make the integration easier to adopt for production agents.
This is especially relevant for research agents using services such as Firecrawl, Tavily, or custom search APIs. Search and scraping should generally be separate Activity boundaries so they can have independent retries, timeouts, observability, and failure handling.
Clearer documentation would also help. In particular, it would be useful to state prominently that:
activity_as_tool()I would also appreciate guidance on whether this can be implemented entirely in
temporalio.contrib.openai_agents, or whether a more general pluggable tool-execution hook would be required from the OpenAI Agents SDK.