How SDK versions differ
We recommend migrating from the legacy AI SDK version to the current version when possible. Recent SDK versions facilitate more efficient implementations by removing the requirement for custom coding in many parts of your application. The current SDKs remove the provider setup, message merging, and metrics wrapping you had to write by hand in the legacy SDKs. For the full before-and-after examples, read Migrate a manual completion call.| Language | Legacy AI SDK | Current AI SDK |
|---|---|---|
| Python | 28 lines | 9 lines |
| Node.js | 25 lines | 9 lines |
| Responsibility | What happens in the current AI SDK |
|---|---|
| Initialize the LaunchDarkly and AI clients | The SDK initializes from the environment, or you call init_client() / initClient() |
| Construct a provider client and choose a model | A handler package resolves the provider and model from the AgentControl config |
Supply fallback values and check enabled | There is no fallback argument. invoke() raises an error if the variation has targeting off or if LaunchDarkly is unreachable. Keep your own fallback response and check state with inspect_config() / inspectConfig() |
| Merge config messages with user input | The SDK merges messages before it calls the provider |
| Create a tracker and wrap the provider call | The SDK records metrics and OpenTelemetry spans on every invoke |
config(), graph(), or a convenience function. The SDK evaluates the config, routes to the matching handler, calls the provider, and records metrics and OpenTelemetry spans for you.
| Step | Legacy AI SDK | Current AI SDK |
|---|---|---|
| Evaluate the config | Call completion_config() / completionConfig(), agent_config() / agentConfig(), or related methods | Call config(), graph(), or a provider convenience function |
| Call the provider | Build a provider client, merge messages, and call the provider yourself | A handler package calls the provider |
| Record metrics | Create a tracker and wrap the provider call | Automatic on every invoke |
What changes when you migrate from a legacy SDK
You must change some parts of your application code when you migrate. They are:- Packages: Replace the legacy AI SDK packages with the current core package, as well as provider and mode handler packages.
- Initialization: Replace explicit LaunchDarkly and AI client construction with automatic initialization from the environment, or call
init_client()/initClient()when you need control. - Model calls: Replace evaluate-then-call-provider-yourself with
config().invoke(),graph(), or a provider convenience function. - Tools and handlers: Register tool implementations and handlers one time, typically in a
Registry, instead of wiring them at every call site. - Metrics and traces: Remove tracker setup and manual span wrapping. The SDK records metrics and creates OpenTelemetry spans automatically.
- Judges and graphs: Attach judges to config variations instead of calling a standalone judge, and replace legacy graph helpers with
graph()orresolve_graph()/resolveGraph(), as well as a native runner.
Replace packages and install handlers
Uninstall the legacy AI SDK packages and install the current core package, as well as one handler package for each provider and mode you use.| Language | Legacy packages | Current packages |
|---|---|---|
| Python | launchdarkly-server-sdk, launchdarkly-server-sdk-ai, and optional provider helpers such as ldai_openai | launchdarkly-ai-server and handler packages such as launchdarkly-ai-openai-messages |
| Node.js | @launchdarkly/node-server-sdk, @launchdarkly/server-sdk-ai, and optional provider packages such as @launchdarkly/server-sdk-ai-openai | @launchdarkly/ai-node and handler packages such as @launchdarkly/ai-openai-messages |
launchdarkly-server-sdk for Python and @launchdarkly/node-server-sdk for Node.js. For edge or custom runtimes, install the core @launchdarkly/ai-server package instead and pass a pre-initialized client.
For the full handler package matrix, read Install the SDK in the Python AI SDK reference or Install the SDK in the Node.js AI SDK reference.
Here’s how to install the base LaunchDarkly server SDK, the AI SDK core package, and the OpenAI messages handler:
Update client initialization
The legacy SDKs require you to construct an explicit LaunchDarkly client and an AI client wrapper. Here’s how the legacy SDKs initialize:LD_SDK_KEY and your provider API keys, and initializes the client on your first AI call. You no longer construct a LaunchDarkly client or an AI client wrapper yourself.
If you need to control initialization, such as to pass custom options or pre-warm the client, call init_client() / initClient() yourself. Call shutdown() when your application exits to flush events and spans.
To learn more, read Manage the client lifecycle or Manage the client lifecycle.
Migrate a manual completion call
This is the most common migration. In the legacy SDKs, you evaluate a completion-mode config, merge messages, call the provider, and wrap the call with a tracker. Here’s the legacy pattern:Use a convenience function
If you call one provider in one mode, replace the evaluate-call-track sequence with that provider’s convenience function. Call it with the config key, the user input, and an LDContext, in that order. The SDK evaluates the config, calls the provider, and records metrics. Pass template variables as thevariables keyword argument in Python or inside the options object in Node.js.
Here’s the same call with a convenience function:
Use handlers for multi-provider routing
If your config can serve more than one provider or mode, register handlers and callconfig().invoke(). Pass template variables as the third argument to invoke(). You no longer pass a fallback default object, merge UI messages with the user message, or create a tracker.
Because there is no fallback argument, invoke() raises an error instead of returning a disabled config. Wrap invoke() to return a fallback response if the variation has targeting off or if LaunchDarkly is unreachable. To read the state without raising, call inspect_config() / inspectConfig(). This returns the enabled flag, the config, and the variation metadata.
Here’s how:
createModel().run(), map those call sites to the same convenience function or config().invoke() path. Managed objects were the closest precursor to the current SDK, but the packages and APIs still change.
Migrate agent mode and tools
In the legacy SDKs, agent mode uses a separate evaluation method, then your application runs the tool loop and records metrics. In the current SDKs, completion and agent mode shareconfig(). The config variation’s mode selects the handler. Register tool implementations by name, or pass them inline.
Tool keys must match the tool names defined in the LaunchDarkly config variation exactly, including case.
Here’s the legacy agent-mode pattern:
Centralize configuration management
Registries are one of the larger cleanup opportunities in this migration. In the legacy SDKs, sharing handler wiring and tool implementations across call sites meant writing your own higher-level wrapper functions or duplicating handling code at each site. In the current SDKs, you register handlers and tools one time in aRegistry, then pass that registry to any call. Provider routing, tool dispatch, and metrics all live in one place.
Use a scoped Registry when different parts of your application need different handlers or tools, or the global registry when a single set is appropriate for the whole application. Some providers also expose built-in tools, such as Claude web search, that you assign as tool implementations instead of writing a function.
Here’s how to register handlers and tools one time, then reuse them:
Migrate judges
In the current SDKs, you attach judges to a config variation rather than calling a standalone judge in your application code. To keep response latency low, you can skip inline evaluation and run judges in the background instead. Run attached judges asynchronously. If you don’t includeskip_judges=true, judges are run inline by default. Here’s how:
run_judge(task, handlers) / runJudge(task, handlers) and track the evaluation metric when present. To learn more, read Run judges asynchronously or Run judges asynchronously.
Migrate agent graphs
Replace legacy graph creation and traversal helpers withgraph().invoke(), or resolve the topology and hand it to a native framework runner.
Here’s how to run a graph with the current SDK router:
resolve_graph() / resolveGraph(), then pass the result to to_lang_graph / toLangGraph, to_openai_agents / toOpenAIAgents, or to_claude_agents / toClaudeAgents. To learn more, read Run an agent graph or Run an agent graph.
API mapping
| Concern | Legacy | Current |
|---|---|---|
| Completion | completion_config() / completionConfig() | config().invoke() or a convenience function |
| Agent | agent_config() / agentConfig() | config().invoke(); mode comes from the variation |
| Multi-agent | agent_configs() / agentConfigs() | graph() or a native framework runner |
| Metrics | Tracker methods | Automatic on every call |
| Judges | create_judge() / createJudge() | Attached judges, plus run_judge() / runJudge() for async work |
| Graphs | create_agent_graph(), traverse helpers | graph(), resolve_graph() / resolveGraph() |
| Init | LDAIClient / initAi() | Lazy init, or init_client() / initClient() |