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]

Reply via email to