11import asyncio
2- from typing import List , Optional
2+ import warnings
3+ from typing import List , Union
34
45from ldai import log
56from ldai .models import AICompletionConfig , LDMessage
67from ldai .providers .model_runner import ModelRunner
7- from ldai .providers .types import JudgeResult , ModelResponse
8+ from ldai .providers .runner import Runner
9+ from ldai .providers .types import JudgeResult , ManagedResult , ModelResponse , RunnerResult
810from ldai .tracker import LDAIConfigTracker
911
1012
1113class ManagedModel :
1214 """
1315 LaunchDarkly managed wrapper for AI model invocations.
1416
15- Holds a ModelRunner. Handles conversation management, judge evaluation
16- dispatch, and tracking automatically via ``create_tracker()``.
17+ Holds a Runner (or legacy ModelRunner) . Handles conversation management,
18+ judge evaluation dispatch, and tracking automatically via ``create_tracker()``.
1719 Obtain an instance via ``LDAIClient.create_model()``.
1820 """
1921
2022 def __init__ (
2123 self ,
2224 ai_config : AICompletionConfig ,
23- model_runner : ModelRunner ,
25+ model_runner : Union [ Runner , ModelRunner ] ,
2426 ):
2527 self ._ai_config = ai_config
2628 self ._model_runner = model_runner
2729 self ._messages : List [LDMessage ] = []
2830
29- async def invoke (self , prompt : str ) -> ModelResponse :
31+ async def run (self , prompt : str ) -> ManagedResult :
3032 """
31- Invoke the model with a prompt string.
33+ Run the model with a prompt string.
3234
3335 Appends the prompt to the conversation history, prepends any
3436 system messages from the config, delegates to the runner, and
3537 appends the response to the history.
3638
39+ :param prompt: The user prompt to send to the model
40+ :return: ManagedResult containing the model's response, metric summary,
41+ and an optional evaluations task
42+ """
43+ tracker = self ._ai_config .create_tracker ()
44+
45+ user_message = LDMessage (role = 'user' , content = prompt )
46+ self ._messages .append (user_message )
47+
48+ config_messages = self ._ai_config .messages or []
49+ all_messages = config_messages + self ._messages
50+
51+ result : Union [RunnerResult , ModelResponse ] = await tracker .track_metrics_of_async (
52+ lambda r : r .metrics ,
53+ lambda : self ._invoke_runner (all_messages ),
54+ )
55+
56+ # Support both new RunnerResult and legacy ModelResponse
57+ if isinstance (result , RunnerResult ):
58+ content = result .content
59+ raw = result .raw
60+ parsed = result .parsed
61+ assistant_message = LDMessage (role = 'assistant' , content = content )
62+ else :
63+ content = result .message .content
64+ raw = getattr (result , 'raw' , None )
65+ parsed = getattr (result , 'parsed' , None )
66+ assistant_message = result .message
67+
68+ input_text = '\r \n ' .join (m .content for m in self ._messages ) if self ._messages else ''
69+
70+ evaluations_task = self ._track_judge_results (tracker , input_text , content )
71+
72+ self ._messages .append (assistant_message )
73+
74+ return ManagedResult (
75+ content = content ,
76+ metrics = tracker .get_summary (),
77+ raw = raw ,
78+ parsed = parsed ,
79+ evaluations = evaluations_task ,
80+ )
81+
82+ async def _invoke_runner (
83+ self , all_messages : List [LDMessage ]
84+ ) -> Union [RunnerResult , ModelResponse ]:
85+ """
86+ Delegate to the runner. Supports both the new ``Runner`` protocol
87+ (``run(messages) → RunnerResult``) and the legacy ``ModelRunner``
88+ (``invoke_model(messages) → ModelResponse``).
89+ """
90+ if isinstance (self ._model_runner , Runner ):
91+ return await self ._model_runner .run (all_messages )
92+ # Legacy ModelRunner path
93+ return await self ._model_runner .invoke_model (all_messages ) # type: ignore[union-attr]
94+
95+ async def invoke (self , prompt : str ) -> ModelResponse :
96+ """
97+ Invoke the model with a prompt string.
98+
99+ .. deprecated::
100+ Use :meth:`run` instead. This method will be removed in a future
101+ release once the migration to :class:`ManagedResult` is complete.
102+
37103 :param prompt: The user prompt to send to the model
38104 :return: ModelResponse containing the model's response and metrics
39105 """
106+ warnings .warn (
107+ "ManagedModel.invoke() is deprecated. Use run() instead." ,
108+ DeprecationWarning ,
109+ stacklevel = 2 ,
110+ )
40111 tracker = self ._ai_config .create_tracker ()
41112
42113 user_message = LDMessage (role = 'user' , content = prompt )
@@ -45,9 +116,9 @@ async def invoke(self, prompt: str) -> ModelResponse:
45116 config_messages = self ._ai_config .messages or []
46117 all_messages = config_messages + self ._messages
47118
48- response = await tracker .track_metrics_of_async (
119+ response : ModelResponse = await tracker .track_metrics_of_async (
49120 lambda result : result .metrics ,
50- lambda : self ._model_runner .invoke_model (all_messages ),
121+ lambda : self ._model_runner .invoke_model (all_messages ), # type: ignore[union-attr]
51122 )
52123
53124 input_text = '\r \n ' .join (m .content for m in self ._messages ) if self ._messages else ''
@@ -102,11 +173,11 @@ def append_messages(self, messages: List[LDMessage]) -> None:
102173 """
103174 self ._messages .extend (messages )
104175
105- def get_model_runner (self ) -> ModelRunner :
176+ def get_model_runner (self ) -> Union [ Runner , ModelRunner ] :
106177 """
107- Return the underlying ModelRunner for advanced use.
178+ Return the underlying runner for advanced use.
108179
109- :return: The ModelRunner instance.
180+ :return: The Runner or legacy ModelRunner instance.
110181 """
111182 return self ._model_runner
112183
0 commit comments