kaxil opened a new pull request, #73532:
URL: https://github.com/apache/airflow/pull/73532

   Airflow has five ways to invoke a vendor-hosted agent (Bedrock AgentCore, 
Vertex AI Agent Engine, Azure AI Foundry, Snowflake Cortex, Anthropic Managed 
Agents) and none of them share an argument name, a result shape or an error 
class. `BaseManagedAgentToolset` from #71946 was supposed to fix that. A month 
later it has zero implementations. The reason is structural: adopting it means 
subclassing a pydantic-ai toolset from inside a provider that still supports 
Airflow 2, which nobody can do.
   
   So this moves the common surface to where `DbApiHook` put it: the hook. 
`airflow.providers.common.ai.managed_agents` defines `BaseManagedAgentHook`, a 
mixin a vendor hook adopts next to its own base. The agent is an argument, like 
a statement is to `DbApiHook.run`. Three methods (`resolve_agent`, 
`agent_capabilities`, `invoke_agent`), typed request/response dataclasses, no 
pydantic-ai import. Amazon adopts it for AgentCore runtimes, Google for Agent 
Engine deployments. On top, written once: `ManagedAgentToolset` (any client of 
the contract becomes one tool for a calling model) and 
`FailoverManagedAgentClient` (clients composed across clouds).
   
   ```python
   claims = BedrockAgentCoreManagedAgentHook(aws_conn_id="aws_prod", 
region_name="us-east-1").agent(RUNTIME_ARN)
   AgentOperator(
       task_id="triage",
       llm_conn_id="anthropic_default",
       prompt="Review claim 4411 and decide whether to pay it.",
       toolsets=[ManagedAgentToolset(claims, tool_name="ask_claims_agent", 
description="Reviews an insurance claim.")],
   )
   ```
   
   ## Design rationale
   
   **Vendors take common.ai as an optional extra, exactly as they take 
common.messaging today.** common.ai needs Airflow 3.0; amazon and google still 
floor 2.11. There is already a pattern in the repo for a 3.x-only common base 
adopted by 2.x providers: `BaseMessageQueueProvider`. Guarded import raising 
`AirflowOptionalProviderFeatureException`, an extra in `pyproject.toml`, 
`pytest.importorskip` in the tests. The two adoptions here follow 
`aws/queues/sqs.py`. Plain `amazon` installs are untouched; pydantic-ai only 
arrives with `amazon[common.ai]`.
   
   **Type the intersection, pass the rest through.** Identity, prompt or 
messages, an optional session, a timeout, a text answer: those mean the same 
thing everywhere and are typed. The rest rides in `vendor_options` in and `raw` 
out. Each hook rejects options that would point the call somewhere else 
(another ARN, account, engine). The model sees `text`. Python callers get `raw`.
   
   **Why `ManagedAgentRejected` instead of `ModelRetry`.** The contract has to 
stay free of pydantic-ai or the guarded import stops being cheap. The toolset 
translates at the boundary. As it turns out neither adopted platform has a 
rephrase-class error anyway: AgentCore returns a container's complaints inside 
a 200, and Agent Engine's `INVALID_ARGUMENT` is an author mistake (wrong input 
key), not something a model can fix by rewording. Both hooks raise terminal 
errors or let transient ones through.
   
   **Failover over clients, not toolsets.** The removed 
`FailoverManagedAgentToolset` took toolsets as members but only ever called 
`invoke` on them, so a member's `tool_name`, `description` and `max_retries` 
did nothing. It also resolved every member's identity before the call, so a 
standby with a bad connection failed calls the primary would have answered. The 
new group takes clients, resolves identity only for logs and metric tags, logs 
which member answered, and refuses any request carrying a `session_id` (a 
failover starts a fresh conversation on the standby). A bound agent applies the 
same rule for a single hook whose capabilities do not include sessions.
   
   **`replayable` now does something.** #71946 declared it; nothing read it; 
`durable=True` replayed managed-agent calls from cache regardless. 
`CachingToolset` now runs the tool instead of replaying when the wrapped 
toolset says `replayable=False`, and it looks through `prefixed`, `filtered` 
and `CombinedToolset`, which do not carry the attribute.
   
   ## Migration path
   
   common.ai is 0.x and the old base had no subclasses in tree. Still, for 
anyone who tried it:
   
   - `FailoverManagedAgentToolset` is gone. Use 
`ManagedAgentToolset(FailoverManagedAgentClient([...]), ...)`.
   - `BaseManagedAgentToolset.agent_ref` returns a `ManagedAgentRef` rather 
than a `dict[str, str]`.
   - `managed_agent.served` loses `role` and `position`, gains `tool`. 
`managed_agent.failover` loses `tool`. `served` counts answers, `failover` 
counts transitions; read them next to each other. Which member answered is in 
the task log.
   
   The new amazon and google extras carry the `# use next version` marker for 
the release manager.
   
   ## Gotchas
   
   - Bedrock: one boto3 client per distinct request timeout, reused, so the 
toolset's `timeout` becomes connect/read timeout without a new session per tool 
call. Retries off unless the connection or caller set them. The connection's 
`config_kwargs` apply as for any AWS hook. Session ids are checked against 
AgentCore's 33 to 256 character bound before the call. Non-JSON, malformed or 
oversize bodies are terminal errors that name the agent and connection.
   - Agent Engine: the query path keeps no conversation state, so a 
`session_id` is refused rather than silently sent as a fresh call. Query jobs 
stay on `RunQueryJobOperator`, which can defer.
   - Not touched: Azure Foundry, Cortex, Anthropic. Cortex has PRs in flight 
and is the obvious next adoption. Anthropic's session-shaped agent wants an 
operator, not a toolset.
   
   Supersedes the toolset-only design of #71946.
   
   ---
   
   * Read the **[Pull Request 
Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)**
 for more information. Note: commit author/co-author name and email in commits 
become permanently public when merged.
   * For fundamental code changes, an Airflow Improvement Proposal 
([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvement+Proposals))
 is needed.
   * When adding dependency, check compliance with the [ASF 3rd Party License 
Policy](https://www.apache.org/legal/resolved.html#category-x).
   * For significant user-facing changes create newsfragment: 
`{pr_number}.significant.rst`, in 
[airflow-core/newsfragments](https://github.com/apache/airflow/tree/main/airflow-core/newsfragments).
 You can add this file in a follow-up commit after the PR is created so you 
know the PR number.
   


-- 
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