Skip to content

Rework common.ai Strands support into a plugin and add Google ADK - #73898

Merged
kaxil merged 1 commit into
commonai-mask-tool-resultsfrom
commonai-native-frameworks
Sep 30, 2026
Merged

kaxil merged 1 commit into
commonai-mask-tool-resultsfrom
commonai-native-frameworks

Conversation

@kaxil

@kaxil kaxil commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #73587, which added Strands support through as_strands_tools(). A tool that kept raising ModelRetry, or kept failing argument validation, came back to the model as an error result every time, so a Strands agent could loop without end. Raising from the tool does not help: Strands catches any exception a function tool raises and hands it to the model as another error. as_strands_tools() has not been released yet, so this replaces it rather than deprecating it.

  • AirflowTools is now a Strands plugin. Its AfterToolCallEvent hook re-raises ToolCallError, which Strands raises out of the run as EventLoopException, so a failure the model cannot fix fails the task and Airflow's retry takes over.
  • Failures the model can correct are bounded by the tool's max_retries, counted as Pydantic AI counts them: once per tool per model turn, so calls a framework runs concurrently in one turn count once.
  • Google ADK: AirflowTools in tools.adk is an ADK toolset. A result reaches the model as {"result": ...}, a failure it can correct as {"error": ...}, and any other failure raises ToolCallError out of the run.
  • airflow_tools() moves to the shared toolset base, and collect_tools() turns the toolsets and tools an adapter is given into one list.
  • The LangChain bridge runs on the same interface: a correctable failure becomes a ToolMessage with status="error", and a tool that keeps failing raises ToolCallError.
  • SandboxToolset can own its sandbox from synchronous code with a with block, which a task running a native agent needs. A tool call outside the block is refused instead of provisioning a sandbox nothing would destroy. Attaching to another task's sandbox works from both forms.
  • MCPToolset.airflow_tools() raises: an MCP session belongs to the Pydantic AI run that opens it, so a native agent should use its framework's own MCP client.

Why one neutral interface under both adapters? Strands, ADK and the LangChain bridge now share one conversion, one error model and one retry budget, so an adapter for another framework is a thin mapping rather than a copy of those rules.

Why the Strands and ADK tests skip in CI. Strands pins mcp below 2.2 and ADK pins OpenTelemetry at 1.42.1 or lower, both below the versions in Airflow's development environment, so neither framework can be installed there. Both integrations are marked experimental, and the docs list the versions they are tested with (Strands 1.56.0, ADK 2.9.1).

An end-to-end Dag that runs every toolset through AgentOperator, a Pydantic AI agent, Strands, ADK and LangChain passes with a real Claude model and a Modal sandbox.

The end-to-end run, and the Strands routes from it:

Every route of the end-to-end Dag succeeded

Strands agent with Airflow toolsets

Strands agent running code in a Modal sandbox that is destroyed when the block ends


  • Read the 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) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

@kaxil
kaxil added this pull request to stack #73905 September 29, 2026 12:49
@kaxil kaxil closed this Sep 29, 2026
@kaxil kaxil reopened this Sep 29, 2026
@kaxil
kaxil marked this pull request as ready for review September 29, 2026 13:17
@kaxil
kaxil force-pushed the commonai-native-frameworks branch from 2ad375c to a291ac4 Compare September 29, 2026 14:03
The Strands adapter from #73587 built plain function tools, and Strands
hands any exception such a tool raises back to the model, so a tool that
kept raising ModelRetry looped without end. AirflowTools is now a Strands
plugin whose AfterToolCallEvent hook re-raises ToolCallError out of the
run, and failures the model can correct are bounded by the tool's
max_retries: counted once per tool per model turn and afresh on every
run, as pydantic-ai counts them. Tools a toolset marks sequential, such
as the sandbox's, run one at a time in the order the model called them.

AirflowTools in tools.adk gives an ADK agent the same tools. airflow_tools()
moves to the shared toolset base, collect_tools() flattens what an adapter
is given and refuses duplicate tool names, and the LangChain bridge runs
on the same interface. SandboxToolset can own its sandbox from
synchronous code with a with block, and MCPToolset refuses the native
path, since an MCP session belongs to the Pydantic AI run that opens it.
@kaxil
kaxil force-pushed the commonai-native-frameworks branch from a291ac4 to 2d96878 Compare September 30, 2026 06:01
@kaxil
kaxil merged commit 2b806f9 into main Sep 30, 2026
63 of 75 checks passed
@kaxil
kaxil deleted the commonai-native-frameworks branch September 30, 2026 06:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants