diff --git a/packages/sdk/server-ai/src/ldai/__init__.py b/packages/sdk/server-ai/src/ldai/__init__.py index 77e7a0a1..7976999a 100644 --- a/packages/sdk/server-ai/src/ldai/__init__.py +++ b/packages/sdk/server-ai/src/ldai/__init__.py @@ -3,14 +3,13 @@ from ldclient import log from ldai.agent_graph import AgentGraphDefinition -from ldai.chat import Chat # Deprecated — use ManagedModel from ldai.client import LDAIClient from ldai.evaluator import Evaluator from ldai.judge import Judge from ldai.managed_agent import ManagedAgent from ldai.managed_agent_graph import ManagedAgentGraph from ldai.managed_model import ManagedModel -from ldai.models import ( # Deprecated aliases for backward compatibility +from ldai.models import ( AIAgentConfig, AIAgentConfigDefault, AIAgentConfigRequest, @@ -18,14 +17,10 @@ AIAgents, AICompletionConfig, AICompletionConfigDefault, - AIConfig, AIJudgeConfig, AIJudgeConfigDefault, Edge, JudgeConfiguration, - LDAIAgent, - LDAIAgentConfig, - LDAIAgentDefaults, LDMessage, LDTool, ModelConfig, @@ -81,10 +76,4 @@ 'ModelConfig', 'ProviderConfig', 'log', - # Deprecated exports - 'AIConfig', - 'Chat', - 'LDAIAgent', - 'LDAIAgentConfig', - 'LDAIAgentDefaults', ] diff --git a/packages/sdk/server-ai/src/ldai/chat/__init__.py b/packages/sdk/server-ai/src/ldai/chat/__init__.py deleted file mode 100644 index cc3dbff9..00000000 --- a/packages/sdk/server-ai/src/ldai/chat/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Backward-compatibility shim — use ldai.managed_model.ManagedModel instead.""" - -from ldai.managed_model import ManagedModel - -# Deprecated alias -Chat = ManagedModel - -__all__ = ['ManagedModel', 'Chat'] diff --git a/packages/sdk/server-ai/src/ldai/client.py b/packages/sdk/server-ai/src/ldai/client.py index 6057107e..12d1a960 100644 --- a/packages/sdk/server-ai/src/ldai/client.py +++ b/packages/sdk/server-ai/src/ldai/client.py @@ -1,5 +1,4 @@ import uuid -import warnings from typing import Any, Callable, Dict, List, Optional, Tuple import chevron @@ -187,27 +186,6 @@ def completion_config( key, context, default or _DISABLED_COMPLETION_DEFAULT, variables, default_ai_provider ) - def config( - self, - key: str, - context: Context, - default: Optional[AICompletionConfigDefault] = None, - variables: Optional[Dict[str, Any]] = None, - ) -> AICompletionConfig: - """ - Get the value of a model configuration. - - .. deprecated:: Use :meth:`completion_config` instead. This method will be removed in a future version. - - :param key: The key of the model configuration. - :param context: The context to evaluate the model configuration in. - :param default: The default value of the model configuration. - :param variables: Additional variables for the model configuration. - :return: The value of the model configuration along with a tracker used for gathering metrics. - """ - warnings.warn("config() is deprecated, use completion_config() instead", DeprecationWarning, stacklevel=2) - return self.completion_config(key, context, default, variables) - def _judge_config( self, key: str, @@ -455,20 +433,6 @@ async def create_model( return ManagedModel(config, runner) - async def create_chat( - self, - key: str, - context: Context, - default: Optional[AICompletionConfigDefault] = None, - variables: Optional[Dict[str, Any]] = None, - default_ai_provider: Optional[str] = None, - ) -> Optional[ManagedModel]: - """ - .. deprecated:: Use :meth:`create_model` instead. This method will be removed in a future version. - """ - warnings.warn("create_chat() is deprecated, use create_model() instead", DeprecationWarning, stacklevel=2) - return await self.create_model(key, context, default, variables, default_ai_provider) - async def create_agent( self, key: str, @@ -578,23 +542,6 @@ def agent_config( key, context, default or _DISABLED_AGENT_DEFAULT, variables ) - def agent( - self, - config: AIAgentConfigRequest, - context: Context, - ) -> AIAgentConfig: - """ - Retrieve a single AI Config agent. - - .. deprecated:: Use :meth:`agent_config` instead. This method will be removed in a future version. - - :param config: The agent configuration to use. - :param context: The context to evaluate the agent configuration in. - :return: Configured AIAgentConfig instance. - """ - warnings.warn("agent() is deprecated, use agent_config() instead", DeprecationWarning, stacklevel=2) - return self.agent_config(config.key, context, config.default, config.variables) - def agent_configs( self, agent_configs: List[AIAgentConfigRequest], @@ -827,23 +774,6 @@ async def create_agent_graph( return ManagedAgentGraph(graph, runner) - def agents( - self, - agent_configs: List[AIAgentConfigRequest], - context: Context, - ) -> AIAgents: - """ - Retrieve multiple AI agent configurations. - - .. deprecated:: Use :meth:`agent_configs` instead. This method will be removed in a future version. - - :param agent_configs: List of agent configurations to retrieve. - :param context: The context to evaluate the agent configurations in. - :return: Dictionary mapping agent keys to their AIAgentConfig configurations. - """ - warnings.warn("agents() is deprecated, use agent_configs() instead", DeprecationWarning, stacklevel=2) - return self.agent_configs(agent_configs, context) - def __evaluate( self, key: str, diff --git a/packages/sdk/server-ai/src/ldai/models.py b/packages/sdk/server-ai/src/ldai/models.py index 47fbdddb..af49f045 100644 --- a/packages/sdk/server-ai/src/ldai/models.py +++ b/packages/sdk/server-ai/src/ldai/models.py @@ -1,4 +1,3 @@ -import warnings from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Union @@ -424,22 +423,3 @@ class AIAgentGraphConfig: root_config_key: str edges: List[Edge] enabled: bool = True - - -# ============================================================================ -# Deprecated Type Aliases for Backward Compatibility -# ============================================================================ - -# Note: AIConfig is now defined above as a base class (line 169). -# For backward compatibility, code should migrate to: -# - Use AICompletionConfigDefault for default/input values -# - Use AICompletionConfig for return values - -# Deprecated: Use AIAgentConfigDefault instead -LDAIAgentDefaults = AIAgentConfigDefault - -# Deprecated: Use AIAgentConfigRequest instead -LDAIAgentConfig = AIAgentConfigRequest - -# Deprecated: Use AIAgentConfig instead (note: this was the old return type) -LDAIAgent = AIAgentConfig diff --git a/packages/sdk/server-ai/src/ldai/tracker.py b/packages/sdk/server-ai/src/ldai/tracker.py index 75b10d51..16d860f9 100644 --- a/packages/sdk/server-ai/src/ldai/tracker.py +++ b/packages/sdk/server-ai/src/ldai/tracker.py @@ -3,7 +3,6 @@ import base64 import json import time -import warnings from dataclasses import dataclass from enum import Enum from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional @@ -59,19 +58,6 @@ def duration_ms(self) -> Optional[int]: """Duration of the AI operation in milliseconds.""" return self._duration_ms - @property - def duration(self) -> Optional[int]: - """ - .. deprecated:: - Use :attr:`duration_ms` instead. - """ - warnings.warn( - "LDAIMetricSummary.duration is deprecated. Use duration_ms instead.", - DeprecationWarning, - stacklevel=2, - ) - return self._duration_ms - @property def success(self) -> Optional[bool]: return self._success @@ -463,48 +449,6 @@ def track_error(self) -> None: "$ld:ai:generation:error", self._context, self.__get_track_data(), 1 ) - def track_openai_metrics(self, func): - """ - Track OpenAI-specific operations. - - .. deprecated:: Use :meth:`track_metrics_of` with ``get_ai_metrics_from_response`` - from ``ldai_openai`` instead. This method will be removed in a future version. - - This function will track the duration of the operation, the token - usage, and the success or error status. - - If the provided function throws, then this method will also throw. - - In the case the provided function throws, this function will record the - duration and an error. - - A failed operation will not have any token usage data. - - :param func: Function to track. - :return: Result of the tracked function. - """ - warnings.warn( - "track_openai_metrics is deprecated. Use track_metrics_of with " - "get_ai_metrics_from_response from ldai_openai instead.", - DeprecationWarning, - stacklevel=2, - ) - start_ns = time.perf_counter_ns() - try: - result = func() - duration = (time.perf_counter_ns() - start_ns) // 1_000_000 - self.track_duration(duration) - self.track_success() - if hasattr(result, "usage") and hasattr(result.usage, "to_dict"): - self.track_tokens(_openai_to_token_usage(result.usage.to_dict())) - except Exception: - duration = (time.perf_counter_ns() - start_ns) // 1_000_000 - self.track_duration(duration) - self.track_error() - raise - - return result - def track_bedrock_converse_metrics(self, res: dict) -> dict: """ Track AWS Bedrock conversation operations. @@ -597,20 +541,6 @@ def _bedrock_to_token_usage(data: dict) -> TokenUsage: ) -def _openai_to_token_usage(data: dict) -> TokenUsage: - """ - Convert an OpenAI usage dictionary to a TokenUsage object. - - :param data: Dictionary containing OpenAI usage data. - :return: TokenUsage object containing usage data. - """ - return TokenUsage( - total=data.get("total_tokens", 0), - input=data.get("prompt_tokens", 0), - output=data.get("completion_tokens", 0), - ) - - class AIGraphTracker: """ Tracks graph-level metrics for AI agent graph operations. diff --git a/packages/sdk/server-ai/tests/test_agents.py b/packages/sdk/server-ai/tests/test_agents.py index fdc6fdc7..fbf37b04 100644 --- a/packages/sdk/server-ai/tests/test_agents.py +++ b/packages/sdk/server-ai/tests/test_agents.py @@ -3,8 +3,8 @@ from ldclient.integrations.test_data import TestData from ldai import ( - LDAIAgentConfig, - LDAIAgentDefaults, + AIAgentConfigDefault, + AIAgentConfigRequest, LDAIClient, ModelConfig, ProviderConfig, @@ -140,9 +140,9 @@ def ldai_client(client: LDClient) -> LDAIClient: def test_single_agent_method(ldai_client: LDAIClient): """Test the single agent() method functionality.""" context = Context.builder('user-key').set('expertise', 'advanced').build() - config = LDAIAgentConfig( + config = AIAgentConfigRequest( key='research-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=False, model=ModelConfig('fallback-model'), instructions="Default instructions" @@ -150,7 +150,7 @@ def test_single_agent_method(ldai_client: LDAIClient): variables={'topic': 'quantum computing'} ) - agent = ldai_client.agent(config, context) + agent = ldai_client.agent_config(config.key, context, config.default, config.variables) assert agent.enabled is True assert agent.model is not None @@ -169,9 +169,9 @@ def test_single_agent_method(ldai_client: LDAIClient): def test_single_agent_with_defaults(ldai_client: LDAIClient): """Test single agent method with non-existent flag using defaults.""" context = Context.create('user-key') - config = LDAIAgentConfig( + config = AIAgentConfigRequest( key='non-existent-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=True, model=ModelConfig('default-model', parameters={'temp': 0.8}), provider=ProviderConfig('default-provider'), @@ -180,7 +180,7 @@ def test_single_agent_with_defaults(ldai_client: LDAIClient): variables={'task': 'general assistance'} ) - agent = ldai_client.agent(config, context) + agent = ldai_client.agent_config(config.key, context, config.default, config.variables) assert agent.enabled is True assert agent.model is not None and agent.model.name == 'default-model' @@ -191,22 +191,22 @@ def test_single_agent_with_defaults(ldai_client: LDAIClient): def test_agents_method_with_configs(ldai_client: LDAIClient): - """Test the new agents() method with LDAIAgentConfig objects.""" + """Test the new agents() method with AIAgentConfigRequest objects.""" context = Context.create('user-key') agent_configs = [ - LDAIAgentConfig( + AIAgentConfigRequest( key='customer-support-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=False, model=ModelConfig('fallback-model'), instructions="Default support" ), variables={'company_name': 'Acme Corp'} ), - LDAIAgentConfig( + AIAgentConfigRequest( key='sales-assistant', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=False, model=ModelConfig('fallback-model'), instructions="Default sales" @@ -215,7 +215,7 @@ def test_agents_method_with_configs(ldai_client: LDAIClient): ) ] - agents = ldai_client.agents(agent_configs, context) + agents = ldai_client.agent_configs(agent_configs, context) assert len(agents) == 2 assert 'customer-support-agent' in agents @@ -236,17 +236,17 @@ def test_agents_method_different_variables_per_agent(ldai_client: LDAIClient): context = Context.builder('user-key').name('Alice').build() agent_configs = [ - LDAIAgentConfig( + AIAgentConfigRequest( key='personalized-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=True, instructions="Default personal" ), variables={} # Will use context only ), - LDAIAgentConfig( + AIAgentConfigRequest( key='customer-support-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=True, instructions="Default support" ), @@ -254,7 +254,7 @@ def test_agents_method_different_variables_per_agent(ldai_client: LDAIClient): ) ] - agents = ldai_client.agents(agent_configs, context) + agents = ldai_client.agent_configs(agent_configs, context) personal_agent = agents['personalized-agent'] assert personal_agent.instructions == 'Hello Alice! I am your personal assistant. Your user key is user-key.' @@ -273,9 +273,9 @@ def test_agents_with_multi_context_interpolation(ldai_client: LDAIClient): context = Context.multi_builder().add(user_context).add(org_context).build() agent_configs = [ - LDAIAgentConfig( + AIAgentConfigRequest( key='multi-context-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=True, instructions="Default multi-context" ), @@ -283,7 +283,7 @@ def test_agents_with_multi_context_interpolation(ldai_client: LDAIClient): ) ] - agents = ldai_client.agents(agent_configs, context) + agents = ldai_client.agent_configs(agent_configs, context) agent = agents['multi-context-agent'] assert agent.instructions == 'Welcome Alice from LaunchDarkly! Your organization tier is Enterprise.' @@ -292,13 +292,13 @@ def test_agents_with_multi_context_interpolation(ldai_client: LDAIClient): def test_disabled_agent_single_method(ldai_client: LDAIClient): """Test that disabled agents are properly handled in single agent method.""" context = Context.create('user-key') - config = LDAIAgentConfig( + config = AIAgentConfigRequest( key='disabled-agent', - default=LDAIAgentDefaults(enabled=False), + default=AIAgentConfigDefault(enabled=False), variables={} ) - agent = ldai_client.agent(config, context) + agent = ldai_client.agent_config(config.key, context, config.default, config.variables) assert agent.enabled is False assert callable(agent.create_tracker) @@ -309,14 +309,14 @@ def test_disabled_agent_multiple_method(ldai_client: LDAIClient): context = Context.create('user-key') agent_configs = [ - LDAIAgentConfig( + AIAgentConfigRequest( key='disabled-agent', - default=LDAIAgentDefaults(enabled=False), + default=AIAgentConfigDefault(enabled=False), variables={} ) ] - agents = ldai_client.agents(agent_configs, context) + agents = ldai_client.agent_configs(agent_configs, context) assert len(agents) == 1 assert agents['disabled-agent'].enabled is False @@ -325,16 +325,16 @@ def test_disabled_agent_multiple_method(ldai_client: LDAIClient): def test_agent_with_missing_metadata(ldai_client: LDAIClient): """Test agent handling when metadata is minimal or missing.""" context = Context.create('user-key') - config = LDAIAgentConfig( + config = AIAgentConfigRequest( key='minimal-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=False, model=ModelConfig('default-model'), instructions="Default instructions" ) ) - agent = ldai_client.agent(config, context) + agent = ldai_client.agent_config(config.key, context, config.default, config.variables) assert agent.enabled is True # From flag assert agent.instructions == 'Minimal agent configuration.' @@ -343,10 +343,10 @@ def test_agent_with_missing_metadata(ldai_client: LDAIClient): def test_agent_config_dataclass(): - """Test the LDAIAgentConfig dataclass functionality.""" - config = LDAIAgentConfig( + """Test the AIAgentConfigRequest dataclass functionality.""" + config = AIAgentConfigRequest( key='test-agent', - default=LDAIAgentDefaults( + default=AIAgentConfigDefault( enabled=True, instructions="Test instructions" ), @@ -359,9 +359,9 @@ def test_agent_config_dataclass(): assert config.variables == {'key': 'value'} # Test with no variables - config_no_vars = LDAIAgentConfig( + config_no_vars = AIAgentConfigRequest( key='test-agent-2', - default=LDAIAgentDefaults(enabled=False) + default=AIAgentConfigDefault(enabled=False) ) assert config_no_vars.key == 'test-agent-2' @@ -382,10 +382,10 @@ def test_agents_request_without_default_uses_disabled(ldai_client: LDAIClient): context = Context.create('user-key') agent_requests = [ - LDAIAgentConfig(key='missing-agent'), + AIAgentConfigRequest(key='missing-agent'), ] - agents = ldai_client.agents(agent_requests, context) + agents = ldai_client.agent_configs(agent_requests, context) assert 'missing-agent' in agents assert agents['missing-agent'].enabled is False diff --git a/packages/sdk/server-ai/tests/test_model_config.py b/packages/sdk/server-ai/tests/test_model_config.py index 3baaec10..838b39d9 100644 --- a/packages/sdk/server-ai/tests/test_model_config.py +++ b/packages/sdk/server-ai/tests/test_model_config.py @@ -155,7 +155,7 @@ def test_uses_default_on_invalid_flag(ldai_client: LDAIClient): ) variables = {'name': 'World'} - config = ldai_client.config('missing-flag', context, default, variables) + config = ldai_client.completion_config('missing-flag', context, default, variables) assert config.messages is not None assert len(config.messages) > 0 @@ -177,7 +177,7 @@ def test_model_config_interpolation(ldai_client: LDAIClient): ) variables = {'name': 'World'} - config = ldai_client.config('model-config', context, default, variables) + config = ldai_client.completion_config('model-config', context, default, variables) assert config.messages is not None assert len(config.messages) > 0 @@ -194,7 +194,7 @@ def test_model_config_no_variables(ldai_client: LDAIClient): context = Context.create('user-key') default = AICompletionConfigDefault(enabled=True, model=ModelConfig('fake-model'), messages=[]) - config = ldai_client.config('model-config', context, default, {}) + config = ldai_client.completion_config('model-config', context, default, {}) assert config.messages is not None assert len(config.messages) > 0 @@ -212,7 +212,7 @@ def test_provider_config_handling(ldai_client: LDAIClient): default = AICompletionConfigDefault(enabled=True, model=ModelConfig('fake-model'), messages=[]) variables = {'name': 'World'} - config = ldai_client.config('model-config', context, default, variables) + config = ldai_client.completion_config('model-config', context, default, variables) assert config.provider is not None assert config.provider.name == 'fakeProvider' @@ -223,7 +223,7 @@ def test_context_interpolation(ldai_client: LDAIClient): default = AICompletionConfigDefault(enabled=True, model=ModelConfig('fake-model'), messages=[]) variables = {'name': 'World'} - config = ldai_client.config( + config = ldai_client.completion_config( 'ctx-interpolation', context, default, variables ) @@ -246,7 +246,7 @@ def test_multi_context_interpolation(ldai_client: LDAIClient): default = AICompletionConfigDefault(enabled=True, model=ModelConfig('fake-model'), messages=[]) variables = {'name': 'World'} - config = ldai_client.config( + config = ldai_client.completion_config( 'multi-ctx-interpolation', context, default, variables ) @@ -267,7 +267,7 @@ def test_model_config_multiple(ldai_client: LDAIClient): default = AICompletionConfigDefault(enabled=True, model=ModelConfig('fake-model'), messages=[]) variables = {'name': 'World', 'day': 'Monday'} - config = ldai_client.config( + config = ldai_client.completion_config( 'multiple-messages', context, default, variables ) @@ -287,7 +287,7 @@ def test_model_config_disabled(ldai_client: LDAIClient): context = Context.create('user-key') default = AICompletionConfigDefault(enabled=False, model=ModelConfig('fake-model'), messages=[]) - config = ldai_client.config('off-config', context, default, {}) + config = ldai_client.completion_config('off-config', context, default, {}) assert config.model is not None assert config.enabled is False @@ -300,7 +300,7 @@ def test_model_initial_config_disabled(ldai_client: LDAIClient): context = Context.create('user-key') default = AICompletionConfigDefault(enabled=False, model=ModelConfig('fake-model'), messages=[]) - config = ldai_client.config('initial-config-disabled', context, default, {}) + config = ldai_client.completion_config('initial-config-disabled', context, default, {}) assert config.enabled is False assert config.model is None @@ -312,7 +312,7 @@ def test_model_initial_config_enabled(ldai_client: LDAIClient): context = Context.create('user-key') default = AICompletionConfigDefault(enabled=False, model=ModelConfig('fake-model'), messages=[]) - config = ldai_client.config('initial-config-enabled', context, default, {}) + config = ldai_client.completion_config('initial-config-enabled', context, default, {}) assert config.enabled is True assert config.model is None @@ -320,7 +320,7 @@ def test_model_initial_config_enabled(ldai_client: LDAIClient): assert config.provider is None -def test_config_method_tracking(ldai_client: LDAIClient): +def test_completion_config_method_tracking(ldai_client: LDAIClient): from unittest.mock import Mock mock_client = Mock() @@ -335,7 +335,7 @@ def test_config_method_tracking(ldai_client: LDAIClient): context = Context.create('user-key') default = AICompletionConfigDefault(enabled=False, model=ModelConfig('fake-model'), messages=[]) - config = client.config('test-config-key', context, default) + client.completion_config('test-config-key', context, default) mock_client.track.assert_any_call( '$ld:ai:usage:completion-config', diff --git a/packages/sdk/server-ai/tests/test_tracker.py b/packages/sdk/server-ai/tests/test_tracker.py index fe517e8d..0063a700 100644 --- a/packages/sdk/server-ai/tests/test_tracker.py +++ b/packages/sdk/server-ai/tests/test_tracker.py @@ -49,7 +49,7 @@ def test_summary_starts_empty(client: LDClient): provider_name="fakeProvider", context=context, ) - assert tracker.get_summary().duration is None + assert tracker.get_summary().duration_ms is None assert tracker.get_summary().feedback is None assert tracker.get_summary().success is None assert tracker.get_summary().tokens is None @@ -72,7 +72,7 @@ def test_tracks_duration(client: LDClient): 100, ) - assert tracker.get_summary().duration == 100 + assert tracker.get_summary().duration_ms == 100 def test_tracks_duration_of(client: LDClient): @@ -208,7 +208,7 @@ def test_tracks_bedrock_metrics(client: LDClient): client.track.assert_has_calls(calls) # type: ignore assert tracker.get_summary().success is True - assert tracker.get_summary().duration == 50 + assert tracker.get_summary().duration_ms == 50 assert tracker.get_summary().tokens == TokenUsage(330, 220, 110) @@ -246,79 +246,10 @@ def test_tracks_bedrock_metrics_with_error(client: LDClient): client.track.assert_has_calls(calls) # type: ignore assert tracker.get_summary().success is False - assert tracker.get_summary().duration == 50 + assert tracker.get_summary().duration_ms == 50 assert tracker.get_summary().tokens == TokenUsage(330, 220, 110) -def test_tracks_openai_metrics(client: LDClient): - context = Context.create("user-key") - tracker = LDAIConfigTracker( - ld_client=client, run_id="test-run-id", config_key="config-key", - variation_key="variation-key", version=3, model_name="fakeModel", - provider_name="fakeProvider", context=context, - ) - - class Result: - def __init__(self): - self.usage = Usage() - - class Usage: - def to_dict(self): - return { - "total_tokens": 330, - "prompt_tokens": 220, - "completion_tokens": 110, - } - - def get_result(): - return Result() - - with pytest.warns(DeprecationWarning, match="track_openai_metrics is deprecated"): - tracker.track_openai_metrics(get_result) - - _otd = {"runId": ANY, "variationKey": "variation-key", "configKey": "config-key", - "version": 3, "modelName": "fakeModel", "providerName": "fakeProvider"} - calls = [ - call("$ld:ai:generation:success", context, _otd, 1), - call("$ld:ai:tokens:total", context, _otd, 330), - call("$ld:ai:tokens:input", context, _otd, 220), - call("$ld:ai:tokens:output", context, _otd, 110), - ] - - client.track.assert_has_calls(calls, any_order=False) # type: ignore - - assert tracker.get_summary().tokens == TokenUsage(330, 220, 110) - - -def test_tracks_openai_metrics_with_exception(client: LDClient): - context = Context.create("user-key") - tracker = LDAIConfigTracker( - ld_client=client, run_id="test-run-id", config_key="config-key", - variation_key="variation-key", version=3, model_name="fakeModel", - provider_name="fakeProvider", context=context, - ) - - def raise_exception(): - raise ValueError("Something went wrong") - - with pytest.warns(DeprecationWarning, match="track_openai_metrics is deprecated"): - try: - tracker.track_openai_metrics(raise_exception) - assert False, "Should have thrown an exception" - except ValueError: - pass - - _eetd = {"runId": ANY, "variationKey": "variation-key", "configKey": "config-key", - "version": 3, "modelName": "fakeModel", "providerName": "fakeProvider"} - calls = [ - call("$ld:ai:generation:error", context, _eetd, 1), - ] - - client.track.assert_has_calls(calls, any_order=False) # type: ignore - - assert tracker.get_summary().tokens is None - - @pytest.mark.parametrize( "kind,label", [ @@ -802,7 +733,7 @@ def test_duplicate_track_duration_is_ignored(client: LDClient): tracker.track_duration(200) assert client.track.call_count == 1 # type: ignore - assert tracker.get_summary().duration == 100 + assert tracker.get_summary().duration_ms == 100 def test_duplicate_track_time_to_first_token_is_ignored(client: LDClient):