Skip to content

Commit c51e235

Browse files
committed
Merge branch 'aklatzke/AIC-2263/sdk-dx-improvements' of github.com:launchdarkly/python-server-sdk-ai into aklatzke/AIC-2263/sdk-dx-improvements
2 parents 849d41f + 99dd7b8 commit c51e235

63 files changed

Lines changed: 6047 additions & 2217 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint-pr-title.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ on:
77
- edited
88
- synchronize
99

10+
permissions:
11+
pull-requests: read
12+
1013
jobs:
1114
lint-pr-title:
1215
uses: launchdarkly/gh-actions/.github/workflows/lint-pr-title.yml@main

.github/workflows/release-please.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
package-server-ai-optimization-released: ${{ steps.release.outputs['packages/optimization--release_created'] }}
5151
package-server-ai-optimization-tag-name: ${{ steps.release.outputs['packages/optimization--tag_name'] }}
5252
steps:
53-
- uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4
53+
- uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
5454
id: release
5555

5656
release-server-ai:

.release-please-manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"packages/sdk/server-ai": "0.18.0",
3-
"packages/ai-providers/server-ai-langchain": "0.5.0",
4-
"packages/ai-providers/server-ai-openai": "0.4.0",
2+
"packages/sdk/server-ai": "1.0.1",
3+
"packages/ai-providers/server-ai-langchain": "0.8.0",
4+
"packages/ai-providers/server-ai-openai": "0.7.0",
55
"packages/optimization": "0.1.0"
66
}

packages/ai-providers/server-ai-langchain/CHANGELOG.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,59 @@
22

33
All notable changes to the LaunchDarkly Python AI LangChain provider package will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [0.8.0](https://github.com/launchdarkly/python-server-sdk-ai/compare/launchdarkly-server-sdk-ai-langchain-0.7.1...launchdarkly-server-sdk-ai-langchain-0.8.0) (2026-05-19)
6+
7+
8+
### ⚠ BREAKING CHANGES
9+
10+
* Remove async from create_model/agent/agent_graph methods ([#187](https://github.com/launchdarkly/python-server-sdk-ai/issues/187))
11+
12+
### Features
13+
14+
* Remove async from create_model/agent/agent_graph methods ([#187](https://github.com/launchdarkly/python-server-sdk-ai/issues/187)) ([dddc00a](https://github.com/launchdarkly/python-server-sdk-ai/commit/dddc00ab3d8b57cd58b71b57296680b8e95560fd))
15+
16+
## [0.7.1](https://github.com/launchdarkly/python-server-sdk-ai/compare/launchdarkly-server-sdk-ai-langchain-0.7.0...launchdarkly-server-sdk-ai-langchain-0.7.1) (2026-05-14)
17+
18+
19+
### Bug Fixes
20+
21+
* Make judge runners non-multi-turn ([#185](https://github.com/launchdarkly/python-server-sdk-ai/issues/185)) ([5c21bd0](https://github.com/launchdarkly/python-server-sdk-ai/commit/5c21bd08bebfbdc5672afa93ad99099202955c92))
22+
23+
## [0.7.0](https://github.com/launchdarkly/python-server-sdk-ai/compare/launchdarkly-server-sdk-ai-langchain-0.6.0...launchdarkly-server-sdk-ai-langchain-0.7.0) (2026-05-13)
24+
25+
26+
### ⚠ BREAKING CHANGES
27+
28+
* Narrow AgentGraphRunner.run input from Any to str ([#177](https://github.com/launchdarkly/python-server-sdk-ai/issues/177))
29+
* Rename LDAIMetrics.usage and AIGraphMetrics.usage to .tokens ([#175](https://github.com/launchdarkly/python-server-sdk-ai/issues/175))
30+
* rename GraphMetrics/GraphMetricSummary to AIGraphMetrics/AIGraphMetricSummary ([#173](https://github.com/launchdarkly/python-server-sdk-ai/issues/173))
31+
32+
### Features
33+
34+
* Narrow AgentGraphRunner.run input from Any to str ([#177](https://github.com/launchdarkly/python-server-sdk-ai/issues/177)) ([cc7a0fe](https://github.com/launchdarkly/python-server-sdk-ai/commit/cc7a0fe64549337c71036cd67973bf0af91c7a42))
35+
* rename GraphMetrics/GraphMetricSummary to AIGraphMetrics/AIGraphMetricSummary ([#173](https://github.com/launchdarkly/python-server-sdk-ai/issues/173)) ([583939d](https://github.com/launchdarkly/python-server-sdk-ai/commit/583939dbe5c11c3c11ed960ee0b46ec377f1bb70))
36+
* Rename LDAIMetrics.usage and AIGraphMetrics.usage to .tokens ([#175](https://github.com/launchdarkly/python-server-sdk-ai/issues/175)) ([d8c4a70](https://github.com/launchdarkly/python-server-sdk-ai/commit/d8c4a702d4b68f146de7ca520bc35f2aa0b155f6))
37+
38+
## [0.6.0](https://github.com/launchdarkly/python-server-sdk-ai/compare/launchdarkly-server-sdk-ai-langchain-0.5.0...launchdarkly-server-sdk-ai-langchain-0.6.0) (2026-05-05)
39+
40+
41+
### ⚠ BREAKING CHANGES
42+
43+
* `LangChainModelRunner.invoke_model()` and `invoke_structured_model()` have been removed. Use the unified `run(input, output_type=...)` method instead, which returns `RunnerResult` in place of `ModelResponse` / `StructuredResponse`.
44+
45+
46+
### Features
47+
48+
* Add judge evaluation support to agent graphs ([#142](https://github.com/launchdarkly/python-server-sdk-ai/issues/142)) ([3d5a6a9](https://github.com/launchdarkly/python-server-sdk-ai/commit/3d5a6a91a87c7475a83a7e440cd4b71337cfd56f))
49+
* Migrate LangGraph runner to AgentGraphRunnerResult; clean up legacy shape detection ([#156](https://github.com/launchdarkly/python-server-sdk-ai/issues/156)) ([efa8e00](https://github.com/launchdarkly/python-server-sdk-ai/commit/efa8e00103d3870d379167769ae38f438b019ec4))
50+
* Support conversation history directly in AI Provider model runners ([#166](https://github.com/launchdarkly/python-server-sdk-ai/issues/166)) ([4bb3e78](https://github.com/launchdarkly/python-server-sdk-ai/commit/4bb3e7813f7c087302ba8446dea6a4a41f012c2e))
51+
* Update LangChain runners to implement Runner protocol returning RunnerResult ([#150](https://github.com/launchdarkly/python-server-sdk-ai/issues/150)) ([62a8e25](https://github.com/launchdarkly/python-server-sdk-ai/commit/62a8e252f4389884fa2f6a90e325db4a8f79376a))
52+
53+
54+
### Bug Fixes
55+
56+
* build judge input as string; strip legacy judge config messages ([#165](https://github.com/launchdarkly/python-server-sdk-ai/issues/165)) ([e6942a6](https://github.com/launchdarkly/python-server-sdk-ai/commit/e6942a6e2d4db17ae1fa6191521f8ac4fb48f30d))
57+
558
## [0.5.0](https://github.com/launchdarkly/python-server-sdk-ai/compare/launchdarkly-server-sdk-ai-langchain-0.4.1...launchdarkly-server-sdk-ai-langchain-0.5.0) (2026-04-21)
659

760

packages/ai-providers/server-ai-langchain/README.md

Lines changed: 52 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -37,80 +37,69 @@ pip install langchain-google-genai
3737
```python
3838
import asyncio
3939
from ldclient import LDClient, Config, Context
40-
from ldai import init
41-
from ldai_langchain import LangChainProvider
40+
from ldai import LDAIClient
41+
from ldai.models import AICompletionConfigDefault, ModelConfig, ProviderConfig
4242

4343
# Initialize LaunchDarkly client
4444
ld_client = LDClient(Config("your-sdk-key"))
45-
ai_client = init(ld_client)
46-
47-
# Get AI configuration. Pass a default for improved resiliency when the flag is unavailable or
48-
# LaunchDarkly is unreachable; omit for a disabled default. Example:
49-
# from ldai.models import AICompletionConfigDefault, LDMessage, ModelConfig, ProviderConfig
50-
# default = AICompletionConfigDefault(
51-
# enabled=True,
52-
# model=ModelConfig("gpt-4"),
53-
# provider=ProviderConfig("openai"),
54-
# messages=[LDMessage(role="system", content="You are a helpful assistant.")]
55-
# )
56-
# config = ai_client.config("ai-config-key", context, default)
45+
ai_client = LDAIClient(ld_client)
46+
5747
context = Context.builder("user-123").build()
58-
config = ai_client.config("ai-config-key", context)
5948

6049
async def main():
61-
# Create a LangChain provider from the AI configuration
62-
provider = await LangChainProvider.create(config)
63-
64-
# Use the provider to invoke the model
65-
from ldai.models import LDMessage
66-
messages = [
67-
LDMessage(role="system", content="You are a helpful assistant."),
68-
LDMessage(role="user", content="Hello, how are you?"),
69-
]
70-
71-
response = await provider.invoke_model(messages)
72-
print(response.message.content)
50+
# Create a ManagedModel backed by the LangChain provider
51+
model = ai_client.create_model(
52+
"ai-config-key",
53+
context,
54+
AICompletionConfigDefault(
55+
enabled=True,
56+
model=ModelConfig("gpt-4"),
57+
provider=ProviderConfig("langchain"),
58+
),
59+
)
60+
61+
if model:
62+
result = await model.run("Hello, how are you?")
63+
print(result.content)
7364

7465
asyncio.run(main())
7566
```
7667

7768
## Usage
7869

79-
### Using LangChainProvider with the Create Factory
70+
### Using `create_model` (recommended)
8071

81-
The simplest way to use the LangChain provider is with the static `create` factory method, which automatically creates the appropriate LangChain model based on your LaunchDarkly AI configuration:
72+
The recommended entry point is `LDAIClient.create_model`, which evaluates a
73+
LaunchDarkly AI config flag, selects the LangChain runner automatically, and
74+
returns a `ManagedModel` that wraps the runner:
8275

8376
```python
84-
from ldai_langchain import LangChainProvider
85-
86-
# Create provider from AI configuration
87-
provider = await LangChainProvider.create(ai_config)
77+
model = ai_client.create_model("ai-config-key", context)
8878

89-
# Invoke the model
90-
response = await provider.invoke_model(messages)
79+
if model:
80+
result = await model.run("What is feature flagging?")
81+
print(result.content)
9182
```
9283

93-
### Using an Existing LangChain Model
84+
### Using the runner directly
9485

95-
If you already have a LangChain model configured, you can use it directly:
86+
If you need to construct a runner manually (e.g. for testing), you can use
87+
`LangChainModelRunner` from the `ldai_langchain` package:
9688

9789
```python
9890
from langchain_openai import ChatOpenAI
99-
from ldai_langchain import LangChainProvider
91+
from ldai_langchain import LangChainModelRunner
10092

101-
# Create your own LangChain model
10293
llm = ChatOpenAI(model="gpt-4", temperature=0.7)
94+
runner = LangChainModelRunner(llm)
10395

104-
# Wrap it with LangChainProvider
105-
provider = LangChainProvider(llm)
106-
107-
# Use with LaunchDarkly tracking
108-
response = await provider.invoke_model(messages)
96+
result = await runner.run("Hello!")
97+
print(result.content)
10998
```
11099

111100
### Structured Output
112101

113-
The provider supports structured output using LangChain's `with_structured_output`:
102+
Pass a JSON schema dict as `output_type` to request structured output:
114103

115104
```python
116105
response_structure = {
@@ -122,92 +111,62 @@ response_structure = {
122111
"required": ["sentiment", "confidence"],
123112
}
124113

125-
result = await provider.invoke_structured_model(messages, response_structure)
126-
print(result.data) # {"sentiment": "positive", "confidence": 0.95}
114+
result = await runner.run(messages, output_type=response_structure)
115+
print(result.parsed) # {"sentiment": "positive", "confidence": 0.95}
127116
```
128117

129118
### Tracking Metrics
130119

131-
Use the provider with LaunchDarkly's tracking capabilities:
120+
`ManagedModel.run()` automatically tracks metrics via the associated
121+
`LDAIConfigTracker`. For manual tracking, use the tracker directly:
132122

133123
```python
134-
# Get the AI config with tracker
135-
config = ai_client.config("ai-config-key", context)
136-
137-
# Create provider
138-
provider = await LangChainProvider.create(config)
124+
model = ai_client.create_model("ai-config-key", context)
139125

140-
# Track metrics automatically
141-
async def invoke():
142-
return await provider.invoke_model(messages)
143-
144-
response = await config.tracker.track_metrics_of_async(
145-
invoke,
146-
lambda r: r.metrics
147-
)
126+
if model:
127+
result = await model.run("Explain feature flags.")
128+
# Metrics are tracked automatically; access them via result.metrics
129+
print(result.metrics.tokens)
148130
```
149131

150132
### Static Utility Methods
151133

152-
The `LangChainProvider` class provides several utility methods:
134+
The `ldai_langchain` helper module provides several utility functions:
153135

154136
#### Converting Messages
155137

156138
```python
157139
from ldai.models import LDMessage
158-
from ldai_langchain import LangChainProvider
140+
from ldai_langchain.langchain_helper import convert_messages_to_langchain
159141

160142
messages = [
161143
LDMessage(role="system", content="You are helpful."),
162144
LDMessage(role="user", content="Hello!"),
163145
]
164146

165-
# Convert to LangChain messages
166-
langchain_messages = LangChainProvider.convert_messages_to_langchain(messages)
147+
langchain_messages = convert_messages_to_langchain(messages)
167148
```
168149

169150
#### Extracting Metrics
170151

171152
```python
172-
from ldai_langchain import LangChainProvider
153+
from ldai_langchain.langchain_helper import get_ai_metrics_from_response
173154

174155
# After getting a response from LangChain
175-
metrics = LangChainProvider.get_ai_metrics_from_response(ai_message)
156+
metrics = get_ai_metrics_from_response(ai_message)
176157
print(f"Success: {metrics.success}")
177-
print(f"Tokens used: {metrics.usage.total if metrics.usage else 'N/A'}")
158+
print(f"Tokens used: {metrics.tokens.total if metrics.tokens else 'N/A'}")
178159
```
179160

180161
#### Provider Name Mapping
181162

182163
```python
183-
# Map LaunchDarkly provider names to LangChain provider names
184-
langchain_provider = LangChainProvider.map_provider("gemini") # Returns "google-genai"
185-
```
186-
187-
## API Reference
164+
from ldai_langchain.langchain_helper import map_provider_name
188165

189-
### LangChainProvider
190-
191-
#### Constructor
192-
193-
```python
194-
LangChainProvider(llm: BaseChatModel, logger: Optional[Any] = None)
166+
# Map LaunchDarkly provider names to LangChain provider names
167+
langchain_provider = map_provider_name("gemini") # Returns "google-genai"
195168
```
196169

197-
#### Static Methods
198-
199-
- `create(ai_config: AIConfigKind, logger: Optional[Any] = None) -> LangChainProvider` - Factory method to create a provider from AI configuration
200-
- `convert_messages_to_langchain(messages: List[LDMessage]) -> List[BaseMessage]` - Convert LaunchDarkly messages to LangChain messages
201-
- `get_ai_metrics_from_response(response: AIMessage) -> LDAIMetrics` - Extract metrics from a LangChain response
202-
- `map_provider(ld_provider_name: str) -> str` - Map LaunchDarkly provider names to LangChain names
203-
- `create_langchain_model(ai_config: AIConfigKind) -> BaseChatModel` - Create a LangChain model from AI configuration
204-
205-
#### Instance Methods
206-
207-
- `invoke_model(messages: List[LDMessage]) -> ChatResponse` - Invoke the model with messages
208-
- `invoke_structured_model(messages: List[LDMessage], response_structure: Dict[str, Any]) -> StructuredResponse` - Invoke with structured output
209-
- `get_chat_model() -> BaseChatModel` - Get the underlying LangChain model
210-
211170
## Documentation
212171

213172
For full documentation, please refer to the [LaunchDarkly AI SDK documentation](https://docs.launchdarkly.com/sdk/ai/python).

packages/ai-providers/server-ai-langchain/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "launchdarkly-server-sdk-ai-langchain"
3-
version = "0.5.0"
3+
version = "0.8.0"
44
description = "LaunchDarkly AI SDK LangChain Provider"
55
authors = [{name = "LaunchDarkly", email = "dev@launchdarkly.com"}]
66
license = {text = "Apache-2.0"}
@@ -20,7 +20,7 @@ classifiers = [
2020
"Topic :: Software Development :: Libraries",
2121
]
2222
dependencies = [
23-
"launchdarkly-server-sdk-ai>=0.18.0",
23+
"launchdarkly-server-sdk-ai>=1.0.1", # x-release-please-version
2424
"langchain-core>=1.0.0",
2525
"langchain>=1.0.0",
2626
]

0 commit comments

Comments
 (0)