Skip to content

[AAASM-3528] 🐛 (adapters): Fix OpenAI Agents adapter to govern current API#158

Merged
Chisanan232 merged 1 commit into
masterfrom
v0.0.1/AAASM-3528/fix/openai_agents_adapter
Jun 22, 2026
Merged

[AAASM-3528] 🐛 (adapters): Fix OpenAI Agents adapter to govern current API#158
Chisanan232 merged 1 commit into
masterfrom
v0.0.1/AAASM-3528/fix/openai_agents_adapter

Conversation

@Chisanan232

Copy link
Copy Markdown
Contributor

Description

The Python SDK's OpenAI Agents adapter (agent_assembly/adapters/openai_agents/) targeted a stale framework API, so applying it was a silent no-op — agents running on the OpenAI Agents SDK were governed only in name and actually ran ungoverned (fail-open).

Root cause: the adapter patched openai.agents + FunctionTool.__call__. Neither exists in the shipped openai-agents framework: the package is the top-level agents module, and a tool is executed by the runner calling each tool instance's on_invoke_tool(ctx, args_json) coroutine — there is no __call__. Because that class attribute did not exist, the class-level patch never applied, and no pre-execution allow/deny or event emission ever fired.

Fix:

  • Detect and patch the real agents package (not openai.agents); is_available() now keys on agents.
  • FunctionTool.on_invoke_tool is a per-instance callable, not a class method, so it cannot be patched once on the class. The adapter now wraps FunctionTool.__init__ (and Handoff.__init__) so every constructed instance has its on_invoke_tool / on_invoke_handoff coroutine wrapped with the governance pre-execution check, deny/pending-approval handling, audit result recording, spawn-context tracking, and delegates_to topology-edge emission.
  • A denied tool now returns the framework's documented string error (sent back to the LLM) instead of executing — blocking the call without aborting the agent run. Runner.run (a real classmethod) is still wrapped for spawn context.
  • The adapter's public interface (OpenAIAgentsAdapter / OpenAIAgentsPatch with apply() / revert() / register_hooks() / unregister_hooks()) is unchanged and stays consistent with the LangChain/LangGraph adapters.

Type of Change

  • 🔧 Bug fix

Breaking Changes

  • No

Related Issues

  • Related JIRA ticket: AAASM-3528

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed

The unit and integration tests now drive the real per-instance on_invoke_tool contract — the integration suite installs the real agents framework (importorskip-guarded; openai-agents added as a dev/test dep) and drives a genuine function_tool exactly as the runner does. The tests assert governance actually fires (a denied tool returns a policy error and its body does not run; an allowed tool runs and is recorded), and they fail if the patch is reverted to a no-op — verified locally by stubbing the wrapper to a no-op and confirming both the unit and integration governance tests go red.

Local checks (all clean for the change):

  • uv run pytest — 584 passed, 13 skipped.
  • uv run ruff check / ruff format --check — clean for changed files (pre-existing ARG002 noise in test/bench/** predates this change and was reduced, not added).
  • uv run mypy agent_assembly — adapter clean; the 4 remaining package-wide errors are the pre-existing _core native-shim / grpc-stub baseline, unrelated to this change.
  • pre-commit run (isort/autoflake/black/mypy) — all pass.

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Comments added for complex logic
  • All tests passing

Closes AAASM-3528

🤖 Generated with Claude Code

The OpenAI Agents adapter targeted a stale framework API and was a
silent no-op, so agents on the OpenAI Agents SDK ran ungoverned
(fail-open). It patched `openai.agents` + `FunctionTool.__call__`, but
the shipped framework is the top-level `agents` package whose tools run
via a per-instance `on_invoke_tool(ctx, json)` coroutine — there is no
`__call__`, so the class-level patch never applied.

Fix:
- Detect and patch the `agents` package (not `openai.agents`).
- Wrap `FunctionTool.__init__` / `Handoff.__init__` so every instance's
  `on_invoke_tool` / `on_invoke_handoff` coroutine is wrapped with the
  pre-execution governance check, deny/pending handling, result
  recording, and topology-edge emission. Deny returns the framework's
  documented string error, blocking the call without aborting the run.
- Key `is_available()` on the real `agents` module.
- Add `openai-agents` as a dev/test dependency so the importorskip
  integration test drives a REAL tool call in CI.

Tests now drive the per-instance `on_invoke_tool` contract (and the real
framework via importorskip) and fail if the patch reverts to a no-op,
asserting genuine governance rather than just that apply() ran.

Closes AAASM-3528

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.52055% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
agent_assembly/adapters/openai_agents/patch.py 94.44% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

@Chisanan232

Copy link
Copy Markdown
Contributor Author

🤖 Claude Code — PR review (record)

CI: ✅ all green/skipped.

Scope vs AAASM-3528: ✅ fully covers it — and it's a real security fix (silent fail-open → governed). The adapter targeted a stale API (openai.agents + FunctionTool.__call__); the shipped framework is the top-level agents package whose tools run via per-instance on_invoke_tool (no __call__), so patch.apply() was a no-op and OpenAI-Agents agents ran ungoverned. Fix wraps FunctionTool.__init__ / Handoff.__init__ so every constructed instance's invocation hook is governed; is_available() keys on agents. Proven not-a-no-op: stubbing the wrapper to a no-op turns the new unit + integration tests red; restored, they pass. Full suite 584 passed / 13 skipped; ruff + mypy clean on changed files.

Verdict:Ready to approve & merge. Closes AAASM-3528. Unblocks the OpenAI-Agents live framework smoke (now landed real in #94).

@Chisanan232

Copy link
Copy Markdown
Contributor Author

This is the ref:
https://github.com/openai/openai-agents-python

@Chisanan232 Chisanan232 merged commit ff5f26c into master Jun 22, 2026
26 checks passed
@Chisanan232 Chisanan232 deleted the v0.0.1/AAASM-3528/fix/openai_agents_adapter branch June 22, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant