Repository navigation
fix(AIC-3592): make native LangGraph hand-offs complete - #246
Merged
Merged
Conversation
to_lang_graph failed every turn that handed off. The hand-off Command now carries a ToolMessage for its call, a node no longer runs again after it hands off (single- and multi-child), only the first hand-off in a message routes, and parallel_tool_calls is no longer passed to bind_tools, which Bedrock Converse rejected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 29, 2026
…ions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A hand-off target can be on another provider. Live Whodunit run on 29 Oct: a Bedrock target with no tools rejected toolUse/toolResult blocks, and an OpenAI target rejected Claude reasoning_content. History from before a node was entered is now plain text: reasoning dropped, tool calls and results as lines. The node's own tool loop stays native. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rite Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ToolMessageChunk Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jeffdupont
marked this pull request as ready for review
October 29, 2026 19:25
aknight-ld
approved these changes
Oct 30, 2026
jeffdupont
added a commit
to launchdarkly/js-ai-sdk
that referenced
this pull request
Oct 30, 2026
## Summary Fixes [AIC-3592](https://launchdarkly.atlassian.net/browse/AIC-3592) (1.0 blocker) in TypeScript. `toLangGraph` failed every turn that handed off: the Whodunit app's `check --engine langgraph` failed 30 of 30 graph turns with "Node whodunit-manor-butler is not reachable". Implements the new §2.x.3 bullets in launchdarkly/ai-sdks-monorepo#118. In `packages/langchain-agents/src/native-graph.ts`: - **The hand-off `Command` answers its tool call.** It now adds a `ToolMessage` (`Handed off to <target>.`) with the call's id, so the target's model call never sees an unanswered `tool_use`. - **The tools node declares its hand-off targets as `ends`**, so LangGraph accepts the `Command` target. This is the "not reachable" error. - **The routing node does not run again after a hand-off.** The static `tools -> node` edge is replaced by a conditional edge that goes back to the node only when no hand-off routed. This applies to single-child and multi-child nodes. - **Only the first hand-off in a message routes**, as `graph()` does. A later one returns `Ignored: only the first transfer in a turn routes.` and does not track `$ld:ai:graph:handoff_success`. - **`parallel_tool_calls` is no longer passed to `bindTools`.** Bedrock Converse rejects it; the first-hand-off rule replaces it. - **A hand-off target sees provider-neutral text history.** Messages already in the state when a node is entered are rewritten for its model: reasoning and other non-text blocks dropped, each assistant message's tool calls appended as `[Tool call] <name> <args>` lines, the tool results after it folded into one user message of `[Tool result] <name>: <text>` lines in call order. Human and system messages pass unchanged. The node's own tool loop after entry stays native. A normal tool call in the same message as a hand-off still runs, in the same tools step, and the target receives its result (decision 1A on the ticket). ## Tests `native-graph.shallow.test.ts` runs six new cases on the real `StateGraph` with a mock model: a multi-child hand-off, a single-child hand-off, a normal call plus a hand-off, two hand-offs, no `parallel_tool_calls`, and a node's own tool loop staying native. Each hand-off case asserts the exact messages the target receives (no tool role, tool calls, or reasoning blocks). A `toNeutralHistory` unit test covers every rewrite rule on the same input as the Python test, with the same expected output. The helper is exported from `native-graph.ts` for that test only; the package index does not re-export it (`api:check` passes). The unused `_text` and the duplicate final-output extraction now use `contentText`. The mocked executor test now asserts the `ToolMessage` in the `Command` update. Local: `yarn code:check`, `yarn typecheck`, `yarn api:check`, `yarn test` all pass. The live Bedrock run is under "Live check". Python: launchdarkly/python-ai-sdk#246. Go is out of scope for 1.0. ## Live check Passed on 29 Oct at head `0a0dd22`: Whodunit `check --engine langgraph` on Bedrock completed 15 of 15 graph lines with 0 errors (the run at `b528263` completed 9 of 16, with the `toolConfig` and `reasoning_content` errors). Reachability 5/5, verdict format 6/6. The later commit `ae7a03e` changes only the test file. Bedrock end-to-end in CI: deferred to Q4 follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) [AIC-3592]: https://launchdarkly.atlassian.net/browse/AIC-3592?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Fixes broken **LangGraph hand-offs** in `toLangGraph` that caused unreachable target nodes and failed multi-agent runs (e.g. Whodunit on Bedrock). > > Hand-off tools now return a **`Command` that includes a `ToolMessage`** answering the transfer call, register **`ToolNode` `ends`** for valid `goto` targets, and use **conditional edges** so the routing node does not run again after a successful hand-off. **Only the first `transfer_to_*` in a turn routes**; later ones return an ignored message. **`parallel_tool_calls` is no longer passed to `bindTools`** (Bedrock compatibility); first-wins routing replaces it. > > When a node is **entered via hand-off**, prior conversation is passed through new **`toNeutralHistory`** (reasoning/non-text stripped, tool calls/results as plain `[Tool call]` / `[Tool result]` lines); the node’s **own tool loop after entry stays native**. > > Adds **real `StateGraph` integration tests** for hand-off scenarios and a **`toNeutralHistory` unit test** aligned with Python; updates the mocked hand-off executor test for the `Command` message update. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ae7a03e. 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>
Merged
jeffdupont
added a commit
that referenced
this pull request
Oct 30, 2026
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>
jeffdupont
pushed a commit
that referenced
this pull request
Oct 30, 2026
🤖 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes AIC-3592 (1.0 blocker) in Python.
to_lang_graphfailed every turn that handed off: the Whodunit app'scheck --engine langgraphfailed 30 of 30 graph turns withChatBedrockConverse._converse_params() got an unexpected keyword argument 'parallelToolCalls'. Implements the new §2.x.3 bullets in launchdarkly/ai-sdks-monorepo#118.In
packages/langchain-agents/src/launchdarkly_ai_langchain_agents/native_graph.py:parallel_tool_callsis no longer passed tobind_tools. This is the Bedrock error. The first-hand-off rule below replaces it.Commandanswers its tool call. It now adds aToolMessage(Handed off to <target>.) with the call's id. The id comes fromInjectedToolCallId, so the hand-off schema is now a small pydantic model (a dict schema skips the injection).pydantic>=2.13is declared, as in the other packages that import it.tools -> nodeedge is replaced by a conditional edge that goes back to the node only when no hand-off routed. This applies to single-child and multi-child nodes.graph()does. A later one returnsIgnored: only the first transfer in a turn routes.and does not track$ld:ai:graph:handoff_success.[Tool call] <name> <args>lines, the tool results after it folded into one user message of[Tool result] <name>: <text>lines in call order. Human and system messages pass unchanged. The node's own tool loop after entry stays native.A normal tool call in the same message as a hand-off still runs, in the same tools step, and the target receives its result (decision 1A on the ticket).
Tests
TestNativeHandoffRealStateGraphruns six cases on the realStateGraphwith a mock model: a multi-child hand-off, a single-child hand-off, a normal call plus a hand-off, two hand-offs, noparallel_tool_calls, and a node's own tool loop staying native. Each hand-off case asserts the exact messages the target receives (no tool role, tool calls, or reasoning blocks).TestToNeutralHistoryunit-tests the rewrite on one input covering every rule (reasoning, null text, an empty assistant, an unmatched result, call order, nested and non-ASCII args, a message chunk, an image in a human message); the TypeScript test uses the same input and expects the same output.Local:
make lint,make format-check,make typecheck,make test(3718 passed, 18 skipped) all pass. The live Bedrock run is under "Live check".TypeScript: launchdarkly/js-ai-sdk#192. Go is out of scope for 1.0.
Live check
Passed on 29 Oct: js-ai-sdk#192 at
0a0dd22, Whodunitcheck --engine langgraphon Bedrock, 15 of 15 graph lines, 0 errors.Bedrock end-to-end in CI: deferred to Q4 follow-up.
🤖 Generated with Claude Code
Note
Overview
Fixes broken LangGraph hand-offs in
to_lang_graph(AIC-3592), including the Bedrock failure from passingparallel_tool_callstobind_tools. Hand-off routing now matchesgraph(): only the firsttransfer_to_*call in a turn navigates; extras return an ignored message.Hand-off
Commandupdates now include aToolMessagethat answers the transfer tool call (viaInjectedToolCallIdon a small Pydantic_HandoffArgsschema).pydantic>=2.13is added as a direct dependency. After tools run, a conditional edge stops the routing node from executing again when a hand-off fired, instead of always looping back through_tools → node.When a node is entered (not continuing its own tool loop), prior conversation is rewritten with
_to_neutral_history: reasoning/non-text blocks dropped, tool calls and results flattened to plain[Tool call]/[Tool result]text so downstream agents on other providers never see native tool or reasoning payloads.Tests add
TestNativeHandoffRealStateGraph(six StateGraph scenarios) andTestToNeutralHistoryaligned with the TypeScript rewrite fixture.Reviewed by Cursor Bugbot for commit cee3051. Bugbot is set up for automated code reviews on this repo. Configure here.