2
2
3
3
import inspect
4
4
from logging import Logger
5
- from typing import Any , Dict , Optional
5
+ from typing import Any , Callable , Dict , List , Optional , Type , TypeVar , Union
6
6
7
7
from semantic_kernel .connectors .ai .ai_exception import AIException
8
8
from semantic_kernel .connectors .ai .chat_completion_client_base import (
12
12
from semantic_kernel .connectors .ai .complete_request_settings import (
13
13
CompleteRequestSettings ,
14
14
)
15
+ from semantic_kernel .connectors .ai .embeddings .embedding_generator_base import (
16
+ EmbeddingGeneratorBase ,
17
+ )
15
18
from semantic_kernel .connectors .ai .text_completion_client_base import (
16
19
TextCompletionClientBase ,
17
20
)
18
21
from semantic_kernel .kernel_base import KernelBase
19
- from semantic_kernel .kernel_config import KernelConfig
20
22
from semantic_kernel .kernel_exception import KernelException
21
23
from semantic_kernel .kernel_extensions import KernelExtensions
22
24
from semantic_kernel .memory .memory_store_base import MemoryStoreBase
26
28
from semantic_kernel .orchestration .sk_context import SKContext
27
29
from semantic_kernel .orchestration .sk_function import SKFunction
28
30
from semantic_kernel .orchestration .sk_function_base import SKFunctionBase
31
+ from semantic_kernel .reliability .pass_through_without_retry import (
32
+ PassThroughWithoutRetry ,
33
+ )
34
+ from semantic_kernel .reliability .retry_mechanism import RetryMechanism
29
35
from semantic_kernel .semantic_functions .semantic_function_config import (
30
36
SemanticFunctionConfig ,
31
37
)
41
47
from semantic_kernel .utils .null_logger import NullLogger
42
48
from semantic_kernel .utils .validation import validate_function_name , validate_skill_name
43
49
50
+ T = TypeVar ("T" )
44
51
45
52
class Kernel (KernelBase , KernelExtensions ):
46
53
_log : Logger
47
- _config : KernelConfig
48
54
_skill_collection : SkillCollectionBase
49
55
_prompt_template_engine : PromptTemplatingEngine
50
56
_memory : SemanticTextMemoryBase
@@ -54,11 +60,9 @@ def __init__(
54
60
skill_collection : Optional [SkillCollectionBase ] = None ,
55
61
prompt_template_engine : Optional [PromptTemplatingEngine ] = None ,
56
62
memory : Optional [SemanticTextMemoryBase ] = None ,
57
- config : Optional [KernelConfig ] = None ,
58
63
log : Optional [Logger ] = None ,
59
64
) -> None :
60
65
self ._log = log if log else NullLogger ()
61
- self ._config = config if config else KernelConfig ()
62
66
self ._skill_collection = (
63
67
skill_collection if skill_collection else SkillCollection (self ._log )
64
68
)
@@ -69,13 +73,25 @@ def __init__(
69
73
)
70
74
self ._memory = memory if memory else NullMemory ()
71
75
76
+ self ._text_completion_services : Dict [
77
+ str , Callable [["KernelBase" ], TextCompletionClientBase ]
78
+ ] = {}
79
+ self ._chat_services : Dict [
80
+ str , Callable [["KernelBase" ], ChatCompletionClientBase ]
81
+ ] = {}
82
+ self ._text_embedding_generation_services : Dict [
83
+ str , Callable [["KernelBase" ], EmbeddingGeneratorBase ]
84
+ ] = {}
85
+
86
+ self ._default_text_completion_service : Optional [str ] = None
87
+ self ._default_chat_service : Optional [str ] = None
88
+ self ._default_text_embedding_generation_service : Optional [str ] = None
89
+
90
+ self ._retry_mechanism : RetryMechanism = PassThroughWithoutRetry ()
91
+
72
92
def kernel (self ) -> KernelBase :
73
93
return self
74
94
75
- @property
76
- def config (self ) -> KernelConfig :
77
- return self ._config
78
-
79
95
@property
80
96
def logger (self ) -> Logger :
81
97
return self ._log
@@ -248,6 +264,235 @@ def import_skill(
248
264
249
265
return skill
250
266
267
+ def get_ai_service (
268
+ self , type : Type [T ], service_id : Optional [str ] = None
269
+ ) -> Callable [["KernelBase" ], T ]:
270
+ matching_type = {}
271
+ if type == TextCompletionClientBase :
272
+ service_id = service_id or self ._default_text_completion_service
273
+ matching_type = self ._text_completion_services
274
+ elif type == ChatCompletionClientBase :
275
+ service_id = service_id or self ._default_chat_service
276
+ matching_type = self ._chat_services
277
+ elif type == EmbeddingGeneratorBase :
278
+ service_id = service_id or self ._default_text_embedding_generation_service
279
+ matching_type = self ._text_embedding_generation_services
280
+ else :
281
+ raise ValueError (f"Unknown AI service type: { type .__name__ } " )
282
+
283
+ if service_id not in matching_type :
284
+ raise ValueError (
285
+ f"{ type .__name__ } service with service_id '{ service_id } ' not found"
286
+ )
287
+
288
+ return matching_type [service_id ]
289
+
290
+ def all_text_completion_services (self ) -> List [str ]:
291
+ return list (self ._text_completion_services .keys ())
292
+
293
+ def all_chat_services (self ) -> List [str ]:
294
+ return list (self ._chat_services .keys ())
295
+
296
+ def all_text_embedding_generation_services (self ) -> List [str ]:
297
+ return list (self ._text_embedding_generation_services .keys ())
298
+
299
+ def add_text_completion_service (
300
+ self ,
301
+ service_id : str ,
302
+ service : Union [
303
+ TextCompletionClientBase , Callable [["KernelBase" ], TextCompletionClientBase ]
304
+ ],
305
+ overwrite : bool = True ,
306
+ ) -> "Kernel" :
307
+ if not service_id :
308
+ raise ValueError ("service_id must be a non-empty string" )
309
+ if not overwrite and service_id in self ._text_completion_services :
310
+ raise ValueError (
311
+ f"Text service with service_id '{ service_id } ' already exists"
312
+ )
313
+
314
+ self ._text_completion_services [service_id ] = (
315
+ service if isinstance (service , Callable ) else lambda _ : service
316
+ )
317
+ if self ._default_text_completion_service is None :
318
+ self ._default_text_completion_service = service_id
319
+
320
+ return self
321
+
322
+ def add_chat_service (
323
+ self ,
324
+ service_id : str ,
325
+ service : Union [
326
+ ChatCompletionClientBase , Callable [["KernelBase" ], ChatCompletionClientBase ]
327
+ ],
328
+ overwrite : bool = True ,
329
+ ) -> "Kernel" :
330
+ if not service_id :
331
+ raise ValueError ("service_id must be a non-empty string" )
332
+ if not overwrite and service_id in self ._chat_services :
333
+ raise ValueError (
334
+ f"Chat service with service_id '{ service_id } ' already exists"
335
+ )
336
+
337
+ self ._chat_services [service_id ] = (
338
+ service if isinstance (service , Callable ) else lambda _ : service
339
+ )
340
+ if self ._default_chat_service is None :
341
+ self ._default_chat_service = service_id
342
+
343
+ if isinstance (service , TextCompletionClientBase ):
344
+ self .add_text_completion_service (service_id , service )
345
+ if self ._default_text_completion_service is None :
346
+ self ._default_text_completion_service = service_id
347
+
348
+ return self
349
+
350
+ def add_text_embedding_generation_service (
351
+ self ,
352
+ service_id : str ,
353
+ service : Union [
354
+ EmbeddingGeneratorBase , Callable [["KernelBase" ], EmbeddingGeneratorBase ]
355
+ ],
356
+ overwrite : bool = False ,
357
+ ) -> "Kernel" :
358
+ if not service_id :
359
+ raise ValueError ("service_id must be a non-empty string" )
360
+ if not overwrite and service_id in self ._text_embedding_generation_services :
361
+ raise ValueError (
362
+ f"Embedding service with service_id '{ service_id } ' already exists"
363
+ )
364
+
365
+ self ._text_embedding_generation_services [service_id ] = (
366
+ service if isinstance (service , Callable ) else lambda _ : service
367
+ )
368
+ if self ._default_text_embedding_generation_service is None :
369
+ self ._default_text_embedding_generation_service = service_id
370
+
371
+ return self
372
+
373
+ def set_default_text_completion_service (self , service_id : str ) -> "Kernel" :
374
+ if service_id not in self ._text_completion_services :
375
+ raise ValueError (
376
+ f"AI service with service_id '{ service_id } ' does not exist"
377
+ )
378
+
379
+ self ._default_text_completion_service = service_id
380
+ return self
381
+
382
+ def set_default_chat_service (self , service_id : str ) -> "Kernel" :
383
+ if service_id not in self ._chat_services :
384
+ raise ValueError (
385
+ f"AI service with service_id '{ service_id } ' does not exist"
386
+ )
387
+
388
+ self ._default_chat_service = service_id
389
+ return self
390
+
391
+ def set_default_text_embedding_generation_service (
392
+ self , service_id : str
393
+ ) -> "Kernel" :
394
+ if service_id not in self ._text_embedding_generation_services :
395
+ raise ValueError (
396
+ f"AI service with service_id '{ service_id } ' does not exist"
397
+ )
398
+
399
+ self ._default_text_embedding_generation_service = service_id
400
+ return self
401
+
402
+ def get_text_completion_service_service_id (
403
+ self , service_id : Optional [str ] = None
404
+ ) -> str :
405
+ if service_id is None or service_id not in self ._text_completion_services :
406
+ if self ._default_text_completion_service is None :
407
+ raise ValueError ("No default text service is set" )
408
+ return self ._default_text_completion_service
409
+
410
+ return service_id
411
+
412
+ def get_chat_service_service_id (self , service_id : Optional [str ] = None ) -> str :
413
+ if service_id is None or service_id not in self ._chat_services :
414
+ if self ._default_chat_service is None :
415
+ raise ValueError ("No default chat service is set" )
416
+ return self ._default_chat_service
417
+
418
+ return service_id
419
+
420
+ def get_text_embedding_generation_service_id (
421
+ self , service_id : Optional [str ] = None
422
+ ) -> str :
423
+ if (
424
+ service_id is None
425
+ or service_id not in self ._text_embedding_generation_services
426
+ ):
427
+ if self ._default_text_embedding_generation_service is None :
428
+ raise ValueError ("No default embedding service is set" )
429
+ return self ._default_text_embedding_generation_service
430
+
431
+ return service_id
432
+
433
+ def remove_text_completion_service (self , service_id : str ) -> "Kernel" :
434
+ if service_id not in self ._text_completion_services :
435
+ raise ValueError (
436
+ f"AI service with service_id '{ service_id } ' does not exist"
437
+ )
438
+
439
+ del self ._text_completion_services [service_id ]
440
+ if self ._default_text_completion_service == service_id :
441
+ self ._default_text_completion_service = next (
442
+ iter (self ._text_completion_services ), None
443
+ )
444
+ return self
445
+
446
+ def remove_chat_service (self , service_id : str ) -> "Kernel" :
447
+ if service_id not in self ._chat_services :
448
+ raise ValueError (
449
+ f"AI service with service_id '{ service_id } ' does not exist"
450
+ )
451
+
452
+ del self ._chat_services [service_id ]
453
+ if self ._default_chat_service == service_id :
454
+ self ._default_chat_service = next (iter (self ._chat_services ), None )
455
+ return self
456
+
457
+ def remove_text_embedding_generation_service (self , service_id : str ) -> "Kernel" :
458
+ if service_id not in self ._text_embedding_generation_services :
459
+ raise ValueError (
460
+ f"AI service with service_id '{ service_id } ' does not exist"
461
+ )
462
+
463
+ del self ._text_embedding_generation_services [service_id ]
464
+ if self ._default_text_embedding_generation_service == service_id :
465
+ self ._default_text_embedding_generation_service = next (
466
+ iter (self ._text_embedding_generation_services ), None
467
+ )
468
+ return self
469
+
470
+ def clear_all_text_completion_services (self ) -> "Kernel" :
471
+ self ._text_completion_services = {}
472
+ self ._default_text_completion_service = None
473
+ return self
474
+
475
+ def clear_all_chat_services (self ) -> "Kernel" :
476
+ self ._chat_services = {}
477
+ self ._default_chat_service = None
478
+ return self
479
+
480
+ def clear_all_text_embedding_generation_services (self ) -> "Kernel" :
481
+ self ._text_embedding_generation_services = {}
482
+ self ._default_text_embedding_generation_service = None
483
+ return self
484
+
485
+ def clear_all_services (self ) -> "Kernel" :
486
+ self ._text_completion_services = {}
487
+ self ._chat_services = {}
488
+ self ._text_embedding_generation_services = {}
489
+
490
+ self ._default_text_completion_service = None
491
+ self ._default_chat_service = None
492
+ self ._default_text_embedding_generation_service = None
493
+
494
+ return self
495
+
251
496
def _create_semantic_function (
252
497
self ,
253
498
skill_name : str ,
@@ -274,7 +519,7 @@ def _create_semantic_function(
274
519
function .set_default_skill_collection (self .skills )
275
520
276
521
if function_config .has_chat_prompt :
277
- service = self ._config . get_ai_service (
522
+ service = self .get_ai_service (
278
523
ChatCompletionClientBase ,
279
524
function_config .prompt_template_config .default_services [0 ]
280
525
if len (function_config .prompt_template_config .default_services ) > 0
@@ -297,7 +542,7 @@ def _create_semantic_function(
297
542
298
543
function .set_chat_service (lambda : service (self ))
299
544
else :
300
- service = self ._config . get_ai_service (
545
+ service = self .get_ai_service (
301
546
TextCompletionClientBase ,
302
547
function_config .prompt_template_config .default_services [0 ]
303
548
if len (function_config .prompt_template_config .default_services ) > 0
0 commit comments