sunholo 0.104.6__py3-none-any.whl → 0.105.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ from collections import deque
12
12
  try:
13
13
  import google.generativeai as genai
14
14
  import proto
15
- from google.generativeai.types import RequestOptions
15
+ from google.generativeai.types import RequestOptions, GenerateContentResponse
16
16
  from google.api_core import retry
17
17
  from google.generativeai import ChatSession
18
18
  from google.api_core.exceptions import RetryError
@@ -60,7 +60,7 @@ class GenAIFunctionProcessor:
60
60
  ```
61
61
  """
62
62
 
63
- def __init__(self, config: ConfigManager=None, model_name=None):
63
+ def __init__(self, config: ConfigManager=None, model_name=None, trace=None, parent_observation_id=None):
64
64
  """
65
65
  Initializes the GenAIFunctionProcessor with the given configuration.
66
66
 
@@ -84,6 +84,9 @@ class GenAIFunctionProcessor:
84
84
  elif model_name:
85
85
  self.model_name = model_name
86
86
 
87
+ self.trace = trace
88
+ self.parent_observation_id = parent_observation_id
89
+
87
90
  self.last_api_requests_and_responses = []
88
91
  self._validate_functions()
89
92
 
@@ -430,6 +433,12 @@ class GenAIFunctionProcessor:
430
433
  # Initialize token queue to ensure sequential processing
431
434
  token_queue = deque()
432
435
 
436
+ span = self.trace.span(
437
+ name=f"GenAIFunctionProcesser_{self.__class__.__name__}",
438
+ parent_observation_id=self.parent_observation_id,
439
+ input = {'content': content},
440
+ ) if self.trace else None
441
+
433
442
  while guardrail < guardrail_max:
434
443
 
435
444
  token_queue.append(f"\n----Loop [{guardrail}] Start------\nFunctions: {list(self.funcs.keys())}\n")
@@ -441,11 +450,23 @@ class GenAIFunctionProcessor:
441
450
 
442
451
  log.info(f"== Start input content for loop [{guardrail}]\n ## Content: {content_parse}")
443
452
  this_text = "" # reset for this loop
444
- response = []
453
+ response = None
454
+ loop_span = span.span(
455
+ name=f"loop_{guardrail}",
456
+ model=self.model_name,
457
+ input = {'content': content},
458
+ ) if span else None
445
459
 
446
460
  try:
447
461
  token_queue.append("\n= Calling Agent =\n")
448
- response = chat.send_message(content, stream=True, request_options=RequestOptions(
462
+
463
+ gen = loop_span.generation(
464
+ name=f"loop_{guardrail}",
465
+ model=self.model_name,
466
+ input = {'content': content},
467
+ ) if loop_span else None
468
+
469
+ response: GenerateContentResponse = chat.send_message(content, stream=True, request_options=RequestOptions(
449
470
  retry=retry.Retry(
450
471
  initial=10,
451
472
  multiplier=2,
@@ -465,19 +486,23 @@ class GenAIFunctionProcessor:
465
486
  token_queue.append(msg)
466
487
  break
467
488
 
468
- loop_metadata = response.usage_metadata
469
- if loop_metadata:
470
- usage_metadata = {
471
- "prompt_token_count": usage_metadata["prompt_token_count"] + (loop_metadata.prompt_token_count or 0),
472
- "candidates_token_count": usage_metadata["candidates_token_count"] + (loop_metadata.candidates_token_count or 0),
473
- "total_token_count": usage_metadata["total_token_count"] + (loop_metadata.total_token_count or 0),
474
- }
475
- token_queue.append((
476
- "\n-- Agent response -- "
477
- f"Loop tokens: [{loop_metadata.prompt_token_count}]/[{usage_metadata['prompt_token_count']}] "
478
- f"Session tokens: [{loop_metadata.total_token_count}]/[{usage_metadata['total_token_count']}] \n"
479
- ))
480
- loop_metadata = None
489
+ if response:
490
+ loop_metadata = response.usage_metadata
491
+ if loop_metadata:
492
+ usage_metadata = {
493
+ "prompt_token_count": usage_metadata["prompt_token_count"] + (loop_metadata.prompt_token_count or 0),
494
+ "candidates_token_count": usage_metadata["candidates_token_count"] + (loop_metadata.candidates_token_count or 0),
495
+ "total_token_count": usage_metadata["total_token_count"] + (loop_metadata.total_token_count or 0),
496
+ }
497
+ token_queue.append((
498
+ "\n-- Agent response -- "
499
+ f"Loop tokens: [{loop_metadata.prompt_token_count}]/[{usage_metadata['prompt_token_count']}] "
500
+ f"Session tokens: [{loop_metadata.total_token_count}]/[{usage_metadata['total_token_count']}] \n"
501
+ ))
502
+ loop_metadata = None
503
+ gen.end(output=dict(response)) if gen else None
504
+ else:
505
+ gen.end(output="No response received") if gen else None
481
506
 
482
507
  for chunk in response:
483
508
  if not chunk:
@@ -494,7 +519,7 @@ class GenAIFunctionProcessor:
494
519
 
495
520
  except ValueError as err:
496
521
  token_queue.append(f"{str(err)} for {chunk=}")
497
-
522
+ fn_span = loop_span.span(name="function_execution", input=response) if loop_span else None
498
523
  try:
499
524
  executed_responses = self.process_funcs(response)
500
525
  except Exception as err:
@@ -503,9 +528,11 @@ class GenAIFunctionProcessor:
503
528
  token_queue.append(f"{str(err)} for {response=}")
504
529
 
505
530
  log.info(f"[{guardrail}] {executed_responses=}")
531
+ fn_span.end(output=executed_responses) if fn_span else None
506
532
 
507
533
  if executed_responses:
508
534
  token_queue.append("\n-- Agent Actions:\n")
535
+ fn_exec = loop_span.span(name="function_actions", input=executed_responses) if loop_span else None
509
536
  for executed_response in executed_responses:
510
537
  token = ""
511
538
  fn = executed_response.function_response.name
@@ -521,6 +548,7 @@ class GenAIFunctionProcessor:
521
548
  callback.on_llm_new_token(token=token)
522
549
 
523
550
  log.info(f"{fn_log} created a result={type(fn_result)=}")
551
+ fn_exec_one = fn_exec.span(name=fn_log, input=fn_result) if fn_exec else None
524
552
 
525
553
  fn_result_json = None
526
554
  # Convert MapComposite to a standard Python dictionary
@@ -573,11 +601,15 @@ class GenAIFunctionProcessor:
573
601
 
574
602
  this_text += token
575
603
  token_queue.append(token)
604
+ fn_exec_one.end(output=token) if fn_exec_one else None
605
+
576
606
  else:
577
607
  token = "\nNo function executions were found\n"
578
608
  token_queue.append(token)
579
609
  this_text += token
580
610
 
611
+ fn_exec.end(output=this_text) if fn_exec else None
612
+
581
613
  if this_text:
582
614
  content.append(f"Agent: {this_text}")
583
615
  # if text includes gs:// try to download it
@@ -594,6 +626,7 @@ class GenAIFunctionProcessor:
594
626
  content.append(f"Agent: No response was found for loop [{guardrail}]")
595
627
 
596
628
  token_queue.append(f"\n----Loop [{guardrail}] End------\n{usage_metadata}\n----------------------")
629
+ loop_span.end(output=content, metadata=loop_metadata) if loop_span else None
597
630
 
598
631
  go_on_check = self.check_function_result("decide_to_go_on", {"go_on": False})
599
632
  if go_on_check:
@@ -616,6 +649,7 @@ class GenAIFunctionProcessor:
616
649
  usage_metadata["functions_called"] = functions_called
617
650
 
618
651
  big_text = "\n".join(big_result[-loop_return:])
652
+ span.end(output=big_text, metadata=usage_metadata) if span else None
619
653
 
620
654
  return big_text, usage_metadata
621
655
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.104.6
3
+ Version: 0.105.1
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Home-page: https://github.com/sunholo-data/sunholo-py
6
- Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.104.6.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.105.1.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -88,7 +88,7 @@ sunholo/gcs/metadata.py,sha256=oQLcXi4brsZ74aegWyC1JZmhlaEV270HS5_UWtAYYWE,898
88
88
  sunholo/genai/__init__.py,sha256=dBl6IA3-Fx6-Vx81r0XqxHlUq6WeW1iDX188dpChu8s,115
89
89
  sunholo/genai/images.py,sha256=EyjsDqt6XQw99pZUQamomCpMOoIah9bp3XY94WPU7Ms,1678
90
90
  sunholo/genai/init.py,sha256=yG8E67TduFCTQPELo83OJuWfjwTnGZsyACospahyEaY,687
91
- sunholo/genai/process_funcs_cls.py,sha256=6NZiYd9VWEzRN_-25PvOpBnQcfuJfWMuqi2hgAYm9ls,29530
91
+ sunholo/genai/process_funcs_cls.py,sha256=c3pNWj8jWahMEwIbejm9euBr31WW0z50H5CPr9FW7cY,31310
92
92
  sunholo/genai/safety.py,sha256=mkFDO_BeEgiKjQd9o2I4UxB6XI7a9U-oOFjZ8LGRUC4,1238
93
93
  sunholo/invoke/__init__.py,sha256=o1RhwBGOtVK0MIdD55fAIMCkJsxTksi8GD5uoqVKI-8,184
94
94
  sunholo/invoke/async_class.py,sha256=G8vD2H94fpBc37mSJSQODEKJ67P2mPQEHabtDaLOvxE,8033
@@ -147,9 +147,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
147
147
  sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
148
148
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
149
149
  sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
150
- sunholo-0.104.6.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
151
- sunholo-0.104.6.dist-info/METADATA,sha256=kOR4eTd1sEjgHhwLIy6EK1KihYG3aMGKyG3c2N029K4,8312
152
- sunholo-0.104.6.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
153
- sunholo-0.104.6.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
154
- sunholo-0.104.6.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
155
- sunholo-0.104.6.dist-info/RECORD,,
150
+ sunholo-0.105.1.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
151
+ sunholo-0.105.1.dist-info/METADATA,sha256=XxAhxZcKvX8_GXcUpvePkoRnEIuCCcwATuCSk_gn3BA,8312
152
+ sunholo-0.105.1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
153
+ sunholo-0.105.1.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
154
+ sunholo-0.105.1.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
155
+ sunholo-0.105.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5