Repository navigation
Conversation
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 4c5efa1. Configure here.
| timeout_s=self._shadow_timeout_s, | ||
| ) | ||
| if not self._skip_shadows: | ||
| start_shadows(shadow_tasks, resolved_handler_list) |
There was a problem hiding this comment.
Shadow setup errors fail live calls
Medium Severity
Building and starting shadows now runs inline on invoke() and stream() with no outer guard. The old invocation-hook runner swallowed hook failures so the real call still ran. build_shadow_tasks only catches _entries_for, so a later parse, dict(context), or start_shadows error now fails the customer's live request even though shadow work is supposed to be best-effort.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 4c5efa1. Configure here.
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>


Why
LaunchDarkly can now attach shadow requests to an AI Config's targeting rules and fallthrough, and delivers them inside the served variation as
shadowConfiguration(AIC-3429). The SDK needs to run them: while serving variation A, also run variation B in the background on the same input and report B on the normal AI metrics, so customers can compare models on real traffic. Draft until the Shadow Testing UI ships.Summary
Shadow requests run from core, the same way judges do. A new
shadows.pypicks the shadow requests for the matched rule or fallthrough, skips ended ones, samples sticky per context, strips tools and judges, and runs them in the background with a 30 second timeout.config().invoke()and.stream()call it directly.config(skip_shadows=True)returnsshadow_taskson the response instead of running them, andrun_shadow(task, handlers)runs one later, mirroringskip_judgesandrun_judge.config(shadow_timeout_s=...)sets the timeout.config()evaluates withvariation_detail()when the client has it, to read the evaluation reason. Graphs, judges and evaluations still callvariation().isShadow,primaryVariationKey,shadowRequestId,ownerKind,ownerIdand the real run'srunId. The shadow's root span carrieslaunchdarkly.is_shadow, the shadow request id and the primary variation key.execute_and_track/execute_and_streamtake optionalrun_id,extra_track_dataandspan_attributes. This shows in the root API report.Nothing to turn on in the SDK: LaunchDarkly only sends shadow requests while
enable-shadow-requestsis on and someone has set one up.Testing approaches
skip_shadows, picklable tasks and matching events between background and deferred runsFeature flags
N/A. LaunchDarkly only sends shadow requests while
enable-shadow-requestsis on.