Repository navigation
fix: give native graph spans their LaunchDarkly identity - #101
Conversation
Every $ld:ai:* event that executeAndTrack sends carries the LaunchDarkly environment id, because AI Config Monitoring needs it to match a trace to the config that produced it. The two payloads built outside that path did not: makeNodeTrackData, used by every native graph adapter, and the graph-level graphTrackData in graph.ts. Read the id through the same tryGetEnvironmentId helper, which is now exported inside the client package so graph.ts can call it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A native graph adapter has no TrackData of its own: makeNodeTrackData describes one node, and the run as a whole is the graph flag. Add makeGraphTrackData, which names the graph flag as both the config key and the graph key, the same choice the SDK's own graph runner makes. Adapters pass it to setLdSpanAttributes in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
toOpenAIAgents, toClaudeAgents, toLangGraph and toVercelAgents each open a launchdarkly.graph span that carried only the graph key and token counts. The AI Config Monitoring tab finds a trace by a feature_flag span event and the config key, so none of these runs appeared against their AI Config. Tag the span through setLdSpanAttributes, the same helper every handler already uses, so the graph span now carries launchdarkly.config.key, launchdarkly.variation.key, launchdarkly.run.id, the context keys, and the feature_flag event with feature_flag.set.id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
toLangGraph opened its launchdarkly.graph span and never ended it, on success or failure. An unended span is never handed to the exporter, so LangGraph users got no graph span in their traces at all. The body now runs in try/finally, matching toVercelAgents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
bugbot run |
The launchdarkly.graph span that graph() opens carried only launchdarkly.graph.key. It now goes through setLdSpanAttributes with the same track data its graph events use, so it has the config key, variation, run id, context keys and the feature_flag event, like the native adapters' graph span. invoke() runs the same walk as stream(), so one call site covers both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The $ld:ai:graph:invocation_success, invocation_failure, duration:total and total_tokens events (and path, in vercel-agents) from the native adapters carried the root node's config key, while their graph span and graph() use the graph key. They now use makeGraphTrackData, so a graph run reports the same config key whichever runner produced it. toOpenAIAgents and toClaudeAgents ended the graph span only on the run's own success and failure paths. An error while building the agents or sub-agent tools left it open, so it was never exported. Both bodies now end the span in a finally, as toLangGraph and toVercelAgents do. The adapters no longer set launchdarkly.graph.key by hand, since setLdSpanAttributes already does. makeGraphTrackData is marked @internal: only the adapters use it, and its signature changes if GraphDefinition gains the graph's variation metadata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
bugbot run |
…-identity # Conflicts: # packages/client/src/index.ts
|
bugbot run |
jeffdupont
left a comment
There was a problem hiding this comment.
Parity review alongside python #121 (launchdarkly/python-ai-sdk#121). This PR already handles most of what I raised there. Graph-level events in all four adapters now use the graph key through makeGraphTrackData. The graph() span gets setLdSpanAttributes (graph.ts:724). The hand-set launchdarkly.graph.key is gone, and every adapter ends its span in a finally. Tested at 1cb2231: yarn build, yarn test (1,174 tests, exit 0), yarn typecheck and biome check . all clean.
Nothing here blocks the merge. Two things I'd like settled before GA. Python has both of them too:
- Write the graph identity into
TESTING.md. The monorepo spec (main at c2cca4f) doesn't say that thelaunchdarkly.graphspan carrieslaunchdarkly.config.key, the run id and thefeature_flagevent. It also doesn't say whichconfigKeygraph-level events use. Both PRs now agree on the graph key, so now is a good time to write it down, before the next change in either SDK drifts. I didn't find a monorepo PR for it. - Graph-level events report a different variation depending on the runner.
graph()sends the graph flag's realvariationKeyandversion(graph.ts:133-142). The native adapters now sendvariationKey: ''andversion: 1(tracking.ts:133), where before this PR they sent the root node's. So one graph flag's$ld:ai:graph:invocation_successcarries a different variation depending on which runner sent it, and per-variation views of native runs come up empty. Before 1.0, either expose the graph flag's meta onGraphDefinitionor write this down in the spec as a known gap.
Smaller notes:
makeGraphTrackDatais still exported from the root (index.ts:44). The@internaltag is only documentation: the repo has nostripInternal, and the name is in the builtdist/index.d.ts. Python #121 has since dropped it from__all__(d693d68). JS can't do that yet, because the clientpackage.jsononly exports., so I'm fine with it merging as is. I'll add it to the 1.0 trim list so it moves to the internal entry point withmakeNodeTrackData.- Every
graph()run with the same context object gets the samelaunchdarkly.run.id. I reproduced it: twoinvoke()calls on onegraph()with the same context gave one run id on both spans and bothinvocation_successevents. The cause is thatrunIdis created inbuildGraph(graph.ts:134) and the build is cached per context (graph.ts:636-643). That predates this PR for events, but now it's on the span too. Python caches the same way (graph.py:898-909); I haven't run it there. The run id is what ties a trace to its events, so I'd fix this in both SDKs before GA. - Setup errors are handled differently in the two SDKs. Here a setup error (for example "Root agent ... was not built") ends the span with status UNSET, no recorded exception and no
invocation_failure. Python #121 opens the span only after setup, so it exports no span at all. Either approach is fine, but they should match.
| export { compose, globalRegistry, Registry } from './registry.js'; | ||
| export { registerAiSdkPackage } from './sdk-info.js'; | ||
| export { makeNodeTrackData, makeRunTrackData } from './tracking.js'; | ||
| export { makeGraphTrackData, makeNodeTrackData, makeRunTrackData } from './tracking.js'; |
There was a problem hiding this comment.
@internal doesn't keep this out of the public surface. There's no stripInternal in the tsconfigs, and makeGraphTrackData is in the built dist/index.d.ts. Python #121 dropped make_graph_track_data from __all__ in d693d68. JS can't do that until the client has an internal entry point (the exports map only has .), so this is fine for now. I'll add it to the 1.0 trim with makeNodeTrackData.
| export const makeGraphTrackData = (graphKey: string, runId: string): TrackData => ({ | ||
| runId, | ||
| configKey: graphKey, | ||
| variationKey: '', |
There was a problem hiding this comment.
Graph-level events from the native adapters now carry variationKey: '' and version: 1. Before this PR they carried the root node's variation, and graph() sends the graph flag's real ones (graph.ts:133-142). So the same event from the same graph flag reports a different variation depending on the runner. The doc comment explains why (GraphDefinition has no _ldMeta). Can we either add the meta before 1.0 or write the gap into TESTING.md? Python's make_graph_track_data has the same issue.
A setup error in a native graph adapter (an agent that was not built, a sub-agent tool or model that fails to build, a graph that fails to compile) ended the launchdarkly.graph span with status UNSET, recorded no exception and emitted no $ld:ai:graph:invocation_failure, because only the run itself was wrapped in the failure handling. toOpenAIAgents, toClaudeAgents and toLangGraph now handle setup and the run in one try: any error records the exception on the span, sets status ERROR with the error message, tracks invocation_failure with the graph's track data when a context is present, and re-throws. The span still ends exactly once, in the finally. toVercelAgents already did this; its setLdSpanAttributes call moves inside the try so the same holds if tagging the span throws.
|
bugbot run |
…-identity # Conflicts: # packages/openai-agents/src/native-graph.ts
|
bugbot run |
…th event graph() caches the built graph per context, so its run id was shared by every invoke() and stream() with that context, and now lands on the launchdarkly.graph span. Each invocation now gets its own id for the span and all graph events. toVercelAgents still emitted $ld:ai:graph:path, which the other adapters no longer send; the path stays on the span only.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit e41fe83. Configure here.
## Summary Spans from the native graph adapters (`to_openai_agents`, `to_claude_agents`, `to_lang_graph`) had nothing tying them to the graph's AI Config, so Monitoring couldn't find them by config key. - The `launchdarkly.graph` span now gets `set_ld_span_attributes`, like every other handler: config key, run id, context keys and the `feature_flag` event. New helper: `make_graph_track_data`. - Graph and node tracking events now carry the environment id when `LD_ENVIRONMENT_ID` is set. - Graph-level events (`$ld:ai:graph:invocation_success` and friends) now use the graph key as `configKey`, matching the span and `graph()`. They used the root node's key. - The `graph()` runner's own `launchdarkly.graph` span gets the same identity. - `make_graph_track_data` stays internal (imported from `launchdarkly_ai_server.utils`, not in `__all__`). `TELEMETRY-CONTRACT.md` section 10 says which config key graph spans and events carry. - A setup error (an agent that fails to build, a graph that fails to compile) now fails the run like a run error does: every adapter opens the span before setup, records the exception with ERROR status, fires `$ld:ai:graph:invocation_failure` and ends the span once. Before, OpenAI and LangChain exported no span, and no adapter tracked the failure. JS twin: launchdarkly/js-ai-sdk#101. ## Testing - Adapter and client tests cover the span attributes, the event and the environment id. - Staging: [graph run with this branch](https://ld-stg.launchdarkly.com/projects/default/traces?query=launchdarkly.operation.type%3Dgen_ai+launchdarkly.graph.key%3Dtravel-agent-flow&page=1&relativeTime=last_24_hours&env=production&env=staging&env=alexis-o11y-lab&selected-env=alexis-o11y-lab&related_resource=eyJ0eXBlIjoidHJhY2UiLCJpZCI6IjNkMmE4ZmE1NDE4Mzc3MGE2OWQ1OWQ4NTQ5NTMwMjY4IiwidGltZXN0YW1wIjoiMjAyNi0wOS0zMFQyMzoyNjozMS44MjJaIiwic3BhbklEIjoiMDI0ZGY2NjAyNjUzNTBhNSJ9). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **Graph telemetry is aligned so Monitoring can tie traces to the graph AI Config.** > > Every `launchdarkly.graph` span—from `graph()` and the OpenAI, Claude, and LangChain native adapters—now goes through `set_ld_span_attributes` with a new `make_graph_track_data` payload (config/graph key, run id, `feature_flag` event, context keys). Graph-level track events (`invocation_success`, `duration:total`, `total_tokens`, `invocation_failure`) use the **graph key** as `configKey` instead of the root node’s key. Node events still use per-node keys. > > The SDK `graph()` runner gets the same span identity, issues a **fresh `runId` per invoke/stream**, and passes run track data into cached routes so handoff events match that run. Tracking payloads include `environmentId` when `LD_ENVIRONMENT_ID` is set. > > Native adapters wrap setup and execution in one try/finally: setup failures (agent build, graph compile, etc.) record an ERROR span, emit `$ld:ai:graph:invocation_failure` keyed to the graph, and end the span once. `TELEMETRY-CONTRACT.md` documents the contract. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a5e9ad3. 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>
## Why #101 exported `makeGraphTrackData` from the `@launchdarkly/ai-server` root (`packages/client/src/index.ts`) but didn't update `ROOT_VALUES` in `packages/client/src/__tests__/skills.test.ts`. The "the package root exports exactly the snapshotted values" test has failed on `main` since 4d97cfa, and `yarn test` stops before the later workspaces run, so every branch cut from `main` is red. ## What - Add `'makeGraphTrackData'` to `ROOT_VALUES` in sorted order. - Regenerate `packages/client/etc/ai-server.api.md` (`api:update`) so the Type check job's `api:check` passes. The approved-names list in ai-sdks-monorepo gets the matching `- makeGraphTrackData` line (leaving the public surface, like `makeNodeTrackData` / `makeRunTrackData`): launchdarkly/ai-sdks-monorepo#61. Its JSDoc already marks it `@internal` for the native graph adapters. ## Testing - `yarn workspace @launchdarkly/ai-server run test`: 1401 passed, 11 skipped. - `yarn workspace @launchdarkly/ai-server api:check` passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Fixes a failing **root export snapshot** test after `makeGraphTrackData` was added to the `@launchdarkly/ai-server` package entry in an earlier change. > > Adds `'makeGraphTrackData'` to the sorted `ROOT_VALUES` list in `skills.test.ts` so `Object.keys(packageIndex)` matches the snapshotted exports again. The API Extractor report (`ai-server.api.md`) is updated to document the existing `@internal` `makeGraphTrackData` export alongside `makeNodeTrackData` / `makeRunTrackData`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bb7f00d. 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>
…and load no host settings by default (#135) `createClaudeAgentsHandler({ cwd, settingSources })` takes two trusted, app-supplied options and passes each one given to every `query()` call, on both the blocking and the streaming path. - **Configs can't set them.** They configure the host process the Agent SDK starts, so they're spread with the handler's own options, after `model.parameters`. The allowlist in `model-parameters.ts` already drops both, so a config can neither set nor override them. - **Host settings load only on opt-in (breaking).** `settingSources` not given now sends `[]` rather than leaving the Agent SDK default, which loads every source (AIC-3584). Apps that want host settings pass `settingSources: ['user', 'project', 'local']`. `cwd` not given still isn't sent. `[]` doesn't stop the SDK from reading the managed-settings policy tier. - **Why.** On Agent SDK 0.3.220, a handler that left `settingSources` unset, on a developer machine, reported that machine's own plugins and 26 skills in its `init` message. The README documents the opt-in. - **The `tools: []` rule is pinned with tests.** A config with no native tools sends an explicit `[]`, which turns every built-in off, and user-defined tools stay reachable through MCP. Python omits the key today; the spec now settles on `[]` for both languages, and the Python fix will follow as `fix(claude-agents)!`. **No new exported names.** The option type is inline in the signature, so the package root's approved name list doesn't change. **Spec:** TESTING.md §2.x "Claude Agents Handler — host options and built-in tool set" and A.18, in launchdarkly/ai-sdks-monorepo#59. **Stacked on top of this:** the experimental skills integration, #136. **CI on `main` is already red:** the client package's root-export snapshot is missing `makeGraphTrackData` (#101). That failure shows up here too, and is being fixed separately. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **Breaking:** Runs no longer load the host machine’s Claude Code settings unless the app opts in. The handler always passes `settingSources: []` to the Agent SDK (instead of leaving the SDK default that loads user/project/local plugins, skills, hooks, `CLAUDE.md`, and settings-file `env`). Deployments that relied on `~/.claude/settings.json` for Bedrock/Vertex/gateway auth need process env vars or `settingSources: ['user']` (documented in the README migration section). > > **Trusted host options** — `cwd` and `settingSources` are added to `createClaudeAgentsHandler`, `claudeAgents`, `claudeGraph`, and `toClaudeAgents` via shared `hostQueryOptions()`. They are applied on every `query()` call (invoke, stream, and all graph nodes) **after** `model.parameters`, so flag config cannot set or override them. > > **Built-in tools** — When no `NativeTool` sentinels are attached, the handler sends **`tools: []`** so Claude Code built-ins stay off; user-defined tools remain available through MCP. > > Tests cover defaults, forwarding, config isolation, and graph paths. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a829919. 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>
🤖 I have created a release *beep* *boop* --- <details><summary>@launchdarkly/ai-claude-agents: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-claude-agents-0.4.0...@launchdarkly/ai-claude-agents-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **claude-agents:** accept trusted cwd and settingSources options, and load no host settings by default ([#135](#135)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) * **claude-agents:** accept trusted cwd and settingSources options, and load no host settings by default ([#135](#135)) ([6acd53d](6acd53d)) ### Bug Fixes * **AIC-3571:** visit every child before its parent in reverseTraverse ([#147](#147)) ([a17a2ce](a17a2ce)) * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **claude-agents:** fail the run when the CLI reports an API error as success ([#138](#138)) ([4637958](4637958)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) * give native graph spans their LaunchDarkly identity ([#101](#101)) ([4d97cfa](4d97cfa)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-claude-messages: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-claude-messages-0.4.0...@launchdarkly/ai-claude-messages-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-langchain-agents: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-langchain-agents-0.4.0...@launchdarkly/ai-langchain-agents-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) * give native graph spans their LaunchDarkly identity ([#101](#101)) ([4d97cfa](4d97cfa)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-langchain-messages: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-langchain-messages-0.4.0...@launchdarkly/ai-langchain-messages-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-litellm-agents: 0.2.0</summary> ## [0.2.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-litellm-agents-0.1.0...@launchdarkly/ai-litellm-agents-0.2.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) ### Features * add LiteLLM messages and agents integrations ([#75](#75)) ([127f156](127f156)) ### Bug Fixes * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-litellm-messages: 0.2.0</summary> ## [0.2.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-litellm-messages-0.1.0...@launchdarkly/ai-litellm-messages-0.2.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) ### Features * add LiteLLM messages and agents integrations ([#75](#75)) ([127f156](127f156)) ### Bug Fixes * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-node: 0.4.0</summary> ## [0.4.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-node-0.3.0...@launchdarkly/ai-node-0.4.0) (2026-10-26) ### ⚠ BREAKING CHANGES * **skills:** promote Agent Skills to core ([#159](#159)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **skills:** promote Agent Skills to core ([#159](#159)) ([c7135cd](c7135cd)) ### Bug Fixes * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-openai-agents: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-openai-agents-0.4.0...@launchdarkly/ai-openai-agents-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * **AIC-3571:** visit every child before its parent in reverseTraverse ([#147](#147)) ([a17a2ce](a17a2ce)) * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **AIC-3586:** propagate tool handler errors instead of sending them to the model ([#139](#139)) ([1f31e85](1f31e85)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) * give native graph spans their LaunchDarkly identity ([#101](#101)) ([4d97cfa](4d97cfa)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-openai-messages: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-openai-messages-0.4.0...@launchdarkly/ai-openai-messages-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-otel: 0.3.0</summary> ## [0.3.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-otel-0.2.0...@launchdarkly/ai-otel-0.3.0) (2026-10-26) ### ⚠ BREAKING CHANGES * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Bug Fixes * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) </details> <details><summary>@launchdarkly/ai-server: 0.5.0</summary> ## [0.5.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-server-0.4.0...@launchdarkly/ai-server-0.5.0) (2026-10-26) ### ⚠ BREAKING CHANGES * **skills:** promote Agent Skills to core ([#159](#159)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) * **client:** the client no longer loads .env. Add import 'dotenv/config' to your entrypoint (and install dotenv) if you relied on it. ### Experimental * **evaluations:** hash eventId and contentHash as RFC 8785 canonical JSON, the same in every SDK ([c971649](c971649)) * **evaluations:** Set JSON as standard for output to pass to judge ([#152](#152)) ([330da44](330da44)) ### Features * **AIC-3534:** add a TypeSafe Jev judge handler ([#122](#122)) ([0c1d6b7](0c1d6b7)) * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) * **skills:** promote Agent Skills to core ([#159](#159)) ([c7135cd](c7135cd)) ### Bug Fixes * **AIC-3541:** accept a node-server-sdk client in initClient() without a cast ([#128](#128)) ([5819449](5819449)) * **AIC-3570:** re-resolve graph flags on every invoke and stream ([#145](#145)) ([ce4f72e](ce4f72e)) * **AIC-3571:** visit every child before its parent in reverseTraverse ([#147](#147)) ([a17a2ce](a17a2ce)) * **AIC-3576:** record deferred judge scores under the evaluated config ([#148](#148)) ([d9fbee6](d9fbee6)) * **AIC-3577:** send object tool results to the model as JSON ([#146](#146)) ([be41d87](be41d87)) * **AIC-3596:** point the missing-OTel warning and docs at @launchdarkly/ai-otel ([#144](#144)) ([9b5f32e](9b5f32e)) * **client:** show a judge an output of 0, false, {} or [] ([c971649](c971649)) * **client:** stop loading dotenv from library code ([#69](#69)) ([fea34f3](fea34f3)) * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) * give native graph spans their LaunchDarkly identity ([#101](#101)) ([4d97cfa](4d97cfa)) * **judges:** a judge config's outputFormat must not reach the provider ([#56](#56)) ([8c6f4d2](8c6f4d2)) * **skills:** Correct the HTTP 403 advice now that server-side FDv2 is available to every account ([#141](#141)) ([5b7b732](5b7b732)) * **skills:** default FDv2SkillStore endpoints from LD_BASE_URI and LD_STREAM_URI ([#134](#134)) ([05f77d9](05f77d9)) </details> <details><summary>@launchdarkly/ai-typesafe: 0.2.0</summary> ## [0.2.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-typesafe-0.1.0...@launchdarkly/ai-typesafe-0.2.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) ### Features * **AIC-3534:** add a TypeSafe Jev judge handler ([#122](#122)) ([0c1d6b7](0c1d6b7)) * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-vercel-agents: 0.3.0</summary> ## [0.3.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-vercel-agents-0.2.0...@launchdarkly/ai-vercel-agents-0.3.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) * give native graph spans their LaunchDarkly identity ([#101](#101)) ([4d97cfa](4d97cfa)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </details> <details><summary>@launchdarkly/ai-vercel-messages: 0.3.0</summary> ## [0.3.0](https://github.com/launchdarkly/js-ai-sdk/compare/@launchdarkly/ai-vercel-messages-0.2.0...@launchdarkly/ai-vercel-messages-0.3.0) (2026-10-26) ### ⚠ BREAKING CHANGES * forward the same model.parameters keys as the Python SDK ([#118](#118)) ### Features * **AIC-3623:** evals from code ([#143](#143)) ([dc74b48](dc74b48)) ### Bug Fixes * forward the same model.parameters keys as the Python SDK ([#118](#118)) ([f7883ce](f7883ce)) ### Dependencies * The following workspace dependencies were updated * dependencies * @launchdarkly/ai-server bumped from ^0.4.0 to ^0.5.0 </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 bumps published versions across the monorepo and records what ships in each package—there is no application source in the diff beyond `LD_AI_PACKAGE_VERSION` strings and dependency pins. > > **@launchdarkly/ai-server** goes to **0.5.0**; provider packages move to **0.5.0** (or **0.4.0** / **0.3.0** / **0.2.0** where applicable), `.release-please-manifest.json` is updated, and every adapter’s `package.json` now depends on **`@launchdarkly/ai-server` ^0.5.0**. New **CHANGELOG** sections document the release notes already merged on `main`. > > Reviewers should treat this as publishing **breaking** behavior called out in those changelogs: libraries no longer auto-load **`.env`** (apps need `import 'dotenv/config'` if they relied on it), **`model.parameters`** forwarding is aligned with the Python SDK, **Agent Skills** are promoted from experimental to core, plus features/fixes such as **evals from code**, TypeSafe judge handler, and **claude-agents** defaulting to no host settings unless `cwd` / `settingSources` are passed. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8c6546c. 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>
Summary
Spans from the native graph adapters (
toOpenAIAgents,toClaudeAgents,toLangGraph,toVercelAgents) had nothing tying them to the graph's AI Config, so Monitoring couldn't find them by config key.launchdarkly.graphspan now getssetLdSpanAttributes, like every other handler: config key, run id, context keys and thefeature_flagevent. New helper:makeGraphTrackData.$ld:ai:graph:invocation_successand friends) now use the graph key asconfigKey, matching the span andgraph(). They used the root node's key.graph()runner's ownlaunchdarkly.graphspan gets the same identity.finally.toLangGraphnever ended it, andtoOpenAIAgents/toClaudeAgentsleft it open on setup errors.makeGraphTrackDatais marked@internal.$ld:ai:graph:invocation_failurefires. Before, the span ended with no status and no failure event.graph()run gets its own run id. The built graph is cached per context, so runs with the same context used to share one id on the span and every graph event. This replaces fix(client): give each graph() run its own run id #109.toVercelAgentsno longer sends$ld:ai:graph:path, matching the other adapters. The path stays on the span.Python twin: launchdarkly/python-ai-sdk#121.
Testing
🤖 Generated with Claude Code
Note
Overview
Native graph runs and the client's
graph()runner now taglaunchdarkly.graphspans with the same LaunchDarkly identity as other handlers viasetLdSpanAttributesand a newmakeGraphTrackDatahelper, so AI Config Monitoring can correlate traces by graph/config key (includingfeature_flagspan events with environment id).Telemetry behavior changes: graph-level
$ld:ai:graph:*events andinvocation_failureuse the graph flag key asconfigKey(not the root node);environmentIdis added to graph and node track payloads viatryGetEnvironmentId.graph().streammints a freshrunIdper invocation even when the built graph is cached. Setup failures (compile/build) are handled like run errors: span ERROR status, exception recorded, graph-level failure event, andspan.end()once infinally(fixes missing/double span lifecycle in LangGraph and other adapters).toVercelAgentsstops emitting$ld:ai:graph:pathas a track event (path remains on the span only).Reviewed by Cursor Bugbot for commit e41fe83. Bugbot is set up for automated code reviews on this repo. Configure here.