Repository navigation
fix(AIC-3598)!: make Python packaging and public types GA-ready - #218
Conversation
- Production/Stable classifiers on all 14 packages (vercel-* had none). - Raise third-party floors that crossed a breaking line to the tested versions in uv.lock (langchain-core, langgraph, openai, openai-agents, anthropic, httpx, typesafe-sdk). - Add an optional [ld] extra for launchdarkly-server-sdk on launchdarkly-ai-server and launchdarkly-ai-python; READMEs install it. - LDClientInterface becomes a Protocol that ldclient.LDClient satisfies; init_client and get_client return it. - Handler protocol and every handler type tool_handlers as dict[str, Callable | NativeTool]; offline evaluations pass a NativeTool through unwrapped, so langchain-agents now guards with callable(). - Native graph adapters take Awaitable[GraphDefinition], a per-package options TypedDict, and return NativeGraphRunner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…heck - scripts/check_packaging.py (make check-packaging, CI job "packaging") installs each wheel into an empty virtualenv with its documented install command, imports every public module and __all__ name, and checks every module the source imports unconditionally is installed, lazy importlib.import_module calls included. Internal dependencies resolve to this commit's wheels; third-party ones from PyPI. - The check found langchain-agents and langchain-messages importing langchain_openai and langchain_anthropic without declaring them, the Python side of the JS @langchain/anthropic gap. langchain-agents now depends on langchain-openai (its default model) and offers [anthropic] and [aws] extras; langchain-messages offers [openai], [anthropic], [aws]. The Anthropic and OpenAI imports are guarded with an install hint, like Bedrock's. - README: document the 1.0 versioning rule (lockstep per language). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itle Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…angchain/anthropic (#170) TypeScript half of [AIC-3598](https://launchdarkly.atlassian.net/browse/AIC-3598). The spec is in launchdarkly/ai-sdks-monorepo#91 (TESTING.md §5.3, §1.4, A.21). The Python half is launchdarkly/python-ai-sdk#218. ## Changes - **`toolHandlers` on the handler contract.** `ProviderHandler.stream` and `createHandler`'s input types took `Record<string, any>`. They now take `Record<string, ToolHandlerFn | NativeTool>`, which matches the blocking call signature and what apps already pass. - The union is the real contract, not functions only: offline evaluations (`evaluations-runner.ts`) pass the trajectory recorder's map to the handler without `wrapToolHandlers`, so a `NativeTool` arrives unwrapped. - Five handlers typed the map narrower, which the old `any` hid: `claude-agents`, `claude-messages`, `langchain-agents`, `litellm-messages` and `openai-messages`. They now accept the union. - Runtime behavior is unchanged, except in `claude-agents`' MCP tool executor. It now guards with `typeof handler !== 'function'`, so a raw `NativeTool` gets the "No handler registered" error instead of `handler is not a function`. There's a test, and it fails without the fix. - **`@langchain/anthropic`** is declared by `@launchdarkly/ai-langchain-agents` as an optional peer plus a devDependency, the same pattern as `@langchain/aws`. The package dynamically imports it for Anthropic nodes. `toolHandlers` on the app-facing API was already typed. - **`zod`** is declared by `@launchdarkly/ai-langchain-agents` (`^4.4.3`, like its siblings). `native-graph.ts` imports it statically and was getting it through LangChain. - **Packaging check, `yarn check:packaging`**, added to the CI build job: - It fails when a package's built `dist` imports a package it doesn't declare, static or dynamic. - It then packs every workspace, installs all the tarballs into one empty project, and loads every `exports` subpath through both `require()` and `import()`. - The scan has unit tests (`yarn test:check-packaging`). It found the `zod` gap above. - **README** documents the 1.0 rule: from 1.0.0, every package is released at the same version. ## Breaking (the reason for the `!`) `ProviderHandler.stream`'s declaration changed, so `scripts/api-breaking.mjs` will flag it. A custom handler whose `stream` typed `toolHandlers` narrower than the union no longer type-checks. Before 1.0 the `!` bumps the minor version, and AIC-3673 cuts 1.0 next. If owners judge it compatible, `api-compatible` is the alternative. ## Checks - `yarn build`, `yarn typecheck` (0 errors), `yarn code:check`, `yarn sherif` - `yarn api:check` (only `ai-server.api.md` changed, the `stream` line) and `yarn api:surface` - `yarn test`: every workspace passes - `yarn check:packaging`: 14 packages declare every import, and all 16 entry points load - `yarn.lock` is unchanged ## Known, out of scope - `@langchain/anthropic@1.5.1` (the pinned dev version, as in `langchain-messages`) asks for `@langchain/core@^1.2.1`, while the lockfile resolves 1.1.49. That predates this change. - In both SDKs, `claude-agents` recognises a native tool only through the tracking stub's `NATIVE_TOOL_KEY`. On the offline evaluations path a raw `NativeTool` is therefore not wired to Claude's built-in tool. That's an evaluations behavior, so it's left for a follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) [AIC-3598]: https://launchdarkly.atlassian.net/browse/AIC-3598?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Tightens the public **handler contract** so `toolHandlers` is consistently `Record<string, ToolHandlerFn | NativeTool>` on blocking and streaming paths (replacing `Record<string, any>` on `ProviderHandler.stream` and internal handler helpers). Provider packages that narrowed the map are aligned, and **claude-agents** MCP execution now rejects unwrapped `NativeTool` values (offline evaluations) with the same “no handler” error instead of calling a non-function. > > **Packaging and release hygiene:** adds `yarn check:packaging` (plus unit tests and CI after full build) to flag undeclared imports in built `dist` and to verify packed tarballs install and every export loads via `require()` and `import()`. **@launchdarkly/ai-langchain-agents** declares missing **`zod`** and optional peer **`@langchain/anthropic`** for its dynamic Anthropic import. README documents **lockstep versioning from 1.0.0**. > > **Breaking:** `ProviderHandler.stream`'s `toolHandlers` type changed; custom handlers with a narrower `stream` signature may need updates. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit dd78326. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts resolved by keeping both sides: - claude-agents: ClaudeNativeGraphOptions export plus main's skills handler. - openai-agents: OpenAINativeGraphOptions plus main's create_openai_agents_handler rename; build_output_type stays private, as main made it in #224. - opencode-agents handler: main's secrets import plus this branch's NativeTool. - API reports regenerated with make api-report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
XieX
left a comment
There was a problem hiding this comment.
A few comments from a review pass, each checked against the code at this head:
- The biggest one is the
LDClientInterface.track()contract (types.py): the new docstring and return type allow an asynctrack, but the SDK never awaits it. - The rest are about packaging-check coverage,
tool_handlerstyping, dependency floors, install hints and CI speed.
…e packaging check - LDClientInterface.track() is typed -> None again and documented as synchronous: no call site awaits it, so an async track would drop every $ld:ai:* event. - tool_handlers takes Mapping[str, Callable[..., Any] | NativeTool] everywhere it is only read, so a caller's precisely typed dict is accepted; drops the dict() copies. - check_packaging installs every declared extra in its own venv and imports what it promises; an extra with no EXTRA_IMPORTS entry fails. Override extras are derived from pyproject. Runs go through a thread pool with buffered output. - LangChain install hints name the package extra; the READMEs list the extras. - README states that dependency floors are the CI-tested versions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jeffdupont
left a comment
There was a problem hiding this comment.
Re-review of 1304692. Four of the six earlier points are resolved: track() is synchronous again, tool_handlers is a Mapping, the extras are installed and import-checked, and the install hints name the extras. A mypy probe against the head types accepts a real ldclient.LDClient, rejects a client with async def track, and accepts a dict[str, Callable[[dict[str, Any]], str]] passed as tool_handlers. I found no call site that awaits track(), and none that mutates tool_handlers.
Three things are still open:
- The packaging check can't fail on an undeclared import that another dependency installs. Today
pydanticis imported unconditionally by openai-agents, litellm-agents, vercel-agents and vercel-messages, andopenaiby litellm-agents, and none of them declares it. TESTING.md section 5.3 in ai-sdks-monorepo#91 requires each one to be declared. - Core's import scan only runs in a venv that has
[ld]installed. An unguardedimport ldclientin core would pass, even though section 5.3 says core must load without the base SDK. - The internal floor is still
launchdarkly-ai-server>=0.4.1. No 0.4.1 release exists, and the handlers now importNativeGraphRunner, which the published 0.5.0 does not have. #242 raises the floor to>=1.0.0,<2, so this PR is only safe if #242 merges before the next release PR.
The floors policy (your point 4) is now written down, but its wording disagrees with the spec text and with some of the floors. See the inline comment on README.md.
…out extras - check_packaging: an unconditional import must come from a distribution the package declares. Installed is no longer enough: a module another dependency pulls in fails. Base runs install with no extras, so core is proven to load without launchdarkly-server-sdk; [ld] is now an extra run like the others. - Declare what the stricter check found: pydantic in openai-agents, litellm-agents, vercel-agents and vercel-messages; openai in litellm-agents. - Internal pins: launchdarkly-ai-server>=1.0.0,<2 everywhere. The native graph adapters import NativeGraphRunner, which published server 0.5.0 lacks. - README states the floor rule spec 5.3 uses: same major as the tested version for 1.x+, same minor for 0.x. - Tests: core is checked without extras, an undeclared dynamic import fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…resolves >=1.0.0,<2 could not resolve if a release went out before release-as 1.0.0 lands (Bugbot). >=0.6 still excludes server 0.5.0, which lacks NativeGraphRunner; this PR's breaking change makes core's next 0.x release 0.6.0, and 1.0.0 satisfies it too. #242 tightens it to >=1.0.0,<2 at the cut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g-ga # Conflicts: # packages/client/api-report/launchdarkly_ai_server.txt
XieX
left a comment
There was a problem hiding this comment.
Thanks for working through all of this. I checked each fix at this head: track() is synchronous and documented that way, tool_handlers is a Mapping with the copies gone, every extra is installed and import-checked, the install hints name the extras, the checks run in parallel, and the floor rule is written down. The declared-distribution check, the core-without-extras run and the >=0.6,<2 internal floor all look right too. Release PR #231 already takes core to 0.6.0, so the floor resolves whichever release goes out first.
Approving. A few non-blocking nits, none of which need to hold this up:
- Private-spec reference. The module docstring of
tests/test_check_packaging.py(line 1) cites the private spec document and a section number. #234, merged to main today but not yet in this branch, removed every such reference from the.pyfiles, so merging this would add one back. Stating the rule in plain words, as #234 did elsewhere, would fix it. The PR description cites section numbers as well. - Namespace packages in the declared-import check (latent). The scan reduces each import to its top-level name, so a module like
opentelemetrymaps to several distributions. A future unguarded lazyfrom opentelemetry.sdk ...in core would pass, becauseopentelemetry-apiis declared, even thoughopentelemetry-sdkis only in[otel]. Every such import in core is guarded today, so nothing is broken. Mapping the full dotted module to its distribution (or special-casing namespace packages) would close the gap. - LangChain default-model consistency. Both LangChain packages default to OpenAI, but langchain-agents depends on
langchain-openaidirectly while langchain-messages offers it as[openai]. A barepip install launchdarkly-ai-langchain-messagestherefore fails on its default path, though with a clear hint. If that difference is intentional, ignore this.
…chain-openai is a dependency Review nits from XieX: - check_packaging keeps each import's full dotted name and maps it to the distribution that owns its file, so a namespace package such as opentelemetry.sdk needs opentelemetry-sdk declared, not any opentelemetry-*. It found langgraph.prebuilt (from langgraph-prebuilt) undeclared in langchain-agents; declared at >=1.1. - langchain-messages depends on langchain-openai, its default model, as langchain-agents does, so a bare install works; the [openai] extra is gone. - The test module docstring no longer cites the private spec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @XieX. All three nits are in f3fbe8a:
Local: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f3fbe8a. Configure here.
launchdarkly-server-sdk is now an extra, so an install without it succeeds and then init_client() raises. The handler and barrel READMEs and the client telemetry install now match the root README and the other handlers (Bugbot). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes main's pyproject.toml files (with #218's new dependencies) and keeps this branch's internal pin, launchdarkly-ai-server>=1.0.0,<2, in all 13. Also fixes release-please-config.json: 12727f3 wrote the release-as lines with literal backslashes (\"release-as\": \"1.0.0\"), which is invalid JSON. The file now parses, with release-as 1.0.0 on all 14 packages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Steps 1 and 2 of [AIC-3672](https://launchdarkly.atlassian.net/browse/AIC-3672). The JS half is AIC-3673. ## What this does - **`release-as: 1.0.0`** on all 14 packages in `release-please-config.json`. Without it, release-please keeps bumping 0.x minors, so the next release PR would ship `launchdarkly-ai-server` 0.6.0 instead of 1.0.0. - **Internal pins.** Every package that depends on `launchdarkly-ai-server` now requires `>=1.0.0,<2`. release-please doesn't update these for Python. #218 (merged) set them to `>=0.6,<2` so either release order resolves; this tightens them to the 1.0 line. - **`uv.lock`** needs no change: uv records workspace dependencies without a version specifier. `uv lock --check` passes. `changelog-sections` is left alone. #235 removes the evaluations Experimental rows when it promotes Evaluations from Code to core. ## Merge this last Merge this after the PRs below. Anything merged before the release PR (#231) merges ships in 1.0.0, and a `!` change merged after 1.0 forces 2.0. - [x] #218 fix(AIC-3598)!: packaging and public types (merged 29 Oct) - [x] #235 feat(evaluations)!: promote Evaluations from Code to core (merged 29 Oct). After it merges, nothing in `launchdarkly_ai_server.experimental` is public. - [x] #237 fix(claude-agents)!: honour max_tokens and disable thinking by default (merged 29 Oct) - [ ] #136 feat(AIC-3439): wildcard handlers accept only named providers (approved; conflicts with main, needs a merge of main) - [x] #234 fix(AIC-3568)!: give the barrel core's `__all__` (merged 29 Oct) - [ ] #246 fix(AIC-3592): make native LangGraph hand-offs complete (spec launchdarkly/ai-sdks-monorepo#118) - [ ] #248 fix(AIC-3573): never send a NativeTool to the model as a function tool (spec launchdarkly/ai-sdks-monorepo#116) - [ ] #240 feat(client): add result variant and value to the feature_flag span event (approved, mergeable) - [ ] #251 fix(AIC-3716): build OpenAI native graph node tools with FunctionTool (review required; touches the same loop as #248) #241 (Shadow Requests) is closed; 1.0 ships with nothing experimental. ## After merging 1. Confirm the regenerated #231 lists 1.0.0 for all 14 packages, then merge it. 2. Install each package from PyPI into an empty venv and import its public entry points (AIC-3672 step 5). 3. Open a PR removing `release-as` straight away, or every later release PR proposes 1.0.0 again. ## Checks - `release-please-config.json` parses as JSON, with `release-as: 1.0.0` on all 14 packages. The first push wrote the lines with literal backslashes; fixed in d720896. - `make test`: 3,711 passed, 18 skipped (before #175 and #236 merged; CI is the current check) (with the parent checkout's `.env` LD URIs blanked; see AIC-3593) - `uv lock --check` passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) [AIC-3672]: https://launchdarkly.atlassian.net/browse/AIC-3672?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Prepares the **1.0.0 GA** cut for all 14 Python packages by teaching release-please to release **1.0.0** instead of another **0.x** bump. > > Adds **`release-as: "1.0.0"`** on every entry in `release-please-config.json` (core `launchdarkly-ai-server`, barrel, and all handler packages). > > Tightens **internal PyPI pins** from `launchdarkly-ai-server>=0.6,<2` to **`>=1.0.0,<2`** in each handler `pyproject.toml` and in `packages/ai` (including **`otel`** / **`ld`** extras). Published wheels will require the 1.0 server line once those versions ship. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ae9f2cc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: andrewklatzke <aklatzke@launchdarkly.com>
🤖 I have created a release *beep* *boop* --- <details><summary>launchdarkly-ai-server: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-server-0.5.0...launchdarkly-ai-server-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **client:** init_client raises when the LaunchDarkly client did not initialize ([#254](#254)) * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ * **AIC-3439:** let wildcard handlers accept only named providers * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **evaluations:** promote Evaluations from Code to core ([#235](#235)) * **client:** capture conversation content by default ([#213](#213)) * **evaluations:** remove default pass rate threshold ([#238](#238)) * **evaluations:** set default pass rate threshold ([#226](#226)) * **client:** spans carry launchdarkly.project_id instead of highlight.project_id * **AIC-3687:** rename create_openai_agent_handler to create_openai_agents_handler ([#225](#225)) * **skills:** rename FDv2SkillStore to LaunchDarklySkillStore ([#223](#223)) ### Features * **AIC-3439:** let wildcard handlers accept only named providers ([454a4de](454a4de)) * **AIC-3687:** rename create_openai_agent_handler to create_openai_agents_handler ([#225](#225)) ([a7cdbc0](a7cdbc0)) * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) * **client:** point judge spans at the run they graded ([#253](#253)) ([863d423](863d423)) * **evaluations:** promote Evaluations from Code to core ([#235](#235)) ([0bc43a5](0bc43a5)) * **evaluations:** remove default pass rate threshold ([#238](#238)) ([882d099](882d099)) * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ ([454a4de](454a4de)) * **evaluations:** set default pass rate threshold ([#226](#226)) ([7ee368c](7ee368c)) * **skills:** rename FDv2SkillStore to LaunchDarklySkillStore ([#223](#223)) ([11f2c0b](11f2c0b)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **AIC-3601:** stop graph routing text inviting a router to answer for its target ([#230](#230)) ([27b8d09](27b8d09)) * **client:** init_client raises when the LaunchDarkly client did not initialize ([#254](#254)) ([6e66c00](6e66c00)) * **client:** stamp launchdarkly.project_id on the telemetry resource ([#229](#229)) ([5347558](5347558)) * **evaluations:** copy inline tool schemas and name both sources on a key collision ([#227](#227)) ([bfbdd4c](bfbdd4c)) * **evaluations:** send criterion errors as errorMessage and skip criteria for rows that did not generate ([#228](#228)) ([8b05b56](8b05b56)) * **graph:** report a node's own judge scores on its node_done stream event ([#236](#236)) ([2f3f9ee](2f3f9ee)) ### Documentation * **AIC-3692:** say which project id attribute the telemetry resource carries ([#239](#239)) ([64eff43](64eff43)) * state that Agent Skills and Evaluations from Code need 1.0.0 ([#191](#191)) ([fe3ef08](fe3ef08)) </details> <details><summary>launchdarkly-ai-python: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-python-0.4.0...launchdarkly-ai-python-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **evaluations:** promote Evaluations from Code to core ([#235](#235)) ### Features * **evaluations:** promote Evaluations from Code to core ([#235](#235)) ([0bc43a5](0bc43a5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) ### Documentation * state that Agent Skills and Evaluations from Code need 1.0.0 ([#191](#191)) ([fe3ef08](fe3ef08)) </details> <details><summary>launchdarkly-ai-claude-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-claude-agents-0.3.0...launchdarkly-ai-claude-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **claude-agents:** honour the config's max_tokens and disable thinking unless the config asks ([#237](#237)) * **client:** capture conversation content by default ([#213](#213)) * **AIC-3685:** make the internal provider helpers private ([#224](#224)) * **skills:** rename FDv2SkillStore to LaunchDarklySkillStore ([#223](#223)) ### Features * **AIC-3685:** make the internal provider helpers private ([#224](#224)) ([9afdb94](9afdb94)) * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) * **skills:** rename FDv2SkillStore to LaunchDarklySkillStore ([#223](#223)) ([11f2c0b](11f2c0b)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **claude-agents:** honour the config's max_tokens and disable thinking unless the config asks ([#237](#237)) ([a7ded1b](a7ded1b)) </details> <details><summary>launchdarkly-ai-claude-messages: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-claude-messages-0.3.0...launchdarkly-ai-claude-messages-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **AIC-3735:** send Claude Messages sampling parameters through extra_body ([#256](#256)) ([c6d0376](c6d0376)) </details> <details><summary>launchdarkly-ai-openai-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-openai-agents-0.3.0...launchdarkly-ai-openai-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) * **AIC-3685:** make the internal provider helpers private ([#224](#224)) * **AIC-3687:** rename create_openai_agent_handler to create_openai_agents_handler ([#225](#225)) ### Features * **AIC-3685:** make the internal provider helpers private ([#224](#224)) ([9afdb94](9afdb94)) * **AIC-3687:** rename create_openai_agent_handler to create_openai_agents_handler ([#225](#225)) ([a7cdbc0](a7cdbc0)) * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **AIC-3716:** build OpenAI native graph node tools with FunctionTool ([#251](#251)) ([b859b67](b859b67)) * **AIC-3726:** realign three usage IDs with the 1.0 factory names ([#252](#252)) ([1c4d904](1c4d904)) </details> <details><summary>launchdarkly-ai-vercel-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-vercel-agents-0.2.0...launchdarkly-ai-vercel-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-litellm-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-litellm-agents-0.2.0...launchdarkly-ai-litellm-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-openai-messages: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-openai-messages-0.3.0...launchdarkly-ai-openai-messages-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **AIC-3726:** realign three usage IDs with the 1.0 factory names ([#252](#252)) ([1c4d904](1c4d904)) </details> <details><summary>launchdarkly-ai-vercel-messages: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-vercel-messages-0.2.0...launchdarkly-ai-vercel-messages-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-litellm-messages: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-litellm-messages-0.2.0...launchdarkly-ai-litellm-messages-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-langchain-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-langchain-agents-0.3.0...launchdarkly-ai-langchain-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ * **AIC-3439:** let wildcard handlers accept only named providers * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **AIC-3439:** let wildcard handlers accept only named providers ([454a4de](454a4de)) * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ ([454a4de](454a4de)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3590:** build Python langchain-agents with langchain.agents.create_agent ([#175](#175)) ([8218626](8218626)) * **AIC-3592:** make native LangGraph hand-offs complete ([#246](#246)) ([bfb738f](bfb738f)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-langchain-messages: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-langchain-messages-0.3.0...launchdarkly-ai-langchain-messages-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ * **AIC-3439:** let wildcard handlers accept only named providers * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **AIC-3439:** let wildcard handlers accept only named providers ([454a4de](454a4de)) * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) * **evaluations:** route generation and judges to a scoped wildcard handler only for its named providers, and accept two scoped wildcards of one mode when their lists differ ([454a4de](454a4de)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3573:** never send a NativeTool to the model as a function tool ([#248](#248)) ([73caeae](73caeae)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) * **AIC-3726:** realign three usage IDs with the 1.0 factory names ([#252](#252)) ([1c4d904](1c4d904)) </details> <details><summary>launchdarkly-ai-opencode-agents: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-opencode-agents-0.3.0...launchdarkly-ai-opencode-agents-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> <details><summary>launchdarkly-ai-typesafe: 1.0.0</summary> ## [1.0.0](launchdarkly-ai-typesafe-0.2.0...launchdarkly-ai-typesafe-1.0.0) (2026-10-30) ### ⚠ BREAKING CHANGES * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) * **client:** capture conversation content by default ([#213](#213)) ### Features * **client:** add result variant and value to the feature_flag span event ([#240](#240)) ([040d487](040d487)) * **client:** capture conversation content by default ([#213](#213)) ([77a7cf5](77a7cf5)) ### Bug Fixes * **AIC-3568:** give the barrel core's __all__, and drop private-spec references ([#234](#234)) ([88e57e6](88e57e6)) * **AIC-3598:** make Python packaging and public types GA-ready ([#218](#218)) ([5860b40](5860b40)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > This is a **Release Please** cut that moves every monorepo package to **1.0.0** and records the GA release in changelogs. It updates `.release-please-manifest.json`, each package’s `pyproject.toml` / `__version__`, and prepends **1.0.0** notes to every `CHANGELOG.md`. > > Handler and barrel packages now require **`launchdarkly-ai-server>=1.0.0,<2`**, so installs must upgrade the core client in lockstep with adapters. > > There is **no new application logic** in this diff—only release metadata. The changelog text still matters for reviewers: it summarizes breaking work already on `main`, including **Evaluations from Code promoted to core**, **conversation content captured by default**, **`init_client` failing when LD init fails**, telemetry **`launchdarkly.project_id`**, renames like **`LaunchDarklySkillStore`** and **`create_openai_agents_handler`**, tightened **wildcard handler routing**, and **GA packaging / public `__all__`** cleanup. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2e904f7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

Python half of AIC-3598. The spec change is launchdarkly/ai-sdks-monorepo#91.
Packaging
Classifiers. All 14 packages say
Development Status :: 5 - Production/Stable. The twovercel-*packages had no classifiers at all.Third-party floors move to the version CI tests wherever the old floor crossed a breaking line (a major for 1.x+ libraries, a minor for 0.x):
langchain-core>=1.6,langgraph>=1.2,openai>=2.44,openai-agents>=0.17anthropic>=0.113,httpx>=0.28,typesafe-sdk>=0.7The rule, as the shared spec states it: a floor sits on the line CI tests, the same major as the tested version for a 1.x+ library and the same minor for a 0.x one. The README says so.
Floors already on the tested major stay put (
opentelemetry-api>=1.25,litellm>=1.83).[ld]extra onlaunchdarkly-ai-serverandlaunchdarkly-ai-pythoninstallslaunchdarkly-server-sdk>=9.18.3,<10. It's an extra rather than a dependency so bring-your-own-client installs stay lean, asclient/AGENTS.mdrequires. The READMEs and theinit_clienterror message point to it.Undeclared LangChain provider packages, found by the new check. Both langchain packages imported
langchain_openaiandlangchain_anthropicwithout declaring them, the Python side of the JS@langchain/anthropicgap:langchain-agentsnow depends onlangchain-openai, its default model, and offers[anthropic]and[aws]extras.langchain-messagesnow depends onlangchain-openai, its default model, as langchain-agents does, and offers[anthropic]and[aws].Internal ranges: every package pins
launchdarkly-ai-server>=0.6,<2. The native graph adapters importNativeGraphRunner, which published server 0.5.0 lacks, so>=0.4.1would let a handler resolve to a core it can't import from.>=0.6resolves whichever lands first, this PR's 0.6.0 or the 1.0.0 cut; chore(AIC-3672): release every Python package as 1.0.0 #242 (AIC-3672) tightens it to>=1.0.0,<2.Public types
LDClientInterfacebecomes aProtocol. It was a plain class withasyncmethods, which matched neither the synchronousldclient.LDClientnor the "maybe awaitable" way core calls it.ldclient.LDClientnow satisfies it structurally; checked with mypy in both directions (a client missingtrackis rejected).init_clientandget_clientreturn it.variation,flushandclosemay be async;trackmust be synchronous (-> None), because no call site awaits it.tool_handlerson the handler protocol and in every handler is typedMapping[str, Callable[..., Any] | NativeTool]instead ofdict[str, Any], so a caller's precisely typeddictis accepted. Offline evaluations pass aNativeToolto the handler unwrapped, solangchain-agentsnow checkscallable()before calling. It used to raiseTypeError: 'NativeTool' object is not callable; there's a test, and it fails without the fix.to_lang_graph,to_openai_agents,to_claude_agents,to_litellm_agents,to_vercel_agents):Awaitable[GraphDefinition]TypedDictexported from the rootNativeGraphRunnerprotocol. They return a small class rather than aSimpleNamespace, because mypy accepts anySimpleNamespaceas any protocol.Packaging check (
make check-packaging, new CI jobpackaging)scripts/check_packaging.pyinstalls each wheel alone, with no extras, into an empty venv, which proves core loads withoutlaunchdarkly-server-sdk. It imports every public module and__all__name. Then it checks that every module the source imports unconditionally, lazyimportlib.import_modulecalls included, comes from a distribution the package declares; installed through some other dependency is not enough. That found undeclaredpydanticin four packages andopenaiin litellm-agents, now declared. Each declared extra gets its own venv and must import whatEXTRA_IMPORTSlists for it; an extra with no entry fails. Internal dependencies resolve to this commit's wheels and third-party ones from PyPI. Each import is resolved by its full dotted name to the distribution that owns it, so a namespace package such asopentelemetry.sdkneedsopentelemetry-sdkdeclared; that foundlanggraph.prebuiltundeclared in langchain-agents. The 22 runs go through a thread pool.Checks
make lint,make format-check,make typecheck(no issues in 104 files),make api-report-check(15 reports current)make test: 3,651 passed, 18 skippedmake check-packaging: all 14 packages and 8 extras pass; removingpydanticfrom vercel-agents makes it fail withpydantic (from pydantic, not declared)Versioning
The README documents the 1.0 rule: from 1.0.0, every package is released at the same version.
🤖 Generated with Claude Code
Note
Overview
Prepares the Python AI SDK monorepo for GA by tightening packaging, install docs, and public types, plus a CI gate that catches undeclared dependencies workspace tests miss.
Packaging and installs. All packages move to Production/Stable classifiers; third-party floors are raised to versions CI exercises (LangChain 1.x, OpenAI 2.x, etc.).
launchdarkly-ai-server[ld]andlaunchdarkly-ai-python[ld]now install boundedlaunchdarkly-server-sdk; READMEs drop separatelaunchdarkly-server-sdklines. Handlers pinlaunchdarkly-ai-server>=0.6,<2. LangChain packages declarelangchain-openaiand add[anthropic]/[aws]extras with guarded import errors; missing deps likepydanticandlanggraph-prebuiltare added where the new checker found gaps.make check-packaging+ CIpackagingjob. Newscripts/check_packaging.pybuilds wheels, installs each package (and each extra) in an isolated venv, validates public__all__imports, and asserts every unconditional/lazy import is owned by a declared distribution—not a transitive install.Public API typing.
LDClientInterfaceis aProtocolaligned with realldclientusage;get_client/init_clientreturn it.tool_handlersisMapping[str, Callable[..., Any] | NativeTool]across core and handlers (LangChain agents reject unwrappedNativeTool). Native graphto_*adapters takeAwaitable[GraphDefinition], export per-package optionsTypedDicts, and returnNativeGraphRunnerinstead of untyped namespaces.README adds 1.0 synchronized versioning policy for the SDK.
Reviewed by Cursor Bugbot for commit bdd635b. Bugbot is set up for automated code reviews on this repo. Configure here.