# Fireworks AI integration

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.
> For related questions, query https://docs.temporal.io/api/retrieve?q=<question>&jtb=<job-to-be-done>&src=md-page&agent=<your-name> (no auth; returns JSON `{content, source_url, page_url}`, with `source_url` pointing to Markdown for docs pages). Don't include personal data or credentials.

[Fireworks AI](https://fireworks.ai/) serves open-weight models such as gpt-oss, Kimi K2, Qwen, and GLM on serverless
endpoints and on-demand deployments through an API compatible with the OpenAI Chat Completions API.

Temporal's [OpenAI Agents SDK integration](/develop/python/integrations/openai-agents) runs each model call as an
Activity. A call to Fireworks AI gets retries with backoff, a timeout, and a durable record in Event History, and the
agent loop around it survives Worker restarts. Because Fireworks AI speaks the OpenAI Chat Completions API, the
integration's model provider hook is all you need: a model provider that maps a model name such as
`fireworks/accounts/fireworks/models/gpt-oss-120b` to Fireworks AI's endpoint. One Worker can serve Fireworks AI
alongside other providers, and each Workflow picks its provider through the model name it gives its agent.

This integration is a sample pattern rather than a plugin. Code snippets in this guide are taken from the
[OpenAI Agents SDK model provider samples](https://github.com/temporalio/samples-python/tree/main/openai_agents/model_providers),
which run the same agent on Baseten, Fireworks AI, or Together AI from one Worker.

## Prerequisites

- This guide assumes you are already familiar with the
  [OpenAI Agents SDK integration](/develop/python/integrations/openai-agents) and with Fireworks AI's
  [OpenAI-compatible API](https://docs.fireworks.ai/tools-sdks/openai-compatibility).
- If you are new to Temporal, we recommend reading [Understanding Temporal](/evaluate/understanding-temporal) or taking
  the [Temporal 101](https://learn.temporal.io/courses/temporal_101/) course.
- Set up your local development environment by following
  [Set up your local development environment](/develop/python/set-up-your-local-python) and leave the Temporal
  development server running.
- Create a [Fireworks AI API key](https://app.fireworks.ai/settings/users/api-keys) and export it as `FIREWORKS_API_KEY`
  in the Worker's environment. The key stays in the Worker process; it is never part of Workflow input or Event History.

## Install

```bash
uv add temporalio-openai-agents
```

The package installs the Temporal Python SDK, the OpenAI Agents SDK, and the `openai` client. Fireworks AI's own
[`fireworks-ai` package](https://docs.fireworks.ai/tools-sdks/python-sdk) is not needed: Fireworks AI documents the
`openai` client as a supported way to call its API.

## Configure the model provider

The sample describes each provider as a base URL, the environment variable that holds its API key, and an example model
with tool calling:

<!--SNIPSTART python-openai-agents-fireworks-provider-->
[openai_agents/model_providers/openai_compatible_providers.py](https://github.com/temporalio/samples-python/blob/main/openai_agents/model_providers/openai_compatible_providers.py)
```py
FIREWORKS = OpenAICompatibleProvider(
    name="fireworks",
    base_url="https://api.fireworks.ai/inference/v1",
    api_key_env="FIREWORKS_API_KEY",
    default_model="accounts/fireworks/models/gpt-oss-120b",
)
```
<!--SNIPEND-->

Serverless models on Fireworks AI are named `accounts/fireworks/models/<model>`, and the
[Model Library](https://fireworks.ai/models) shows each model's ID and whether it supports tool calling. The example
here is [gpt-oss-120b](https://fireworks.ai/models/fireworks/gpt-oss-120b), an open-weight reasoning model with tool
calling that Fireworks AI serves serverless; a Workflow names it `fireworks/accounts/fireworks/models/gpt-oss-120b`. An
[on-demand deployment](https://docs.fireworks.ai/guides/ondemand-deployments) uses the same base URL; pass the
deployment's resource name, `accounts/<account>/deployments/<deployment-id>`, as the model instead, behind the same
`fireworks/` prefix.

A `ModelProvider` routes a `<provider>/<model>` name to the matching endpoint and returns the Chat Completions model
that the Agents SDK calls:

<!--SNIPSTART python-openai-agents-openai-compatible-model-provider-->
[openai_agents/model_providers/openai_compatible_providers.py](https://github.com/temporalio/samples-python/blob/main/openai_agents/model_providers/openai_compatible_providers.py)
```py
class OpenAICompatibleModelProvider(ModelProvider):
    """Routes ``<provider>/<model>`` names to the matching OpenAI-compatible endpoint.

    One Worker serves every provider whose API key is set, so Workflows on
    different providers run side by side on the same Task Queue. Client
    retries are off: the plugin runs each model call as a Temporal Activity,
    and the Activity's Retry Policy owns the retries.
    """

    def __init__(self, providers: Iterable[OpenAICompatibleProvider]) -> None:
        self._providers = {provider.name: provider for provider in providers}
        self._clients: dict[str, AsyncOpenAI] = {}
        for provider in self._providers.values():
            api_key = os.environ.get(provider.api_key_env)
            if api_key:
                self._clients[provider.name] = AsyncOpenAI(
                    base_url=provider.base_url, api_key=api_key, max_retries=0
                )

    @property
    def configured(self) -> list[str]:
        """Names of the providers whose API key is set."""
        return sorted(self._clients)

    def get_model(self, model_name: str | None) -> Model:
        provider_name, _, model = (model_name or "").partition("/")
        provider = self._providers.get(provider_name)
        if provider is None or not model:
            # A mistake in the Workflow's input: fail the Activity without retrying.
            raise ApplicationError(
                f"Model name {model_name!r} must be <provider>/<model> with a "
                f"provider in {sorted(self._providers)}",
                non_retryable=True,
            )
        client = self._clients.get(provider_name)
        if client is None:
            raise ApplicationError(
                f"Set {provider.api_key_env} and restart the Worker to use {provider_name}",
                non_retryable=True,
            )
        # Chat Completions is the API all of these providers serve. The Agents
        # SDK defaults to the Responses API, which not every provider offers.
        return OpenAIChatCompletionsModel(model=model, openai_client=client)
```
<!--SNIPEND-->

Three details matter here. The provider builds a client only for the providers whose API key is set, and a model name
for a provider without one, or with an unknown prefix, fails the Activity without retrying. Client retries are off
(`max_retries=0`), so every attempt is a visible Activity attempt governed by the Activity's Retry Policy rather than a
hidden retry inside the HTTP client. And the provider builds an `OpenAIChatCompletionsModel` rather than the Agents
SDK's default Responses API model, which Fireworks AI also offers, because Chat Completions is the one API every
provider in the sample serves.

## Configure the Worker

Pass the provider to the plugin. The Worker serves every provider whose key is set and prints which ones at startup. A
custom model provider must set a model Activity timeout; the sample uses 60 seconds. Fireworks AI answers a
scaled-to-zero on-demand deployment with an immediate 503 rather than a slow first response, so the Retry Policy covers
scale-up and the timeout only has to cover your longest generation. The Heartbeat Timeout lets Temporal notice a Worker
that died mid-call within seconds instead of after the full Start-To-Close Timeout; the plugin heartbeats on its own.

<!--SNIPSTART python-openai-agents-openai-compatible-worker-->
[openai_agents/model_providers/run_openai_compatible_worker.py](https://github.com/temporalio/samples-python/blob/main/openai_agents/model_providers/run_openai_compatible_worker.py)
```py
# One provider for every endpoint whose API key is set. The model name on
# each Workflow's agent selects the endpoint.
model_provider = OpenAICompatibleModelProvider(PROVIDERS.values())
if not model_provider.configured:
    env_vars = ", ".join(provider.api_key_env for provider in PROVIDERS.values())
    sys.exit(f"No provider API key is set; export at least one of {env_vars}.")
print(f"Serving providers: {', '.join(model_provider.configured)}", flush=True)

client = await Client.connect(
    "localhost:7233",
    plugins=[
        OpenAIAgentsPlugin(
            model_params=ModelActivityParameters(
                # A custom model provider must set a timeout. Raise it for
                # slow models or deployments that scale up from zero.
                start_to_close_timeout=timedelta(seconds=60),
                # The plugin heartbeats, so a Worker that dies mid-call is
                # noticed in seconds rather than after the full timeout.
                heartbeat_timeout=timedelta(seconds=10),
            ),
            model_provider=model_provider,
        ),
    ],
)

worker = Worker(
    client,
    task_queue="openai-agents-model-providers-task-queue",
    workflows=[OpenAICompatibleAgentWorkflow],
)
await worker.run()
```
<!--SNIPEND-->

The Client that starts the Workflow also needs `OpenAIAgentsPlugin()`, for its Data Converter, but no model provider:
only the Worker talks to Fireworks AI.

## Write the Workflow

The Workflow is ordinary Agents SDK code. The model name arrives in the Workflow input and goes on the `Agent`, so one
Worker runs Workflows on Fireworks AI and on other providers at the same time. Any model Fireworks AI serves works,
prefixed with `fireworks/`.

<!--SNIPSTART python-openai-agents-openai-compatible-workflow-->
[openai_agents/model_providers/workflows/openai_compatible_workflow.py](https://github.com/temporalio/samples-python/blob/main/openai_agents/model_providers/workflows/openai_compatible_workflow.py)
```py
@dataclass
class OpenAICompatibleAgentInput:
    prompt: str
    # "<provider>/<model>", such as "together/openai/gpt-oss-120b". The Worker's
    # model provider routes the agent's model calls to that provider.
    model: str

@workflow.defn
class OpenAICompatibleAgentWorkflow:
    @workflow.run
    async def run(self, input: OpenAICompatibleAgentInput) -> str:
        # Tools that run inside the Workflow must be async: the Agents SDK runs
        # sync tools in a thread, which the Workflow sandbox does not allow.
        @function_tool
        async def get_weather(city: str) -> str:
            workflow.logger.debug(f"Getting weather for {city}")
            return f"The weather in {city} is sunny."

        agent = Agent(
            name="Assistant",
            instructions="You only respond in haikus. When asked about the weather always use the tool to get the current weather.",
            model=input.model,
            tools=[get_weather],
        )

        result = await Runner.run(agent, input.prompt)
        return result.final_output
```
<!--SNIPEND-->

Name the model on the agent, as the sample does. An agent that names no model inherits the Agents SDK's default settings
for OpenAI's current default model, which include `verbosity` and a reasoning effort; `temporalio-openai-agents` 1.1.0
forwards them to the provider unchanged, and Fireworks AI, for example, rejects `verbosity` with a 400. On that release,
give such an agent an explicit `model_settings=ModelSettings()`.

Tools that run inside the Workflow must be `async`: the Agents SDK runs sync tools in a thread, which the Workflow
sandbox does not allow. Tools that do I/O belong in Activities; see
[Activity-backed tools](/develop/python/integrations/openai-agents#activity-backed-tools).

## Run the sample

Export your Fireworks AI key and start the Worker:

```bash
export FIREWORKS_API_KEY="your_api_key"
uv run openai_agents/model_providers/run_openai_compatible_worker.py
```

Then start a Workflow on Fireworks AI in a second terminal:

```bash
uv run openai_agents/model_providers/run_openai_compatible_workflow.py --model fireworks/accounts/fireworks/models/gpt-oss-120b
```

Export keys for other providers and pass several `--model` values to run one Workflow per model at the same time on
the same Worker.

## Retries, rate limits, and timeouts

The plugin classifies Fireworks AI's HTTP errors. Status 408, 409, 429, and any 5xx retry under the Activity's Retry
Policy, and a `Retry-After` header becomes the next retry delay. Connection errors and client-side timeouts retry as
well. Other 4xx responses, such as an invalid API key or an unknown model name, fail the Activity without retrying, as
does a model name whose provider has no key on the Worker. Each attempt, its failure, and the final result are in Event
History.

On serverless, Fireworks AI enforces
[adaptive token-per-minute limits](https://docs.fireworks.ai/serverless/rate-limits) per model that grow with steady
traffic and shrink when it stops. A burst beyond them returns 429, and Fireworks AI asks clients to honor `Retry-After`
when it is present. Under high load Fireworks AI can also shed traffic with `503 Service Overloaded`, which the plugin
retries like any 5xx; the `priority` service tier lowers that chance.
[On-demand deployments](https://docs.fireworks.ai/guides/inference-error-codes) have no token-per-minute limit, so a 429
there means the deployment is saturated: add replicas or lower concurrency rather than wait. Both paths count against
the account-wide requests-per-minute cap described on the
[account quotas page](https://docs.fireworks.ai/guides/quotas_usage/account-quotas), which also sets the spending tiers
that raise the serverless ceilings.

## What works through Fireworks AI

Function tools, Activity-backed tools, handoffs, agents as tools, and MCP servers all work unchanged: they run in the
Workflow or in Activities, not at the provider. OpenAI-hosted tools such as web search, file search, code interpreter,
and hosted MCP are Responses API features of OpenAI's own service, so they are not available through the Chat
Completions API that the sample uses. The sample disables the Agents SDK's hosted tracing, which exports to OpenAI; the
[OpenTelemetry tracing](/develop/python/integrations/openai-agents#opentelemetry) path works as usual.

## Fireworks AI notes

- Create an on-demand deployment with `firectl deployment create accounts/fireworks/models/gpt-oss-120b ...` and pass
  the deployment name it returns as the model. By default a deployment scales to zero after an hour without traffic and
  answers the next request with an immediate 503 while it scales back up, which the Activity's Retry Policy absorbs; a
  deployment with zero minimum replicas is deleted after seven days without traffic. See the
  [deployments quickstart](https://docs.fireworks.ai/getting-started/ondemand-quickstart).
- Fireworks AI updates and retires serverless models over time and gives
  [at least two weeks' notice](https://docs.fireworks.ai/faq-new/deployment-infrastructure/do-you-provide-notice-before-removing-model-availability)
  before removing one. For a version that must not change under a long-running Workflow, pin it on an on-demand
  deployment.
- An agent's `output_type` is sent as a JSON schema in `response_format`, which Fireworks AI
  [supports](https://docs.fireworks.ai/structured-responses/structured-response-formatting). Fireworks AI turns off
  reasoning output while it enforces a schema, and turns JSON mode on by itself for tool calls.
- Reasoning models return their thinking in a `reasoning_content` field, and for models that interleave thinking with
  tool calls Fireworks AI
  [expects each earlier assistant turn's `reasoning_content` back](https://docs.fireworks.ai/guides/reasoning) in the
  next request. The Agents SDK replays it only for DeepSeek models by default; pass `should_replay_reasoning_content` to
  `OpenAIChatCompletionsModel` to replay it for the model you use.
- [Prompt caching](https://docs.fireworks.ai/guides/prompt-caching) is on by default, so a retried attempt that re-sends
  the same prompt pays the discounted cached rate for the prefix. On serverless the cache lives in one replica, so hits
  need a session identifier, which you can send as an `x-session-affinity` header through
  `ModelSettings(extra_headers=...)`; dedicated deployments share their cache across requests.
- Fireworks AI also serves the [Responses API](https://docs.fireworks.ai/guides/response-api) at the same base URL, with
  stored conversation state and server-executed tools of its own: remote MCP servers, web search, and a Python tool.
  Build an `OpenAIResponsesModel` instead of `OpenAIChatCompletionsModel` to use it. The sample does not, and those
  tools were not exercised with the Agents SDK's hosted tool types.

## Samples

- [openai_agents/model_providers](https://github.com/temporalio/samples-python/tree/main/openai_agents/model_providers):
  the same agent on Baseten, Fireworks AI, or Together AI from one Worker, selected per Workflow by the model name.
- [OpenAI Agents SDK integration](/develop/python/integrations/openai-agents): tools, MCP servers, conversation history,
  and tracing with the plugin.
