Skip to content

ENG-3760: export user-facing v2 names from the package root - #1167

Merged
aix-ahmet merged 8 commits into
developmentfrom
ENG-3760-root-imports
Oct 9, 2026
Merged

aix-ahmet merged 8 commits into
developmentfrom
ENG-3760-root-imports

Conversation

@elsheikhams99

@elsheikhams99 elsheikhams99 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

aixplain/__init__.py star-re-exports aixplain.v2.__all__, but several commonly used public classes were never in that list, so users, docs, tests and downstream repos had to write from aixplain.v2.<module> import X.

Add the missing user-facing names to aixplain/v2/__init__.py (imports + __all__), so from aixplain import Model, Integration, ModelResult, AgentRunResult, ToolResult, ActionSpec, ActionInputSpec, Result, Parameter, Usage, StreamChunk, Node, AUTO_DEFAULT_MODEL_ID, ... works. The versioned path keeps working unchanged.

Fix aixplain.exceptions shadowing: it carried v1-era ValidationError/ResourceError that nothing in aixplain.v2 raised, so from aixplain.exceptions import ValidationError silently caught nothing. It now re-exports the v2 classes the SDK actually raises; v1-only types stay in aixplain.exceptions.types.

  • Add tests/unit/v2/test_public_exports.py: every public class in aixplain/v2/ must be root-exported or on an explicit internal allowlist.
  • Rewrite SDK tests and docs to root imports; llms bundles use root imports.
  • Regenerate the API reference with a from aixplain import ... line on each page; docs/import-paths.md records the export-vs-internal rule.
  • CHANGELOG + MIGRATION "Import paths" carry the old -> new mapping.

Breaking changes (old → new)

Needs a UI/docs team ack before merge (ENG-3760).

aixplain.exceptions

  • aixplain.exceptions.ValidationError / ResourceError: v1 classes → the v2 classes the SDK raises (same objects as aixplain.ValidationError / aixplain.ResourceError). The v2 constructor is (message, details=None), and the v1 attributes (status_code, error_code, category) are gone.
  • aixplain.exceptions.{AixplainBaseException, AuthenticationError, AlreadyDeployedError, BillingError, SupplierError, NetworkError, ServiceError, InternalError, get_error_from_status_code} → deprecated in aixplain.exceptions (still resolve, with a DeprecationWarning; removed in 0.4.0); import them from aixplain.exceptions.types. The v1 ValidationError/ResourceError that get_error_from_status_code returns now also subclass the v2 classes, so except aixplain.ValidationError catches them.

API reference pages / api_sidebar.js entries (docs/api-reference/python/...)

  • aixplain/v1/** (124 sidebar entries) → removed (v1 was removed in 0.3.0)
  • aixplain/utils/{asset_cache, cache_utils, convert_datatype_utils, evolve_utils, file_utils, llm_utils, request_utils, validation_utils} → removed (modules no longer exist)
  • aixplain/v2/utility (page and sidebar entry) → removed (module removed with aix.Utility)
  • aixplain/v2/enums_include, aixplain/_compat, aixplain/cli_groups → removed from the sidebar (no page existed)
  • Added: aixplain/v2/graph, aixplain/v2/plain_data, aixplain/utils/url_safety
  • Every aixplain/v2/<module> page now starts with a `from aixplain import ...` line. Module paths and file names are unchanged.

Non-breaking (release notes only): 30 new root exports (see CHANGELOG). from aixplain.v2.<module> import X keeps working.

Follow-up: aixplain/aixplain-agents#461 switches agents to root imports and from_row (draft; blocked until an SDK release contains this).

`aixplain/__init__.py` star-re-exports `aixplain.v2.__all__`, but several
commonly used public classes were never in that list, so users, docs, tests
and downstream repos had to write `from aixplain.v2.<module> import X`.

Add the missing user-facing names to `aixplain/v2/__init__.py` (imports +
`__all__`), so `from aixplain import Model, Integration, ModelResult,
AgentRunResult, ToolResult, ActionSpec, ActionInputSpec, Result, Parameter,
Usage, StreamChunk, Node, AUTO_DEFAULT_MODEL_ID, ...` works. The versioned
path keeps working unchanged.

Fix `aixplain.exceptions` shadowing: it carried v1-era
`ValidationError`/`ResourceError` that nothing in `aixplain.v2` raised, so
`from aixplain.exceptions import ValidationError` silently caught nothing.
It now re-exports the v2 classes the SDK actually raises; v1-only types stay
in `aixplain.exceptions.types`.

- Add `tests/unit/v2/test_public_exports.py`: every public class in
  `aixplain/v2/` must be root-exported or on an explicit internal allowlist.
- Rewrite SDK tests and docs to root imports; llms bundles use root imports.
- Regenerate the API reference with a `from aixplain import ...` line on each
  page; `docs/import-paths.md` records the export-vs-internal rule.
- CHANGELOG + MIGRATION "Import paths" carry the old -> new mapping.

Breaking changes:
- `aixplain.exceptions.ValidationError` / `ResourceError` now resolve to the
  v2 classes the SDK raises (previously v1 look-alikes that caught nothing).
- `api_sidebar.js` drops stale `aixplain.v1.*` entries and `aixplain.utils.*`
  pages for modules that no longer exist (regenerated snapshot).

@elsheikhams99 elsheikhams99 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Self-review: request changes (small). The export change itself is correct: all 30 new root names are the same objects as the v2 originals, with no collisions. The guard test fails for each of the cases it targets. Two problems introduced by this PR should be fixed before review, plus a few nits. Fixes are coming in a follow-up commit on this branch.

Fix before review

1. aixplain.exceptions now mixes two hierarchies that disagree (aixplain/exceptions/__init__.py). I ran these checks on both base and branch:

base branch
isinstance(get_error_from_status_code(400), aixplain.exceptions.ValidationError) True False
same for 403/404/465 with ResourceError True False
ValidationError subclass of aixplain.exceptions.AixplainBaseException True False
aixplain.exceptions.ValidationError("x", status_code=400) works TypeError

The package's own helper now returns errors that its own ValidationError does not catch. It is the same "catches nothing" bug in the opposite direction. The only downstream user I found in the org is aixplain/agentification, which imports get_error_from_status_code. It catches with its own exception types, so nothing I could find breaks. Fix: document that get_error_from_status_code and AixplainBaseException belong to the v1 hierarchy, and list the constructor and base-class changes in the CHANGELOG/MIGRATION breaking-change notes.

2. docs/llms.txt lost its module descriptions. _extract_summary uses the first paragraph of each page, which is now the import line. As a result, 25 entries changed from text like "Agent module for aiXplain v2 SDK." to a bare `from aixplain import …` list. Fix: skip the import-line paragraph when extracting the summary.

Non-blocking

  • README.md:90 still has from aixplain.v2 import Inspector. Only docs/README.md was rewritten.
  • docs/import-paths.md:24 says *Type aliases, plain_data helpers and create_operation_failed_error are on the guard allowlist. The guard only inspects class statements, and create_operation_failed_error is exported from aixplain.exceptions.__all__.
  • The guard only sees class statements. A functional TypedDict or Union alias would slip through. Nothing slips through today: every unexported non-class name is an internal constant or TypeVar.
  • No test pins from . import exceptions in the root __init__. Removing it leaves all 195 guard tests green, while aixplain.exceptions becomes unbound after import aixplain.
  • post_process_docs.py is not idempotent: a second run adds a second import line to each page.
  • docs/rfcs/rfc-static-graph-agents.md:128 moves the not-yet-existing ParallelNode onto aixplain.v2.graph.
  • docs/api-reference/.../v2/utility.md is an orphan page for a removed module. This predates the PR.
  • The rewritten test imports add 8 lines over 120 characters.
  • Most of the 9.7k-line llms-full.txt diff is catch-up regeneration, since docs were last regenerated on 2026-07-24. It is not caused by this change.

Verified

  • Unit tests: 2602 passed and 3 failed on the branch, against 2407 passed and the same 3 failed on merge base fb549f5c. The failures are in test_client.py::TestRateLimitAndJitteredRetry and come from the local urllib3, which lacks Retry.retry_after_max. The extra 195 are the new guard tests.
  • Guard mutation tests: the guard fails on an unexported new class, on Model removed from __all__, and on exceptions/__init__.py reverted to base.
  • Lint: ruff 0.12.12 is clean on aixplain/v2.
  • Imports: importing aixplain.exceptions first causes no import cycle. The functional suite collects (186 tests).
  • Docs: all 180 from aixplain import names in the changed docs resolve. Every page in api_sidebar.js exists (base had 135 dangling entries). Regenerating llms*.txt and the API reference produces byte-identical output.
  • Not verified: the functional suite was not run (CI only ran pre-commit). I did not check the Jira ticket or the aixplain-agents follow-up.

- Document that aixplain.exceptions holds two hierarchies:
  get_error_from_status_code returns the v1 classes from
  aixplain.exceptions.types, which the re-exported v2 ValidationError /
  ResourceError do not catch. CHANGELOG and MIGRATION now list the full
  breaking change (v2 constructor, no v1 attributes, no longer
  AixplainBaseException subclasses).
- generate_llms_full.py: skip the `from aixplain import` line when
  extracting a module summary, so llms.txt keeps its descriptions.
- post_process_docs.py: replace an existing root-import line instead of
  adding a second one, so the script can be re-run.
- Tests: pin the root `aixplain.exceptions` binding (fresh interpreter)
  and the documented v1/v2 split; ruff-format the rewritten imports.
- Docs: root README/docs README use `from aixplain import Aixplain,
  Inspector`; import-paths.md states the guard only checks classes;
  RFC imports ParallelNode from the root; drop the orphaned
  v2/utility.md page; regenerate the two exceptions API pages.
Resolve conflict in aixplain/v2/__init__.py with #1168: keep ToolResult
alongside the new ToolBatch / SkillBatch exports.
Take development's README (#1161 removed the multi-agent section whose
import this branch had rewritten).
- aixplain.exceptions exports only the v2 classes the SDK raises. The v1
  hierarchy (AixplainBaseException, AuthenticationError, ...,
  get_error_from_status_code) is no longer re-exported, so the package no
  longer mixes two hierarchies whose same-named classes don't catch each
  other. It stays in aixplain.exceptions.types. CHANGELOG/MIGRATION list
  the removed re-exports.
- Drop create_operation_failed_error from aixplain.exceptions; the ticket
  keeps it internal (aixplain.v2.exceptions).
- AGENTS.md: point the exceptions rule at the v2 hierarchy and mention the
  public-exports guard test.
- post_process_docs.py: read aixplain/v2/__init__.py next to the script and
  fail loudly if missing; drop a stale root-import line when a module no
  longer exports anything.
- eval_dashboard/app.py, test_agent_eval.py: root imports.
- Regenerate the API reference and llms files for the merged
  ToolBatch/SkillBatch (#1168) and progress (#1153) changes.
aixplain-agents imports the private aixplain.v2.resource._flatten_asset_info
and re-implements Resource.get's deserialization by hand to build Model/Tool
handles from cached batch rows. Add GetResourceMixin.from_row: on a
client-bound class (aix.Model.from_row(row)) it does exactly what get() does
with the response -- flatten assetInfo, from_dict, bind context, record
server fields, mark saved -- without a request, and without mutating the
row.

Also move the tests merged from development (get_many, nested progress)
to root imports, and regenerate the resource API page and llms-full.txt.
- Inspector: get() now goes through an overridden _from_row hook that adapts
  the guard model via from_guard_model, so aix.Inspector.from_row(row)
  builds the same configured guard as get() instead of deserializing the
  guard model as an Inspector. One hook means get and from_row cannot drift.
- from_row deep-copies the row (as get_many does), so edits to the instance
  never reach a cached raw row.
- test_public_exports: an exported name must be the class defined in that
  module, catching a same-named class in another v2 module.
- docs/v2-plain-data.md: classify PromptTokensDetails and
  CompletionTokensDetails as output objects.
- post_process_docs.py: sort and de-duplicate names per module.
- aixplain/v2/__init__.py: ToolDict & co. are as_tool() output, not inputs.
Middle ground before dropping the v1 hierarchy from aixplain.exceptions:

- AixplainBaseException, AuthenticationError, AlreadyDeployedError,
  BillingError, SupplierError, NetworkError, ServiceError, InternalError and
  get_error_from_status_code resolve again from aixplain.exceptions through a
  module __getattr__ that emits a DeprecationWarning naming
  aixplain.exceptions.types and the 0.4.0 removal. They stay off __all__, so
  import aixplain and star-imports do not warn.
- The v1 ValidationError / ResourceError in aixplain.exceptions.types also
  subclass the v2 classes, so except aixplain.ValidationError catches what
  get_error_from_status_code returns. AixplainBaseException.__init__ calls
  super() first so the v2 base cannot reset details.
- CHANGELOG, MIGRATION and docs/import-paths.md describe the deprecation.
@aix-ahmet
aix-ahmet merged commit 4c6dec6 into development Oct 9, 2026
1 check passed
aix-ahmet added a commit that referenced this pull request Oct 9, 2026
#1159 added AgentError (the code/message of result.error) and #1167 added a
test that every public v2 class is exported or allowlisted; they merged
separately, so development's unit suite failed on it. It is exported like its
siblings AgentResponseData and AgentRunResult.
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.

2 participants