Skip to content

Commit ce84fe5

Browse files
authored
chore: Update SDK dependency, use provider helpers, and fix broken examples (#19)
1 parent 84d3c2d commit ce84fe5

7 files changed

Lines changed: 66 additions & 105 deletions

examples/bedrock_example.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import ldclient
33
from ldclient import Context
44
from ldclient.config import Config
5-
from ldai.client import LDAIClient, AIConfig, ModelConfig, ProviderConfig, LDMessage
5+
from ldai.client import LDAIClient
66
import boto3
77

88
client = boto3.client("bedrock-runtime", region_name="us-east-1")
@@ -49,12 +49,13 @@ def main():
4949
# provider=ProviderConfig(name='bedrock'),
5050
# messages=[LDMessage(role='system', content='You are a helpful assistant.')],
5151
# )
52-
# config_value, tracker = aiclient.config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
53-
config_value, tracker = aiclient.config(
52+
# config_value = aiclient.completion_config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
53+
config_value = aiclient.completion_config(
5454
ai_config_key,
5555
context,
5656
variables={'myUserVariable': "Testing Variable"}
5757
)
58+
tracker = config_value.tracker
5859

5960
if not config_value.enabled:
6061
print("AI Config is disabled")

examples/gemini_example.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import ldclient
33
from ldclient import Context
44
from ldclient.config import Config
5-
from ldai.client import LDAIClient, AIConfig, ModelConfig, ProviderConfig, LDMessage
5+
from ldai.client import LDAIClient, LDMessage
66
from ldai.tracker import TokenUsage
77
from google import genai
88
from google.genai import types
@@ -119,12 +119,13 @@ def main():
119119
# provider=ProviderConfig(name='google'),
120120
# messages=[LDMessage(role='system', content='You are a helpful assistant.')],
121121
# )
122-
# config_value, tracker = aiclient.config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
123-
config_value, tracker = aiclient.config(
122+
# config_value = aiclient.completion_config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
123+
config_value = aiclient.completion_config(
124124
ai_config_key,
125125
context,
126126
variables={'myUserVariable': "Testing Variable"}
127127
)
128+
tracker = config_value.tracker
128129

129130
if not config_value.enabled:
130131
print("AI Config is disabled")

examples/langchain_example.py

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import os
2+
import asyncio
23
import ldclient
34
from ldclient import Context
45
from ldclient.config import Config
5-
from ldai.client import LDAIClient, AIConfig, ModelConfig, ProviderConfig, LDMessage
6-
from ldai.tracker import TokenUsage
6+
from ldai.client import LDAIClient
7+
from ldai_langchain import LangChainProvider
78
from langchain.chat_models import init_chat_model
89

910
# Set sdk_key to your LaunchDarkly SDK key.
@@ -21,43 +22,7 @@ def map_provider_to_langchain(provider_name):
2122
lower_provider = provider_name.lower()
2223
return provider_mapping.get(lower_provider, lower_provider)
2324

24-
def track_langchain_metrics(tracker, func):
25-
"""
26-
Track LangChain-specific operations.
27-
28-
This function will track the duration of the operation, the token
29-
usage, and the success or error status.
30-
31-
If the provided function throws, then this method will also throw.
32-
33-
In the case the provided function throws, this function will record the
34-
duration and an error.
35-
36-
A failed operation will not have any token usage data.
37-
38-
:param tracker: The LaunchDarkly tracker instance.
39-
:param func: Function to track.
40-
:return: Result of the tracked function.
41-
"""
42-
try:
43-
result = tracker.track_duration_of(func)
44-
tracker.track_success()
45-
if hasattr(result, "usage_metadata") and result.usage_metadata:
46-
# Extract token usage from LangChain response
47-
usage_data = result.usage_metadata
48-
token_usage = TokenUsage(
49-
input=usage_data.get("input_tokens", 0),
50-
output=usage_data.get("output_tokens", 0),
51-
total=usage_data.get("total_tokens", 0) # LangChain also has values for input_token_details { cache_creation, cache_read }
52-
)
53-
tracker.track_tokens(token_usage)
54-
except Exception:
55-
tracker.track_error()
56-
raise
57-
58-
return result
59-
60-
def main():
25+
async def async_main():
6126
if not sdk_key:
6227
print("*** Please set the LAUNCHDARKLY_SDK_KEY env first")
6328
exit()
@@ -92,12 +57,13 @@ def main():
9257
# provider=ProviderConfig(name='openai'),
9358
# messages=[LDMessage(role='system', content='You are a helpful assistant.')],
9459
# )
95-
# config_value, tracker = aiclient.config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
96-
config_value, tracker = aiclient.config(
60+
# config_value = aiclient.completion_config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
61+
config_value = aiclient.completion_config(
9762
ai_config_key,
9863
context,
9964
variables={'myUserVariable': "Testing Variable"}
10065
)
66+
tracker = config_value.tracker
10167

10268
if not config_value.enabled:
10369
print("AI Config is disabled")
@@ -120,8 +86,11 @@ def main():
12086
print("User Input:\n", USER_INPUT)
12187
messages.append({'role': 'user', 'content': USER_INPUT})
12288

123-
# Track the LangChain completion with LaunchDarkly metrics
124-
completion = track_langchain_metrics(tracker, lambda: llm.invoke(messages))
89+
# Track the LangChain completion with LaunchDarkly metrics using the LD LangChain provider's extractor
90+
completion = await tracker.track_metrics_of(
91+
lambda: llm.ainvoke(messages),
92+
LangChainProvider.get_ai_metrics_from_response,
93+
)
12594
ai_response = completion.content
12695

12796
# Add the AI response to the conversation history.
@@ -139,5 +108,9 @@ def main():
139108
ldclient.get().close()
140109

141110

111+
def main():
112+
asyncio.run(async_main())
113+
114+
142115
if __name__ == "__main__":
143116
main()

examples/langgraph_agent_example.py

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from pprint import pprint
44
from ldclient import Context
55
from ldclient.config import Config
6-
from ldai.client import LDAIClient, LDAIAgentConfig, LDAIAgentDefaults
6+
from ldai.client import LDAIClient
77
from ldai.tracker import TokenUsage
8+
from ldai_langchain import LangChainProvider
89
from langchain.chat_models import init_chat_model
910
from langgraph.prebuilt import create_react_agent
1011

@@ -29,28 +30,25 @@ def track_langgraph_metrics(tracker, func):
2930
try:
3031
result = tracker.track_duration_of(func)
3132
tracker.track_success()
32-
33-
# For LangGraph agents, usage_metadata is included on all messages that used AI
33+
3434
total_input_tokens = 0
3535
total_output_tokens = 0
3636
total_tokens = 0
37-
3837
if "messages" in result:
39-
for message in result['messages']:
40-
# Check for usage_metadata directly on the message
41-
if hasattr(message, "usage_metadata") and message.usage_metadata:
42-
usage_data = message.usage_metadata
43-
total_input_tokens += usage_data.get("input_tokens", 0)
44-
total_output_tokens += usage_data.get("output_tokens", 0)
45-
total_tokens += usage_data.get("total_tokens", 0)
46-
38+
for message in result["messages"]:
39+
metrics = LangChainProvider.get_ai_metrics_from_response(message)
40+
if metrics.usage:
41+
total_input_tokens += metrics.usage.input
42+
total_output_tokens += metrics.usage.output
43+
total_tokens += metrics.usage.total
4744
if total_tokens > 0:
48-
token_usage = TokenUsage(
49-
input=total_input_tokens,
50-
output=total_output_tokens,
51-
total=total_tokens
45+
tracker.track_tokens(
46+
TokenUsage(
47+
input=total_input_tokens,
48+
output=total_output_tokens,
49+
total=total_tokens,
50+
)
5251
)
53-
tracker.track_tokens(token_usage)
5452
except Exception:
5553
tracker.track_error()
5654
raise
@@ -88,17 +86,12 @@ def main():
8886
# Pass a default for improved resiliency when the agent config is unavailable
8987
# or LaunchDarkly is unreachable; omit for a disabled default.
9088
# Example (enabled default):
91-
# default = LDAIAgentDefaults(
89+
# default = AIAgentConfigDefault(
9290
# enabled=True,
9391
# instructions='You are a helpful assistant.',
9492
# )
9593
# agent_config = aiclient.agent_config(agent_config_key, context, default=default)
96-
agent_config = aiclient.agent_config(
97-
LDAIAgentConfig(
98-
key=agent_config_key,
99-
),
100-
context
101-
)
94+
agent_config = aiclient.agent_config(agent_config_key, context)
10295

10396
if not agent_config.enabled:
10497
print("AI Agent Config is disabled")

examples/langgraph_multi_agent_example.py

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
import ldclient
33
from ldclient import Context
44
from ldclient.config import Config
5-
from ldai.client import LDAIClient, LDAIAgentConfig, LDAIAgentDefaults
5+
from ldai.client import LDAIClient
66
from ldai.tracker import TokenUsage
7+
from ldai_langchain import LangChainProvider
78
from langchain.chat_models import init_chat_model
89
from langgraph.prebuilt import create_react_agent
910
from langgraph.graph import StateGraph, END
@@ -39,30 +40,26 @@ def track_langgraph_metrics(tracker, func, prev_message_count=0):
3940
try:
4041
result = tracker.track_duration_of(func)
4142
tracker.track_success()
42-
43-
# For LangGraph agents, usage_metadata is included on all messages that used AI
43+
4444
total_input_tokens = 0
4545
total_output_tokens = 0
4646
total_tokens = 0
47-
4847
if "messages" in result:
49-
# Only look at messages that were added during this function call
50-
new_messages = result['messages'][prev_message_count:]
48+
new_messages = result["messages"][prev_message_count:]
5149
for message in new_messages:
52-
# Check for usage_metadata directly on the message
53-
if hasattr(message, "usage_metadata") and message.usage_metadata:
54-
usage_data = message.usage_metadata
55-
total_input_tokens += usage_data.get("input_tokens", 0)
56-
total_output_tokens += usage_data.get("output_tokens", 0)
57-
total_tokens += usage_data.get("total_tokens", 0)
58-
50+
metrics = LangChainProvider.get_ai_metrics_from_response(message)
51+
if metrics.usage:
52+
total_input_tokens += metrics.usage.input
53+
total_output_tokens += metrics.usage.output
54+
total_tokens += metrics.usage.total
5955
if total_tokens > 0:
60-
token_usage = TokenUsage(
61-
input=total_input_tokens,
62-
output=total_output_tokens,
63-
total=total_tokens
56+
tracker.track_tokens(
57+
TokenUsage(
58+
input=total_input_tokens,
59+
output=total_output_tokens,
60+
total=total_tokens,
61+
)
6462
)
65-
tracker.track_tokens(token_usage)
6663
except Exception:
6764
tracker.track_error()
6865
raise
@@ -76,17 +73,12 @@ def create_agent_with_config(aiclient, config_key, context):
7673
# Pass a default for improved resiliency when the agent config is unavailable
7774
# or LaunchDarkly is unreachable; omit for a disabled default.
7875
# Example (enabled default):
79-
# default = LDAIAgentDefaults(
76+
# default = AIAgentConfigDefault(
8077
# enabled=True,
8178
# instructions='You are a helpful assistant.',
8279
# )
83-
# agent_config = aiclient.agent_config(LDAIAgentConfig(key=config_key, default=default), context)
84-
agent_config = aiclient.agent_config(
85-
LDAIAgentConfig(
86-
key=config_key,
87-
),
88-
context
89-
)
80+
# agent_config = aiclient.agent_config(config_key, context, default=default)
81+
agent_config = aiclient.agent_config(config_key, context)
9082

9183
if not agent_config.enabled:
9284
return None, None, True

examples/openai_example.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import ldclient
33
from ldclient import Context
44
from ldclient.config import Config
5-
from ldai.client import LDAIClient, AIConfig, ModelConfig, ProviderConfig, LDMessage
5+
from ldai.client import LDAIClient
66
from openai import OpenAI
77

88
openai_client = OpenAI()
@@ -50,12 +50,13 @@ def main():
5050
# provider=ProviderConfig(name='openai'),
5151
# messages=[LDMessage(role='system', content='You are a helpful assistant.')],
5252
# )
53-
# config_value, tracker = aiclient.config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
54-
config_value, tracker = aiclient.config(
53+
# config_value = aiclient.completion_config(ai_config_key, context, default, {'myUserVariable': "Testing Variable"})
54+
config_value = aiclient.completion_config(
5555
ai_config_key,
5656
context,
5757
variables={'myUserVariable': "Testing Variable"}
5858
)
59+
tracker = config_value.tracker
5960

6061
if not config_value.enabled:
6162
print("AI Config is disabled")

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ direct-judge-example = 'examples.direct_judge_example:main'
2020

2121
[tool.poetry.dependencies]
2222
python = "^3.10"
23-
launchdarkly-server-sdk-ai = "^0.16.0"
24-
launchdarkly-server-sdk-ai-langchain = "^0.3.0"
25-
launchdarkly-server-sdk-ai-openai = "^0.1.0"
23+
launchdarkly-server-sdk-ai = "^0.16.1"
24+
launchdarkly-server-sdk-ai-langchain = "^0.3.2"
25+
launchdarkly-server-sdk-ai-openai = "^0.2.1"
2626
launchdarkly-observability = { version = ">=0.1.0", optional = true }
2727

2828
boto3 = { version = ">=0.2.0", optional = true }

0 commit comments

Comments
 (0)