kaxil opened a new pull request, #77071: URL: https://github.com/apache/airflow/pull/77071
The four OpenAI Agents SDK examples in common.ai built the SDK's client by hand from the connection's password and host: ```python llm = BaseHook.get_connection(LLM_CONN_ID) AsyncOpenAI(api_key=llm.password, base_url=llm.host or None) ``` The connection they read is an OpenAI connection (`openai_default`). That reads two fields and drops everything else [`OpenAIHook` builds the client from](https://github.com/apache/airflow/blob/0bc9e82ed258eab9d70a00fc419c1b07df7f9b77/providers/openai/src/airflow/providers/openai/hooks/openai.py#L230-L252): `openai_client_kwargs` in the extra (`base_url`, `api_key`, `timeout`, `organization`, `default_headers`, ...) and `auth_type: workload_identity`. Anyone who copies the examples gets a client that silently ignores those settings. A connection that sets `base_url` only in `openai_client_kwargs` sends its key to api.openai.com instead. The examples now get the client from the hook, with [`OpenAIHook.aget_conn()`](https://github.com/apache/airflow/blob/0bc9e82ed258eab9d70a00fc419c1b07df7f9b77/providers/openai/src/airflow/providers/openai/hooks/openai.py#L216-L228): ```python async with await OpenAIHook(LLM_CONN_ID).aget_conn() as client: agent = Agent(..., model=OpenAIChatCompletionsModel(model=LLM_MODEL, openai_client=client)) result = await run_durably(agent, question) ``` The guide's install line, connection description and durable/approval prose follow (`run_durably` in the examples, `run_durably_sync` still documented for sync code). ## Design rationale **Why the tasks became `async`.** The SDK's models take an `AsyncOpenAI`, and the only way `OpenAIHook` builds one is `aget_conn()`, a coroutine. An async task awaits it on the task's event loop and runs the agent with `await Runner.run(...)` / `await run_durably(...)`. The cost is that async tasks need Airflow 3.2.1+, while common.ai supports 2.11+; the guide gives older Airflow a one-sentence fallback (the old hand-built client, without the connection's other settings). The floor wording matches the [Pydantic AI hook's async section](https://github.com/apache/airflow/blob/0bc9e82ed258eab9d70a00fc419c1b07df7f9b77/providers/common/ai/docs/hooks/pydantic_ai.rst#L104). **Why not make common.ai depend on the openai provider.** The adapter (`run_durably`, `AirflowTools`, `AirflowTraceProcessor`) never touches the client; only the examples build one. So the provider is something the user installs alongside, listed in the guide's install command (`apache-airflow-providers-openai>=2.2.0`, the release that added `aget_conn`), not a dependency of common.ai. ## Validation End to end on Airflow main (LocalExecutor, Postgres) against a real model (`gpt-5.4-mini` behind an OpenAI-compatible gateway), with `openai-agents` 0.24.0: | Run | Result | |---|---| | `example_openai_agents_agent` | success; `list_tables` and two `query` tool calls, answer returned | | `example_openai_agents_durable` | success | | `example_openai_agents_approval` | paused in Required Actions twice, approved both via the HITL API; log shows `Durable: issue_refund approved by admin` and the task succeeded | | Connection with `base_url` only in `openai_client_kwargs`, no host: old hand-built client | `AuthenticationError: Error code: 401 - Your authentication token is not from a valid issuer` (the key went to api.openai.com) | | Same connection, `OpenAIHook(...).aget_conn()` | success, model answered | `example_openai_agents_data_access` needs a Postgres warehouse and an S3 bucket, so it was only parsed, not run. `airflow-core/tests/unit/always/test_example_dags.py -k openai_agents`: 12 passed. ## Follow-ups - A sync way to get an `AsyncOpenAI` from `OpenAIHook` would let sync tasks (and Airflow before 3.2.1) use the full connection too. - `PydanticAIHook` accepts only `pydanticai*` connections, so one OpenAI key is stored twice when a Dag uses both the SDK and `@task.agent`. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
