Write your first AgentApp¶
Create a small AgentApp from the Flower Hub template, customize its prompt, and run it on SuperGrid. The app makes one model request through the OpenAI SDK so you can focus on the AgentApp lifecycle before adding connectors.
Complete Chat in your terminal first. This tutorial targets Flower 1.35.0.
Create the project¶
Download the AgentApp template from Flower Hub:
$ uvx --from flwr==1.35.0 flwr new @flwrlabs/agent
$ cd agent
The command creates a ready-to-build project:
agent/
├── .gitignore
├── agent/
│ ├── __init__.py
│ └── agent_app.py
├── LICENSE
├── README.md
└── pyproject.toml
Rename the project and change its publisher before publishing it under your
own account. You can keep the generated values while running it locally or on
SuperGrid.
Understand the AgentApp¶
Open agent/agent_app.py:
"""A minimal Flower AgentApp."""
import os
from flwr.agentapp import AgentApp, AgentSession
from flwr.app import Context
from openai import OpenAI
MODEL = "openai/gpt-5.6-sol"
app = AgentApp()
@app.main()
def main(agent: AgentSession, context: Context) -> None:
"""Send the configured input to the model."""
prompt = context.run_config.get("agent.input")
if not isinstance(prompt, str) or not prompt.strip():
raise ValueError("agent.input must be a non-empty string")
client = OpenAI(
base_url=os.environ["FLWR_RUNTIME_BASE_URL"],
api_key=os.environ["FLWR_RUNTIME_API_KEY"],
max_retries=0,
)
stream = client.responses.create(
model=MODEL,
input=prompt.strip(),
stream=True,
)
output_text = []
for event in stream:
agent.events.emit(event.to_dict())
if event.type in {"error", "response.failed"}:
raise RuntimeError(f"Model response failed: {event}")
if event.type == "response.output_text.delta":
output_text.append(event.delta)
print("".join(output_text))
AgentApp.main registers the function Flower calls. The runtime passes:
agent, anAgentSessionfor connectors and frontend-visible eventscontext, which contains the fused run configuration and persistent state
Flower also injects FLWR_RUNTIME_BASE_URL and FLWR_RUNTIME_API_KEY into the
AgentApp process. The OpenAI client uses them to send the request through
Flower, so the project does not need a model-provider API key.
The SDK yields typed streaming events. The loop republishes each event through
agent.events.emit so Flower Chat and other run-event clients can render the
response. Calling print does not publish an assistant response; it writes the
completed answer only to the AgentApp logs.
Review the Flower configuration¶
The generated pyproject.toml includes the SDK and targets Flower 1.35.0:
[project]
dependencies = ["flwr>=1.35.0,<2.0", "openai>=2.16.0,<3.0.0"]
[tool.flwr.app]
flwr-version-target = "1.35.0"
[tool.flwr.app.config.agent]
input = "Explain why flowers turn toward light."
[tool.flwr.app.components]
agentapp = "agent.agent_app:app"
The component value uses <module>:<attribute>. Flower imports app from
agent/agent_app.py. The nested config.agent.input value becomes
context.run_config["agent.input"].
Change the default prompt to something easy to recognize:
[tool.flwr.app.config.agent]
input = "Explain Flower Agent in one sentence."
Create the environment¶
$ uv sync
uv creates .venv and a lock file. You do not need to activate the
environment because the following commands use uv run.
Checkpoint
uv sync should resolve Flower 1.35 and the OpenAI SDK without a dependency
error.
Validate the bundle¶
$ uv run flwr build
The command should report the created .fab path. It validates the project
configuration and component reference before submission.
If Flower cannot load the component, check:
the
agentpackage directorythe
agent_app.pymodulethe
:appobject referenced inpyproject.toml
Run on SuperGrid¶
Log in, then submit the project and stream its logs:
$ uv run flwr login supergrid
$ uv run flwr run . supergrid --stream
Override the configured prompt for one run:
$ uv run flwr run . supergrid \
--run-config 'agent.input="Describe photosynthesis for a five-year-old."' \
--stream
Success checkpoint
The command prints a run ID, the run reaches a finished state, and the streamed model response appears in the run activity and logs.
If the run fails, use the printed ID with:
$ uv run flwr list --run-id <run-id> supergrid
$ uv run flwr log <run-id> supergrid --show
Understand this app’s limits¶
The app makes one model request and exits. It does not:
replay prior messages from a run series
persist the assistant response for a later run
expose connectors
handle model-requested function calls
create automations
Those behaviors belong in AgentApp code rather than appearing automatically. Continue with Build a collaborative research agent for a bounded connector loop with conversation state, read Use the OpenAI SDK in an AgentApp for the runtime details, or publish the AgentApp to Flower Hub so others can run it.