Skip to content

INF-2933 item 6: isolate OpenAI SDK + simplify tool factory#53

Open
declanatinference wants to merge 10 commits into
inf-2933-halo-cleanupfrom
inf-2933-item-6-isolate-sdk
Open

INF-2933 item 6: isolate OpenAI SDK + simplify tool factory#53
declanatinference wants to merge 10 commits into
inf-2933-halo-cleanupfrom
inf-2933-item-6-isolate-sdk

Conversation

@declanatinference
Copy link
Copy Markdown
Collaborator

@declanatinference declanatinference commented May 22, 2026

Summary

Lands items 6a, 6b, 6c from the INF-2933 HALO cleanup plan.

6a — single SDK boundary module. New engine/agents/openai_sdk_client.py re-exports the OpenAI Agents SDK and OpenAI client surface HALO uses (Agent, FunctionTool, RunConfig, RunContextWrapper, Runner, Tool, SdkToolContext, AsyncOpenAI, omit) and owns three helpers: build_async_openai_client, install_default_sdk_client (pins use_for_tracing=False), and is_retriable_llm_error. Eight engine modules (main.py, openai_agent_runner.py, compactor.py, engine_run_state.py, agent_context.py, synthesis_tool.py, tool_protocol.py, subagent_tool_factory.py) now go through the boundary instead of importing from openai or agents directly.

6b — drop the per-depth make_ctx closure. to_sdk_function_tool(tool, *, run_state, parent_context) now builds the ToolContext itself per invocation. The closure that _child_tools_for_depth rebuilt at every recursion depth is gone.

6c — extract subagent invocation, drop SDK AgentAsToolInput leak. Replaced the inline ~125-line guarded_invoke closure with a module-level _run_subagent_invocation (plus a thin SDK-annotated wrapper that's load-bearing for tool_call_id plumbing). Replaced AgentAsToolInput.model_validate_json(...).input with a local CallSubagentArgs(BaseModel) so the SDK's internal wrapper type stops leaking into HALO's call site.

Stacked on PR #50 — base is inf-2933-halo-cleanup, which GitHub will auto-retarget to main when that merges. Plan and notes live under docs/superpowers/plans/2026-05-19-inf-2933-item-6-isolate-sdk.md (gitignored).

Test plan

  • uv run ruff check engine/ tests/ — clean
  • uv run ruff format --check engine/ tests/ — clean
  • task test:unit — 298 passing (288 baseline + 10 new sdk_client tests)
  • task check — type-check pass (basedpyright kept spinning locally on an unrelated issue; will rerun on CI)
  • task test:integration — cross-platform integration suite
  • Sanity-run a single engine query end-to-end to confirm streaming + subagent paths still work

Note

Medium Risk
Moderate risk because it restructures how the OpenAI client/Agents SDK are imported and initialized, and refactors tool context construction and subagent invocation paths that affect runtime execution and error-handling behavior.

Overview
Centralizes all OpenAI/Agents SDK usage behind a new boundary module engine/agents/openai_sdk_client.py, re-exporting SDK/client symbols and adding helpers for client construction, default-client installation (always use_for_tracing=False), and retriable-error classification.

Updates the engine to route SDK client creation/installation and retry logic through that boundary (including moving _is_retriable_llm_error out of openai_agent_runner.py), and refactors tool wiring so to_sdk_function_tool() builds ToolContext directly from run_state/parent_context instead of a per-depth context_factory closure.

Simplifies subagent tooling by extracting the call_subagent execution into a module-level _run_subagent_invocation() and replacing the SDK-internal AgentAsToolInput dependency with a local CallSubagentArgs model; tests are updated and new unit coverage is added for the boundary helpers and lifecycle changes.

Reviewed by Cursor Bugbot for commit 053f587. Bugbot is set up for automated code reviews on this repo. Configure here.

Drop direct `openai.AsyncOpenAI` and `agents.set_default_openai_client`
imports from `engine.main`; build the per-run client via
`build_async_openai_client` and pin the SDK default via
`install_default_sdk_client`. The boundary module is now the single seam
for OpenAI SDK / Agents SDK construction in engine.main.

Tests that previously monkeypatched `engine.main.AsyncOpenAI` and
`engine.main.set_default_openai_client` are repointed at the new seam
(`build_async_openai_client` / `install_default_sdk_client`). The
`use_for_tracing=False` invariant is now verified inside the boundary's
own unit test, so the main test asserts only that the install routes
through the boundary helper.
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