Uh oh!
There was an error while loading. Please reload this page.
Introduce AWS Strands Agents hook to common AI provider and Skills integration - #67450
Introduce AWS Strands Agents hook to common AI provider and Skills integration#67450gopidesupavan wants to merge 21 commits into
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
gopidesupavan
commented
May 25, 2026
Thanks you @kaxil — resolved comments. |
56ab16f to
0d2ef3bCompareUh oh!
There was an error while loading. Please reload this page.
| return AgentRunResult( | ||
| output=str(response), | ||
| model_name=self._resolved_model_id or self.model_id, | ||
| ) |
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
Yeah this needs refactor , will updated..
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-leaseAutomated nudge — ignore if you're not ready to rebase. This comment is updated in place on future |
0d2ef3b to
a2bf153Compare
aaron-y-chen
left a comment
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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-agentsversion: 1.41.0
There was a problem hiding this comment.
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'
Add Strands Agents hook to common AI provider
Summary
Add AWS Strands Agents as a new agent backend for
AgentOperatorand@task.agentin the common AI provider, building on theBaseAIHookcontract.Introduce
StrandsHook(shared Strands SDK integration) andStrandsGeminiHookas the first backend (conn_type:strands-gemini, default connection ID:strands_default)Wire toolsets through
_tool_spec_to_native, convertingToolSpecinstances to Strands-native toolsAdd skills support end-to-end:
SkillSpecdataclass onBaseAIHook,skills/skills_paramsonAgentRunRequestandAgentOperator, and StrandsAgentSkillsplugin integration for filesystem paths and inline skill definitionsRegister the new connection type in
provider.yaml/get_provider_info.pyand 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, inlineSkillSpec+ SQL toolset, direct hook usage, and@task.agentDocument 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)StrandsHookcurrently setssupports_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)PydanticAIHookcurrently leavessupports_skills=False, soAgentOperator.skills/skills_paramsonly work with Strands backends in this PR. A follow-up should wire the same operator-level skills API to pydantic-ai via thepydantic-ai-skillslibrary (Agent Skills / agentskills.io spec with progressive disclosure).Files changed
hooks/strands_ai.py,hooks/base_ai.pyoperators/agent.pyexample_dags/example_strands.pyprovider.yaml,get_provider_info.py,pyproject.tomldocs/connections/strands.rst,docs/hooks/strands_ai.rst,docs/operators/agent.rst, …tests/unit/common/ai/hooks/test_strands_ai.py,test_base_ai.py,operators/test_agent.pyWas generative AI tooling used to co-author this PR?
{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.