@@ -125,6 +125,81 @@ def to_dict(self) -> dict:
125
125
}
126
126
127
127
128
+ @dataclass (frozen = True )
129
+ class LDAIAgent :
130
+ """
131
+ Represents an AI agent configuration with instructions and model settings.
132
+
133
+ An agent is similar to an AIConfig but focuses on instructions rather than messages,
134
+ making it suitable for AI assistant/agent use cases.
135
+ """
136
+ enabled : Optional [bool ] = None
137
+ model : Optional [ModelConfig ] = None
138
+ provider : Optional [ProviderConfig ] = None
139
+ instructions : Optional [str ] = None
140
+ tracker : Optional [LDAIConfigTracker ] = None
141
+
142
+ def to_dict (self ) -> Dict [str , Any ]:
143
+ """
144
+ Render the given agent as a dictionary object.
145
+ """
146
+ result : Dict [str , Any ] = {
147
+ '_ldMeta' : {
148
+ 'enabled' : self .enabled or False ,
149
+ },
150
+ 'model' : self .model .to_dict () if self .model else None ,
151
+ 'provider' : self .provider .to_dict () if self .provider else None ,
152
+ }
153
+ if self .instructions is not None :
154
+ result ['instructions' ] = self .instructions
155
+ return result
156
+
157
+
158
+ @dataclass (frozen = True )
159
+ class LDAIAgentDefaults :
160
+ """
161
+ Default values for AI agent configurations.
162
+
163
+ Similar to LDAIAgent but without tracker and with optional enabled field,
164
+ used as fallback values when agent configurations are not available.
165
+ """
166
+ enabled : Optional [bool ] = None
167
+ model : Optional [ModelConfig ] = None
168
+ provider : Optional [ProviderConfig ] = None
169
+ instructions : Optional [str ] = None
170
+
171
+ def to_dict (self ) -> Dict [str , Any ]:
172
+ """
173
+ Render the given agent defaults as a dictionary object.
174
+ """
175
+ result : Dict [str , Any ] = {
176
+ '_ldMeta' : {
177
+ 'enabled' : self .enabled or False ,
178
+ },
179
+ 'model' : self .model .to_dict () if self .model else None ,
180
+ 'provider' : self .provider .to_dict () if self .provider else None ,
181
+ }
182
+ if self .instructions is not None :
183
+ result ['instructions' ] = self .instructions
184
+ return result
185
+
186
+
187
+ @dataclass
188
+ class LDAIAgentConfig :
189
+ """
190
+ Configuration for individual agent in batch requests.
191
+
192
+ Combines agent key with its specific default configuration and variables.
193
+ """
194
+ key : str
195
+ default_value : LDAIAgentDefaults
196
+ variables : Optional [Dict [str , Any ]] = None
197
+
198
+
199
+ # Type alias for multiple agents
200
+ LDAIAgents = Dict [str , LDAIAgent ]
201
+
202
+
128
203
class LDAIClient :
129
204
"""The LaunchDarkly AI SDK client object."""
130
205
@@ -147,13 +222,144 @@ def config(
147
222
:param variables: Additional variables for the model configuration.
148
223
:return: The value of the model configuration along with a tracker used for gathering metrics.
149
224
"""
150
- variation = self ._client .variation (key , context , default_value .to_dict ())
225
+ model , provider , messages , instructions , tracker , enabled = self .__evaluate (key , context , default_value .to_dict (), variables )
226
+
227
+ config = AIConfig (
228
+ enabled = bool (enabled ),
229
+ model = model ,
230
+ messages = messages ,
231
+ provider = provider ,
232
+ )
233
+
234
+ return config , tracker
235
+
236
+ def agent (
237
+ self ,
238
+ config : LDAIAgentConfig ,
239
+ context : Context ,
240
+ ) -> LDAIAgent :
241
+ """
242
+ Retrieve a single AI Config agent.
243
+
244
+ This method retrieves a single agent configuration with instructions
245
+ dynamically interpolated using the provided variables and context data.
246
+
247
+ Example::
248
+
249
+ agent = client.agent(LDAIAgentConfig(
250
+ key='research_agent',
251
+ default_value=LDAIAgentDefaults(
252
+ enabled=True,
253
+ model=ModelConfig('gpt-4'),
254
+ instructions="You are a research assistant specializing in {{topic}}."
255
+ ),
256
+ variables={'topic': 'climate change'}
257
+ ), context)
258
+
259
+ if agent.enabled:
260
+ research_result = agent.instructions # Interpolated instructions
261
+ agent.tracker.track_success()
262
+
263
+ :param config: The agent configuration to use.
264
+ :param context: The context to evaluate the agent configuration in.
265
+ :return: Configured LDAIAgent instance.
266
+ """
267
+ # Track single agent usage
268
+ self ._client .track (
269
+ "$ld:ai:agent:function:single" ,
270
+ context ,
271
+ config .key ,
272
+ 1
273
+ )
274
+
275
+ return self .__evaluate_agent (config .key , context , config .default_value , config .variables )
276
+
277
+ def agents (
278
+ self ,
279
+ agent_configs : List [LDAIAgentConfig ],
280
+ context : Context ,
281
+ ) -> LDAIAgents :
282
+ """
283
+ Retrieve multiple AI agent configurations.
284
+
285
+ This method allows you to retrieve multiple agent configurations in a single call,
286
+ with each agent having its own default configuration and variables for instruction
287
+ interpolation.
288
+
289
+ Example::
290
+
291
+ agents = client.agents([
292
+ LDAIAgentConfig(
293
+ key='research_agent',
294
+ default_value=LDAIAgentDefaults(
295
+ enabled=True,
296
+ instructions='You are a research assistant.'
297
+ ),
298
+ variables={'topic': 'climate change'}
299
+ ),
300
+ LDAIAgentConfig(
301
+ key='writing_agent',
302
+ default_value=LDAIAgentDefaults(
303
+ enabled=True,
304
+ instructions='You are a writing assistant.'
305
+ ),
306
+ variables={'style': 'academic'}
307
+ )
308
+ ], context)
309
+
310
+ research_result = agents["research_agent"].instructions
311
+ agents["research_agent"].tracker.track_success()
312
+
313
+ :param agent_configs: List of agent configurations to retrieve.
314
+ :param context: The context to evaluate the agent configurations in.
315
+ :return: Dictionary mapping agent keys to their LDAIAgent configurations.
316
+ """
317
+ # Track multiple agents usage
318
+ agent_count = len (agent_configs )
319
+ self ._client .track (
320
+ "$ld:ai:agent:function:multiple" ,
321
+ context ,
322
+ agent_count ,
323
+ agent_count
324
+ )
325
+
326
+ result : LDAIAgents = {}
327
+
328
+ for config in agent_configs :
329
+ agent = self .__evaluate_agent (
330
+ config .key ,
331
+ context ,
332
+ config .default_value ,
333
+ config .variables
334
+ )
335
+ result [config .key ] = agent
336
+
337
+ return result
338
+
339
+ def __evaluate (
340
+ self ,
341
+ key : str ,
342
+ context : Context ,
343
+ default_dict : Dict [str , Any ],
344
+ variables : Optional [Dict [str , Any ]] = None ,
345
+ ) -> Tuple [Optional [ModelConfig ], Optional [ProviderConfig ], Optional [List [LDMessage ]], Optional [str ], LDAIConfigTracker , bool ]:
346
+ """
347
+ Internal method to evaluate a configuration and extract components.
348
+
349
+ :param key: The configuration key.
350
+ :param context: The evaluation context.
351
+ :param default_dict: Default configuration as dictionary.
352
+ :param variables: Variables for interpolation.
353
+ :return: Tuple of (model, provider, messages, instructions, tracker, enabled).
354
+ """
355
+ variation = self ._client .variation (key , context , default_dict )
151
356
152
357
all_variables = {}
153
358
if variables :
154
359
all_variables .update (variables )
155
360
all_variables ['ldctx' ] = context .to_dict ()
156
361
362
+ # Extract messages
157
363
messages = None
158
364
if 'messages' in variation and isinstance (variation ['messages' ], list ) and all (
159
365
isinstance (entry , dict ) for entry in variation ['messages' ]
@@ -168,11 +374,18 @@ def config(
168
374
for entry in variation ['messages' ]
169
375
]
170
376
377
+ # Extract instructions
378
+ instructions = None
379
+ if 'instructions' in variation and isinstance (variation ['instructions' ], str ):
380
+ instructions = self .__interpolate_template (variation ['instructions' ], all_variables )
381
+
382
+ # Extract provider config
171
383
provider_config = None
172
384
if 'provider' in variation and isinstance (variation ['provider' ], dict ):
173
385
provider = variation ['provider' ]
174
386
provider_config = ProviderConfig (provider .get ('name' , '' ))
175
387
388
+ # Extract model config
176
389
model = None
177
390
if 'model' in variation and isinstance (variation ['model' ], dict ):
178
391
parameters = variation ['model' ].get ('parameters' , None )
@@ -183,6 +396,7 @@ def config(
183
396
custom = custom
184
397
)
185
398
399
+ # Create tracker
186
400
tracker = LDAIConfigTracker (
187
401
self ._client ,
188
402
variation .get ('_ldMeta' , {}).get ('variationKey' , '' ),
@@ -192,21 +406,46 @@ def config(
192
406
)
193
407
194
408
enabled = variation .get ('_ldMeta' , {}).get ('enabled' , False )
195
- config = AIConfig (
196
- enabled = bool (enabled ),
197
- model = model ,
198
- messages = messages ,
199
- provider = provider_config ,
409
+
410
+ return model , provider_config , messages , instructions , tracker , enabled
411
+
412
+ def __evaluate_agent (
413
+ self ,
414
+ key : str ,
415
+ context : Context ,
416
+ default_value : LDAIAgentDefaults ,
417
+ variables : Optional [Dict [str , Any ]] = None ,
418
+ ) -> LDAIAgent :
419
+ """
420
+ Internal method to evaluate an agent configuration.
421
+
422
+ :param key: The agent configuration key.
423
+ :param context: The evaluation context.
424
+ :param default_value: Default agent values.
425
+ :param variables: Variables for interpolation.
426
+ :return: Configured LDAIAgent instance.
427
+ """
428
+ model , provider , messages , instructions , tracker , enabled = self .__evaluate (
429
+ key , context , default_value .to_dict (), variables
200
430
)
201
431
202
- return config , tracker
432
+ # For agents, prioritize instructions over messages
433
+ final_instructions = instructions if instructions is not None else default_value .instructions
434
+
435
+ return LDAIAgent (
436
+ enabled = bool (enabled ) if enabled is not None else default_value .enabled ,
437
+ model = model or default_value .model ,
438
+ provider = provider or default_value .provider ,
439
+ instructions = final_instructions ,
440
+ tracker = tracker ,
441
+ )
203
442
204
443
def __interpolate_template (self , template : str , variables : Dict [str , Any ]) -> str :
205
444
"""
206
- Interpolate the template with the given variables.
445
+ Interpolate the template with the given variables using Mustache format .
207
446
208
- :template: The template string.
209
- :variables: The variables to interpolate into the template.
447
+ :param template: The template string.
448
+ :param variables: The variables to interpolate into the template.
210
449
:return: The interpolated string.
211
450
"""
212
451
return chevron .render (template , variables )
0 commit comments