Skip to content

Introduce AWS Strands Agents hook to common AI provider and Skills integration - #67450

Open
gopidesupavan wants to merge 21 commits into
apache:mainfrom
gopidesupavan:add-strands-hook-gemini
Open

Introduce AWS Strands Agents hook to common AI provider and Skills integration#67450
gopidesupavan wants to merge 21 commits into
apache:mainfrom
gopidesupavan:add-strands-hook-gemini

Conversation

@gopidesupavan

Copy link
Copy Markdown
Member

Add Strands Agents hook to common AI provider

Summary

Add AWS Strands Agents as a new agent backend for AgentOperator and @task.agent in the common AI provider, building on the BaseAIHook contract.

  • Introduce StrandsHook (shared Strands SDK integration) and StrandsGeminiHook as the first backend (conn_type: strands-gemini, default connection ID: strands_default)

  • Wire toolsets through _tool_spec_to_native, converting ToolSpec instances to Strands-native tools

  • Add skills support end-to-end: SkillSpec dataclass on BaseAIHook, skills / skills_params on AgentRunRequest and AgentOperator, and Strands AgentSkills plugin integration for filesystem paths and inline skill definitions

  • Register the new connection type in provider.yaml / get_provider_info.py and add optional dependency:

    pip install 'apache-airflow-providers-common-ai[strands]'

    (strands-agents[gemini]>=1.0.0)

  • Add example DAGs (example_strands.py) covering basic operator usage, skills, inline SkillSpec + SQL toolset, direct hook usage, and @task.agent

  • Document connection setup, hook usage, and operator skills in new/updated RST pages

Depends on

BaseAIHook PR #67438


Follow-ups

Durable execution for Strands (durable=True)

StrandsHook currently sets supports_durable=False. A follow-up PR should mirror the pydantic-ai durable path so Strands agents can resume from cached steps on task retry.

Out of scope for this PR: usage limits for Strands hooks.

Skills for Pydantic AI (pydantic-ai-skills)

PydanticAIHook currently leaves supports_skills=False, so AgentOperator.skills / skills_params only work with Strands backends in this PR. A follow-up should wire the same operator-level skills API to pydantic-ai via the pydantic-ai-skills library (Agent Skills / agentskills.io spec with progressive disclosure).

Files changed

AreaFiles
Hookshooks/strands_ai.py, hooks/base_ai.py
Operatoroperators/agent.py
Examplesexample_dags/example_strands.py
Provider metadataprovider.yaml, get_provider_info.py, pyproject.toml
Docsdocs/connections/strands.rst, docs/hooks/strands_ai.rst, docs/operators/agent.rst, …
Teststests/unit/common/ai/hooks/test_strands_ai.py, test_base_ai.py, operators/test_agent.py

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

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

Comment threadproviders/common/ai/src/airflow/providers/common/ai/hooks/strands_ai.py Outdated
Comment threadproviders/common/ai/src/airflow/providers/common/ai/hooks/strands_ai.py Outdated
Comment threadproviders/common/ai/provider.yaml
@gopidesupavan

Copy link
Copy Markdown
MemberAuthor

Thanks you @kaxil — resolved comments.

@gopidesupavan
gopidesupavanforce-pushed the add-strands-hook-gemini branch from 56ab16f to 0d2ef3bCompareMay 27, 2026 10:43
Comment threadproviders/common/ai/src/airflow/providers/common/ai/hooks/strands_ai.py Outdated
Comment on lines +134 to +137
return AgentRunResult(
output=str(response),
model_name=self._resolved_model_id or self.model_id,
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructs AgentRunResult with only output and model_name, so usage and tool_names stay at their None defaults. log_run_summary then skips both the token counts (logging.py:35) and the tool-call sequence (logging.py:49) for Strands even when tools ran, whereas the pydantic-ai path populates both. Strands' result exposes usage metrics and a tool trace; mapping them into AgentUsage / tool_names here would match the pydantic-ai path. Use getattr(..., None) guards if the metrics shape varies across SDK versions. (Low priority: no crash, just missing observability.)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this needs refactor , will updated..

@github-actions

github-actionsBot commented May 29, 2026

Copy link
Copy Markdown
Contributor

uv.lock on main just moved via #72058 ("Fix linux/arm64 CI image build broken by the ibm.db2 provider"), commit 57a0519 and this PR currently conflicts.

Quickest fix:

git fetch upstream main && git rebase upstream/main
rm uv.lock && uv lock
git add uv.lock && git rebase --continue
git push --force-with-lease

Automated nudge — ignore if you're not ready to rebase. This comment is updated in place on future uv.lock bumps.

@gopidesupavan
gopidesupavanforce-pushed the add-strands-hook-gemini branch from 0d2ef3b to a2bf153CompareMay 31, 2026 21:28

@aaron-y-chenaaron-y-chen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A potential bug I found, I hope this helps :)

return Agent(
model=self.get_model(),
tools=native_tools or [],
structured_output_model=request.output_type,

@aaron-y-chenaaron-y-chenAug 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I found that an AttributeError occurs when I run the code below, is this the expected behavior?

fromstrandsimportAgentfromstrands.modelsimportModelclassFakeModel(Model):
defget_config(self): return {}
defupdate_config(self, **kw): passasyncdefstream(self, *a, **k):
raiseAssertionError("should never reach inference")
asyncdefstructured_output(self, *a, **k):
raiseAssertionError("should never reach inference")
agent=Agent(model=FakeModel(), tools=[], structured_output_model=str)
print("Agent constructed OK")
agent("hello")
  • Output: AttributeError: type object 'str' has no attribute 'model_json_schema'
  • strands-agents version: 1.41.0

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you using this hook @aaron-y-chen ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran another experiment and reproduced it through StrandsGeminiHook itself, against a real connection (my own Gemini API key, model gemini-3.6-flash):

Repro code
importjsonimportosfromunittest.mockimportpatchfromairflow.models.connectionimportConnectionfromairflow.providers.common.ai.hooks.baseimportAgentRunRequestfromairflow.providers.common.ai.hooks.strands_aiimportStrandsGeminiHookhook=StrandsGeminiHook()
conn=Connection(
conn_id="strands_default",
conn_type="strands-gemini",
password=os.environ.get("GOOGLE_API_KEY", "unused"),
extra=json.dumps({"model": "gemini-3.6-flash"}),
)
request=AgentRunRequest(prompt="Reply with the single word: pong") # output_type defaults to strwithpatch.object(hook, "get_connection", return_value=conn):
agent=hook.create_agent(request)
hook.run_agent(agent, request)
# AttributeError: type object 'str' has no attribute 'model_json_schema'

Sign up for freeto 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.

3 participants

@gopidesupavan@kaxil@aaron-y-chen