pbesa 4.0.5__tar.gz → 4.0.7__tar.gz

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.
Files changed (103) hide show
  1. {pbesa-4.0.5 → pbesa-4.0.7}/PKG-INFO +3 -2
  2. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/cognitive.py +326 -187
  3. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-39.pyc +0 -0
  4. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/util.py +0 -0
  5. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/mas.py +0 -0
  6. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/models.py +0 -0
  7. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/delegator.py +0 -0
  8. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/dialog.py +10 -2
  9. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/dispatcher_team.py +1 -1
  10. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/prompts.py +0 -0
  11. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/templates.py +0 -0
  12. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/worker.py +3 -3
  13. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa.egg-info/PKG-INFO +3 -2
  14. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa.egg-info/requires.txt +0 -0
  15. {pbesa-4.0.5 → pbesa-4.0.7}/setup.py +1 -1
  16. {pbesa-4.0.5 → pbesa-4.0.7}/.gitignore +0 -0
  17. {pbesa-4.0.5 → pbesa-4.0.7}/LICENSE +0 -0
  18. {pbesa-4.0.5 → pbesa-4.0.7}/LICENSE.txt +0 -0
  19. {pbesa-4.0.5 → pbesa-4.0.7}/MANIFEST +0 -0
  20. {pbesa-4.0.5 → pbesa-4.0.7}/README.md +0 -0
  21. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/db.sqlite3 +0 -0
  22. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__init__.py +0 -0
  23. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/__init__.cpython-36.pyc +0 -0
  24. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/pbesa.cpython-36.pyc +0 -0
  25. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/settings.cpython-36.pyc +0 -0
  26. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/urls.cpython-36.pyc +0 -0
  27. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/wsgi.cpython-36.pyc +0 -0
  28. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/asgi.py +0 -0
  29. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/pbesa.py +0 -0
  30. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/settings.py +0 -0
  31. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/urls.py +0 -0
  32. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/helloworld/wsgi.py +0 -0
  33. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/manage.py +0 -0
  34. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__init__.py +0 -0
  35. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/__init__.cpython-36.pyc +0 -0
  36. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/admin.cpython-36.pyc +0 -0
  37. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/apps.cpython-36.pyc +0 -0
  38. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/models.cpython-36.pyc +0 -0
  39. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/urls.cpython-36.pyc +0 -0
  40. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/views.cpython-36.pyc +0 -0
  41. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/admin.py +0 -0
  42. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/apps.py +0 -0
  43. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  44. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  45. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  46. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translatecontroller.py +0 -0
  47. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translatedelegate.py +0 -0
  48. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translateresponse.py +0 -0
  49. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  50. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  51. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/translatetask.py +0 -0
  52. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/workeragent.py +0 -0
  53. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/migrations/__init__.py +0 -0
  54. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/migrations/__pycache__/__init__.cpython-36.pyc +0 -0
  55. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/models.py +0 -0
  56. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/tests.py +0 -0
  57. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/urls.py +0 -0
  58. {pbesa-4.0.5 → pbesa-4.0.7}/examples/django/helloworld/translate/views.py +0 -0
  59. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/countercontroller.cpython-36.pyc +0 -0
  60. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/counterdelegate.cpython-36.pyc +0 -0
  61. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/counterresponse.cpython-36.pyc +0 -0
  62. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  63. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  64. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  65. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/countercontroller.py +0 -0
  66. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/counterdelegate.py +0 -0
  67. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/controller/counterresponse.py +0 -0
  68. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/counteragent.cpython-36.pyc +0 -0
  69. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/countertask.cpython-36.pyc +0 -0
  70. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  71. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  72. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/counteragent.py +0 -0
  73. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/mas/worker/countertask.py +0 -0
  74. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/remote_a.py +0 -0
  75. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/remote_b.py +0 -0
  76. {pbesa-4.0.5 → pbesa-4.0.7}/examples/remote/remote_c.py +0 -0
  77. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/__init__.py +0 -0
  78. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/__init__.py +0 -0
  79. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/adapter.py +0 -0
  80. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/agent.py +0 -0
  81. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/io/__init__.py +0 -0
  82. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/io/system_file.py +0 -0
  83. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/io/tcp_server.py +0 -0
  84. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/__init__.py +0 -0
  85. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-36.pyc +0 -0
  86. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-37.pyc +0 -0
  87. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-38.pyc +0 -0
  88. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/res/conf.json +0 -0
  89. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/kernel/world.py +0 -0
  90. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/__init__.py +0 -0
  91. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/adm_listener.py +0 -0
  92. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/adm_listener_handler.py +0 -0
  93. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/exceptions.py +0 -0
  94. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/remote_adm.py +0 -0
  95. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/remote/remote_adm_handler.py +0 -0
  96. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/__init__.py +0 -0
  97. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/collaborative_team.py +0 -0
  98. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/delegator_team.py +0 -0
  99. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa/social/selected_dispatcher_team.py +0 -0
  100. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa.egg-info/SOURCES.txt +0 -0
  101. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa.egg-info/dependency_links.txt +0 -0
  102. {pbesa-4.0.5 → pbesa-4.0.7}/pbesa.egg-info/top_level.txt +0 -0
  103. {pbesa-4.0.5 → pbesa-4.0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.5
3
+ Version: 4.0.7
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo==4.6.3
@@ -8,3 +8,4 @@ Requires-Dist: requests==2.32.3
8
8
  Requires-Dist: azure-ai-projects==1.0.0b6
9
9
  Requires-Dist: azure-ai-inference==1.0.0b9
10
10
  Requires-Dist: azure-identity==1.20.0
11
+ Dynamic: requires-dist
@@ -13,6 +13,7 @@
13
13
  # Define resources
14
14
  # --------------------------------------------------------
15
15
 
16
+ import uuid
16
17
  import json
17
18
  import logging
18
19
  import traceback
@@ -20,13 +21,16 @@ from pydantic import BaseModel
20
21
  from typing import List, Optional
21
22
  from abc import ABC, abstractmethod
22
23
  from pbesa.models import AIFoundry, AzureInference, GPTService, ServiceProvider
23
- from pbesa.social.dialog import DialogState, imprimir_grafo, recorrer_interacciones, extraer_diccionario_nodos, ActionNode, DeclarativeNode#, TerminalNode
24
+ from pbesa.social.dialog import (
25
+ DialogState, imprimir_grafo, recorrer_interacciones, extraer_diccionario_nodos,
26
+ ActionNode, DeclarativeNode, GotoNode) #, TerminalNode
24
27
  from pbesa.social.prompts import CLASSIFICATION_PROMPT, DERIVE_PROMPT, RECOVERY_PROMPT
25
28
  # --------------------------------------------------------
26
29
  # Define DTOs
27
30
  # --------------------------------------------------------
28
31
 
29
32
  class InteraccionDTO(BaseModel):
33
+ id: str
30
34
  tipo: str
31
35
  texto: str
32
36
  actor: str
@@ -38,6 +42,7 @@ def interaccion_serializer(interaccion):
38
42
  if isinstance(interaccion, list):
39
43
  return [interaccion_serializer(i) for i in interaccion]
40
44
  return {
45
+ "id": interaccion["id"] if "id" in interaccion and interaccion["id"] else str(uuid.uuid4()),
41
46
  "tipo": interaccion["tipo"],
42
47
  "texto": interaccion["texto"],
43
48
  "actor": interaccion["actor"],
@@ -468,6 +473,19 @@ class Dialog(ABC):
468
473
  self.__deep_limit = 3
469
474
  # Define knowledge
470
475
  self.knowledge = None
476
+ # Define point recovery
477
+ self.__recovery = {
478
+ "owner": "Web",
479
+ "team": "Web",
480
+ "performative": DialogState.START,
481
+ "counter": 0
482
+ }
483
+ # Define recovery message
484
+ self.RECOVERY_MSG = "Lo lamento, puedes darme más detalles o reformular"
485
+ # Define vertices list
486
+ self.__vertices = []
487
+ # Define visited nodes
488
+ self.__visited_nodes = 0
471
489
 
472
490
  def setup_world(self):
473
491
  """ Set up model method """
@@ -561,223 +579,344 @@ class Dialog(ABC):
561
579
  self.__work_memory = []
562
580
  # Set up model
563
581
  self.setup_world()
564
-
565
- def team_inquiry(self, team, data, operation, session_flag) -> str:
566
- canales = self.state['canales']
567
- canal = canales.get(team)
568
- dto = None
569
- if operation:
582
+ # Reset dialog state
583
+ self.__recovery = {
584
+ "owner": "Web",
585
+ "team": "Web",
586
+ "performative": DialogState.START,
587
+ "counter": 0
588
+ }
589
+
590
+ def notify(self, text):
591
+ try:
592
+ canales = self.state['canales']
593
+ canal = canales.get("Webhook")
594
+ session_id = self.state['session_id']
570
595
  dto = {
571
- "data": {
572
- 'text': data,
573
- 'operation': operation
574
- },
596
+ "session_id": session_id,
597
+ "text": text[0:100]
575
598
  }
576
- else:
577
- if session_flag:
578
- logging.info(f"Session flag: {session_flag}")
579
- logging.info(f"------------RESET--------------- {data}")
580
- self.reset()
581
- return data
582
-
599
+ response = canal.post("notify", dto)
600
+ if response['status']:
601
+ logging.info(f"Notificación enviada: {text}")
583
602
  else:
603
+ logging.warning(f"Notificación no enviada: {text}")
604
+ except Exception as e:
605
+ logging.error(f"Error al enviar notificación: {text}")
606
+ logging.erro(f"Error: {e}")
607
+
608
+ def team_inquiry(self, team, data, operation, session_flag) -> str:
609
+ try:
610
+ dto = None
611
+ canales = self.state['canales']
612
+ canal = canales.get(team)
613
+ if session_flag:
584
614
  dto = {
585
615
  "data": {
586
- 'text': data
616
+ 'text': data,
617
+ 'session_id': self.state['session_id'],
587
618
  },
588
619
  }
589
- response = canal.post(team.lower(), dto)
590
- if response['status']:
591
- return response['message']['response']
592
-
593
- logging.info(f"------------RESET---------------")
594
- self.reset()
595
- return "Lo lamento, no puedo responder en este momento"
596
-
597
- def get_text(self, mensaje) -> str:
598
- mensaje_limpio = mensaje.replace("<|im_start|>user<|im_sep|>", "").replace("<|im_start|>system<|im_sep|>", "")
599
- mensaje_limpio = mensaje_limpio.replace("<|im_start|>", "").replace("<|im_sep|>", "").replace("<|im_end|>", "")
600
- mensaje_limpio = mensaje_limpio.replace("[Usuario]: ", "").replace("[Sistema]: ", "")
601
- return mensaje_limpio.strip()
602
-
603
- def transition(self, owner, dialog_state, query, team_source=False) -> str:
604
- logging.info(f"Transition: {owner} -> {dialog_state}, Team: {team_source}, Query: {query}")
605
- text = ""
620
+ # Evia mensaje a los agentes remotos
621
+ logging.info('>>>> Call remote agent: team.\n')
622
+ response = canal.post(team.lower(), dto)
623
+ if response and not response['status']:
624
+ logging.error(f'No se pudo establecer la comunicación con el agente remoto')
625
+ return None
626
+ logging.info(f'>>>> Response: {response}')
627
+ return response['message']['response']
628
+ else:
629
+ if operation:
630
+ dto = {
631
+ "data": {
632
+ 'text': data,
633
+ 'operation': operation
634
+ },
635
+ }
636
+ else:
637
+ dto = {
638
+ "data": {
639
+ 'text': data
640
+ },
641
+ }
642
+ response = canal.post(team.lower(), dto)
643
+ if response['status']:
644
+ return response['message']['response']
645
+ else:
646
+ return None
647
+ logging.info("END: team_inquiry")
648
+ except Exception as e:
649
+ logging.error(f"Error al consultar al equipo: {team}")
650
+ return None
606
651
 
607
- # Verifica que exista la performativa
608
- if not dialog_state in self.__dfa:
609
- logging.warning(f"------------Performativa no existe---------------")
610
- self.reset()
652
+ def get_text(self, mensaje) -> str:
653
+ if mensaje:
654
+ mensaje_limpio = mensaje.replace("<|im_start|>user<|im_sep|>", "").replace("<|im_start|>system<|im_sep|>", "") \
655
+ .replace("<|im_start|>", "").replace("<|im_sep|>", "").replace("<|im_end|>", "") \
656
+ .replace("[Usuario]: ", "").replace("[Sistema]: ", "") \
657
+ .replace("<|user|>", "").replace("<|system|>", "")
658
+ return mensaje_limpio.strip()
659
+ else:
660
+ return ""
661
+
662
+ def recovery(self, query):
663
+ try:
611
664
  prompt = RECOVERY_PROMPT % query
612
- temp_work_memory = [{"role": "user", "content": query}]
665
+ temp_work_memory = [{"role": "user", "content": prompt}]
613
666
  res = self.__ai_service.generate(temp_work_memory)
614
667
  res = self.get_text(res)
615
- return "Web", DialogState.START, res, "Web"
668
+ if res and not res == "":
669
+ return self.__recovery['owner'], self.__recovery['performative'], res, self.__recovery['team']
670
+ else:
671
+ logging.info(f"------------RESET---------------")
672
+ logging.info(f"Recovery from: {self.__recovery['performative']}")
673
+ self.reset()
674
+ self.notify("STOP")
675
+ return "Web", DialogState.START, self.RECOVERY_MSG, "Web"
676
+ except Exception as e:
677
+ return self.RECOVERY_MSG
616
678
 
617
- node = self.__dfa[dialog_state]
618
- if not isinstance(node, list):
619
- node = node.children
620
-
621
- # Flujo de selección
622
- if node and len(node)> 1:
623
- logging.info(f"--> Más de una opción.")
624
- options = ""
625
- cont = 1
626
- for item in node:
627
- options += f"{cont}) {item.text}\n"
628
- cont += 1
629
- prompt = CLASSIFICATION_PROMPT % (query, options)
630
- logging.info(f"Query: {query},\n Options:\n{options}")
631
- self.__meta_work_memory.append({"role": "user", "content": prompt})
632
- text = self.__ai_service.generate(self.__meta_work_memory)
633
- logging.info(f"Thought: {text}")
634
- self.__meta_work_memory = []
635
- text = self.get_text(text)
636
- select_node = None
637
- for option in range(1, cont):
638
- if str(option) in text:
639
- select_node = node[option-1]
640
- logging.info(f"Select node: {select_node.text}")
641
- break
642
- if not select_node:
643
- logging.info("=> No se seleccionó ninguna opción")
644
- logging.info(f"=> Node: {node}")
645
- logging.info(f"=> len node: {len(node)}")
646
- select_node = node[0]
647
- logging.info(f"=> Selecciona el primer nodo: {select_node.text}")
648
- elif node and len(node) == 1:
649
- logging.info(f"--> Una opción.")
650
- select_node = node[0]
651
- else:
679
+ def transition(self, owner, dialog_state, query, team_source=False) -> str:
680
+ try:
681
+ res = ""
682
+ logging.info(f"TOPTQ: {owner} - {dialog_state} - {team_source} - {query}")
683
+ # Punto de restauración
684
+ counter = (self.__recovery['counter'] + 1) if self.__recovery['performative'] == dialog_state else self.__recovery['counter']
685
+ self.__recovery = {
686
+ "owner": owner,
687
+ "team": owner,
688
+ "performative": dialog_state,
689
+ "counter": counter
690
+ }
691
+ logging.info(f"Recovery attemps: {self.__recovery["counter"]}")
692
+ # Verifica si se ha alcanzado el límite de recuperación
693
+ if self.__recovery['counter'] <= 3 and self.__visited_nodes < 5:
694
+ self.notify("identificando concepto...")
695
+ #--------------------------
696
+ # Verifica que exista la performativa
697
+ if not dialog_state in self.__dfa:
698
+ self.notify("concepto no encontrado")
699
+ return self.recovery(query)
700
+ # Performativa encontrada
701
+ children = None
702
+ self.notify("concepto encontrado")
703
+ #--------------------------
704
+ # Obtiene los hijos del nodo
705
+ node = self.__dfa[dialog_state]
706
+ if not isinstance(node, list):
707
+ children = node.children
708
+ else:
709
+ # Es una lista de nodos
710
+ children = node
711
+ #--------------------------
712
+ # Flujo de selección
713
+ select_node = None
714
+ self.notify("flujo de seleccion...")
715
+ if children and len(children)> 1:
716
+ logging.info(f"--> Más de una opción.")
717
+ options = ""
718
+ cont = 1
719
+ for item in children:
720
+ options += f"{cont}) {item.text}\n"
721
+ cont += 1
722
+ prompt = CLASSIFICATION_PROMPT % (query, options)
723
+ logging.info(f"Query: {query},\n Options:\n{options}")
724
+ self.__meta_work_memory.append({"role": "user", "content": prompt})
725
+ res = self.__ai_service.generate(self.__meta_work_memory)
726
+ logging.info(f"Thought: {res}")
727
+ self.__meta_work_memory = []
728
+ res = self.get_text(res)
729
+ for option in range(1, cont):
730
+ if str(option) in res:
731
+ select_node = children[option-1]
732
+ logging.info(f"Select node: {select_node.text}")
733
+ break
734
+ if not select_node:
735
+ logging.info("=> No se seleccionó ninguna opción")
736
+ select_node = children[0]
737
+ logging.info(f"=> Selecciona el primer nodo: {select_node.text}")
738
+ elif children and len(children) == 1:
739
+ logging.info(f"--> Una opción.")
740
+ select_node = children[0]
741
+ else:
742
+ logging.info("???> Es un nodo terminal o iniciador")
743
+ return self.recovery(query)
744
+ #--------------------------
745
+ # Verifica si es un nodo
746
+ # que ya fue recorrido
747
+ if select_node.performative in self.__vertices:
748
+ logging.info(f"-> nodo ya recorrido: {select_node.text}")
749
+ self.__visited_nodes += 1
750
+ else:
751
+ logging.info(f"-> nodo no recorrido: {select_node.text}")
752
+ self.__visited_nodes = 0
753
+ # Maraca el nodo como visitado
754
+ self.__vertices.append(select_node.performative)
755
+ #---------------------------
756
+ # Verifica si el nodo es un
757
+ # nodo de salto
758
+ if isinstance(select_node, GotoNode):
759
+ logging.info(f"-> node de salto: {select_node.text}")
760
+ performative = select_node.text.replace("Salta a:", "").strip()
761
+ select_node = self.__dfa[performative]
762
+ logging.info(f"-> Salto: {select_node.text}, performativa: {select_node.performative}")
763
+ #---------------------------
764
+ # Efectua transicion
765
+ if select_node:
766
+ res = select_node.text
767
+ node = select_node.children[0]
768
+ logging.info(f"Flujo normal: {res}")
769
+ self.notify(res)
770
+ #---------------------------
771
+ # Verifica si el nuevo nodo
772
+ # es un nodo de salto
773
+ if isinstance(node, GotoNode):
774
+ logging.info(f"-> node de salto: {node.text}")
775
+ performative = node.text.replace("Salta a:", "").strip()
776
+ node = self.__dfa[performative]
777
+ logging.info(f"-> Salto: {node.text}, performativa: {node.performative}")
778
+ #---------------------------
779
+ # Actualiza la memoria de
780
+ # trabajo
781
+ if team_source:
782
+ self.__work_memory.append({"role": "user", "content": res})
783
+ else:
784
+ self.__work_memory.append({"role": "user", "content": query})
785
+ self.__work_memory.append({"role": "user", "content": res})
786
+ #---------------------------
787
+ # Efectua inferencia
788
+ new_owner, new_dialog_state, res, team = self.do_transition(owner, node, query)
789
+ res = self.get_text(res)
790
+ return new_owner, new_dialog_state, res, team
791
+ else:
792
+ logging.info(f"------------RESET---------------")
793
+ self.notify("STOP")
794
+ self.reset()
795
+ return "Web", DialogState.START, self.RECOVERY_MSG, "Web"
796
+ logging.info("END: do_transition")
797
+ except Exception as e:
798
+ traceback.print_exc()
652
799
  logging.info(f"------------RESET---------------")
653
800
  self.reset()
654
- logging.info(f"???> text: {text} es terminal")
655
- text = self.get_text(text)
656
- return owner, DialogState.START, text, owner
657
-
658
- # Flujo normal
659
- logging.info(f"Flujo normal: {select_node.text}")
660
- if team_source:
661
- self.__work_memory.append({"role": "user", "content": select_node.text})
662
- else:
663
- self.__work_memory.append({"role": "user", "content": query})
664
- self.__work_memory.append({"role": "user", "content": select_node.text})
665
- new_owner, new_dialog_state, text, team = self.do_transition(owner, select_node.children[0], query)
666
- text = self.get_text(text)
667
- return new_owner, new_dialog_state, text, team
801
+ self.notify("STOP")
802
+ return owner, DialogState.START, "Lo lamento, no puedo responder en este momento", owner
668
803
 
669
804
  def do_transition(self, owner, node, query) -> str:
670
805
  """ Generate method
671
806
  :return: str
672
- """
673
- if isinstance(node, DeclarativeNode):
674
- logging.info(f"D -> node: {node.text}")
675
- self.__work_memory.append({"role": "user", "content": node.text})
676
- elif isinstance(node, ActionNode):
677
-
678
- #------------------------------
679
- # Accion
680
- #------------------------------
681
-
682
- logging.info(f"-> node action: {node.action}")
683
- if node.tool and not node.tool == "Ninguno":
684
- logging.info(f"-> node tool: {node.tool}")
685
- self.__work_memory.append({"role": "user", "content": node.text})
686
- logging.info("-----")
687
- logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
688
- logging.info("-----")
689
- res = self.__ai_service.generate(self.__work_memory)
690
- logging.info(f"-> node tool: {res}")
691
- res = self.get_text(res)
692
- # Check if res is empty
693
- if not res or res == "":
694
- logging.info("1 -> res vacio")
695
- res = "Lo lamento, no puedo responder en este momento"
696
-
697
- logging.info(f"------------RESET---------------")
698
- self.reset()
699
-
700
- return owner, DialogState.START, res, owner
701
- logging.info(f"-> node tool: envia -> {res}")
702
- text = self.team_inquiry(node.team, res, node.tool, False)
703
- else:
807
+ """
808
+ try:
809
+ if isinstance(node, ActionNode):
810
+ self.notify("realizando acción...")
704
811
  #------------------------------
705
- # Lllamada
812
+ # Accion
706
813
  #------------------------------
707
- logging.info(f"-> node team: {node.team}")
708
- # Verifica si el nodo es termianl ya que significa
709
- # que el dialogo cambia de agente
710
- if node.is_terminal:
711
- logging.info(f"-> node team -> es terminal -> {node.text}")
814
+ logging.info(f"-> node action: {node.action}")
815
+ if node.tool and not node.tool == "Ninguno":
816
+ self.notify("aplicando herramienta...")
817
+ logging.info(f"-> node tool: {node.tool}")
712
818
  self.__work_memory.append({"role": "user", "content": node.text})
713
819
  logging.info("-----")
714
820
  logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
715
- logging.info("-----")
821
+ logging.info("-----")
716
822
  res = self.__ai_service.generate(self.__work_memory)
823
+ logging.info(f"-> node tool: {res}")
717
824
  res = self.get_text(res)
718
- self.__work_memory.append({"role": "system", "content": res})
719
825
  # Check if res is empty
720
826
  if not res or res == "":
721
- logging.info("2 -> res vacio")
722
- res = "Lo lamento, no puedo responder en este momento"
723
- logging.info(f"------------RESET---------------")
724
- self.reset()
725
- return owner, DialogState.START, res, owner
726
- logging.info(f"-> node team -> envia: {res}")
727
- text = self.team_inquiry(node.team, res, None, True)
728
- return node.team, DialogState.START, res, node.team
827
+ self.notify("no pude hacer uso de la herramienta")
828
+ return self.recovery(query)
829
+ logging.info(f"-> node tool: envia -> {res}")
830
+ res = self.team_inquiry(node.team, res, node.tool, False)
729
831
  else:
730
- logging.info("-> node team -> continua")
731
- self.__work_memory.append({"role": "user", "content": node.text})
732
- logging.info(f"-> node team -> envia: {query}")
733
- text = self.team_inquiry(node.team, query, node.tool, False)
734
- logging.info(f"-> node team -> text: {text}")
735
- if text:
736
- logging.info(f"-> Adicion WM node team -> text: {text}")
737
- self.__work_memory.append({"role": "system", "content": text})
738
- self.__deep_count += 1
739
- if self.__deep_count < self.__deep_limit:
740
- return self.transition(owner, node.performative, text, True)
832
+ self.notify("realizando llamada...")
833
+ #------------------------------
834
+ # Lllamada
835
+ #------------------------------
836
+ logging.info(f"-> node team: {node.team}")
837
+ # Verifica si el nodo es termianl ya que significa
838
+ # que el dialogo cambia de agente
839
+ if node.is_terminal:
840
+ logging.info(f"-> node team -> es terminal -> {node.text}")
841
+ self.__work_memory.append({"role": "user", "content": node.text})
842
+ logging.info("-----")
843
+ logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
844
+ logging.info("-----")
845
+ res = self.__ai_service.generate(self.__work_memory)
846
+ res = self.get_text(res)
847
+ self.__work_memory.append({"role": "system", "content": res})
848
+ # Check if res is empty
849
+ if not res or res == "":
850
+ self.notify(f"no pude contactar al agente: {node.team}")
851
+ return self.recovery(query)
852
+ self.notify(f"le envio al agente {node.team}: {res}")
853
+ logging.info(f"-> node team -> envia: {res}")
854
+ res = self.team_inquiry(node.team, res, None, True)
855
+ if res and not res == "ERROR" and not res == "":
856
+ logging.info(f"------------RESET---------------")
857
+ self.reset()
858
+ self.notify("STOP")
859
+ return node.team, DialogState.START, res, node.team
860
+ else:
861
+ return self.recovery(query)
862
+ else:
863
+ logging.info("-> node team -> continua")
864
+ self.__work_memory.append({"role": "user", "content": node.text})
865
+ logging.info(f"-> node team -> envia: {query}")
866
+ res = self.team_inquiry(node.team, query, node.tool, False)
867
+ self.notify(f"continuando con díalogo")
868
+ # Adiciona el texto al work memory
869
+ if res and not res == "ERROR" and not res == "":
870
+ logging.info(f"-> Adicion WM node team -> text: {res}")
871
+ self.__work_memory.append({"role": "system", "content": res})
872
+ else:
873
+ return self.recovery(query)
874
+ logging.info("#########> Procesa respuesta del equipo en profundidad")
875
+ # Verifica si se alcanzó el límite de profundidad
876
+ self.__deep_count += 1
877
+ if self.__deep_count < self.__deep_limit:
878
+ self.notify("efectuando inferencia en profundidad")
879
+ return self.transition(owner, node.performative, res, True)
880
+ else:
881
+ self.notify(f"se alcanzó el límite de profundidad: {self.__deep_count}")
882
+ self.__deep_count = 0
883
+ logging.info("-> node team -> deep limit")
884
+ logging.info(f"------------RESET---------------")
885
+ self.notify("STOP")
886
+ self.reset()
887
+ return "Web", DialogState.START, self.RECOVERY_MSG, "Web"
741
888
  else:
742
- self.__deep_count = 0
743
- logging.info("-> node team -> deep limit")
744
-
745
- logging.info(f"------------RESET---------------")
746
- self.reset()
747
-
748
- return "Web", DialogState.START, "Lo lamento me he perdido, ¿podrías repetir la pregunta?"
749
- else:
750
- logging.info(f"!!!!!!!!!!!!!!!!!!!!!!!> Otro tipo de nodo: {node.text}")
751
-
752
- logging.info(f"=> !!!!: {query}")
753
- logging.info("-----")
754
- logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
755
- logging.info("-----")
756
- res = self.__ai_service.generate(self.__work_memory)
757
- logging.info(f"=> res: {res}")
758
- res = self.get_text(res)
759
- self.__work_memory.append({"role": "system", "content": res})
760
- # Check if res is empty
761
- if not res or res == "":
762
- logging.info("3 -> res vacio")
763
-
889
+ self.notify("efectuando inferencia...")
890
+ logging.info(f"D -> node: {node.text}")
891
+ self.__work_memory.append({"role": "user", "content": node.text})
892
+ logging.info(f"=> !!!!: {query}")
893
+ logging.info("-----")
894
+ logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
895
+ logging.info("-----")
896
+ res = self.__ai_service.generate(self.__work_memory)
897
+ res = self.get_text(res)
898
+ self.__work_memory.append({"role": "system", "content": res})
899
+ # Check if res is empty
900
+ if not res or res == "":
901
+ return self.recovery(query)
902
+ logging.info(f"=> Thought DEEP: {res}")
903
+ self.notify(f"Realizando inferencia: {res}")
904
+ new_dialog_state = node.performative
905
+ if not node.is_terminal:
906
+ self.notify(f"continuando díalogo de inferencia")
907
+ return owner, new_dialog_state, res, owner
908
+ self.notify(f"finalizando díalogo de inferencia")
909
+ logging.info(f"Tipe node: {type(node)}")
910
+ logging.info(f"$$$> new_owner: {owner} new_dialog_state: {new_dialog_state}")
911
+ self.notify("STOP")
912
+ return owner, new_dialog_state, res, owner
913
+ logging.info("END: do_transition")
914
+ except Exception as e:
915
+ traceback.print_exc()
764
916
  logging.info(f"------------RESET---------------")
765
917
  self.reset()
766
-
767
- res = "Lo lamento, no puedo responder en este momento"
768
- return owner, DialogState.START, res, owner
769
-
770
- logging.info(f"=> Thought DEEP: {res}")
771
-
772
- new_dialog_state = node.performative
773
- if not node.is_terminal:
774
- logging.info(f"=> new_owner: {owner} new_dialog_state: {new_dialog_state}")
775
- return owner, new_dialog_state, res, owner
776
-
777
- logging.info(f"Tipe node: {type(node)}")
778
-
779
- logging.info(f"$$$> new_owner: {owner} new_dialog_state: {new_dialog_state}")
780
- return owner, new_dialog_state, res, owner
918
+ self.notify("STOP")
919
+ return owner, DialogState.START, "Lo lamento, no puedo responder en este momento", owner
781
920
 
782
921
  def set_knowledge(self, knowledge) -> str:
783
922
  """ Set knowledge method
File without changes
File without changes
File without changes
File without changes
@@ -37,7 +37,7 @@ class DialogState:
37
37
  class Node:
38
38
  def __init__(self, actor, performative, text=None, is_terminal=False):
39
39
  self.actor = actor
40
- self.performative = performative # Se asigna el ID del objeto (en str)
40
+ self.performative = performative
41
41
  self.text = text
42
42
  self.is_terminal = is_terminal
43
43
  self.children = []
@@ -57,6 +57,10 @@ class ResponseNode(Node):
57
57
  def __init__(self, actor, performative, text, is_terminal=False):
58
58
  super().__init__(actor, performative=performative, text=text, is_terminal=is_terminal)
59
59
 
60
+ class GotoNode(Node):
61
+ def __init__(self, actor, performative, text, is_terminal=False):
62
+ super().__init__(actor, performative=performative, text=text, is_terminal=is_terminal)
63
+
60
64
  #------------------------------------------
61
65
  # Define functions
62
66
  #------------------------------------------
@@ -125,7 +129,7 @@ def recorrer_interacciones(obj):
125
129
  # Si tiene la clave "tipo", creamos un nodo (según su valor) y procesamos sus hijos
126
130
  if "tipo" in obj:
127
131
  # Se usa el id del diccionario convertido a cadena para 'performative'
128
- current_id = str(id(obj))
132
+ current_id = obj["id"] if "id" in obj else str(id(obj))
129
133
  texto = obj.get("texto")
130
134
 
131
135
  # Procesamos los nodos hijos buscando en las claves "interacciones" y "Interacciones"
@@ -150,6 +154,8 @@ def recorrer_interacciones(obj):
150
154
  nuevo_nodo = ActionNode(actor=obj["actor"], performative=current_id, text=texto, action=tipo, team=obj["equipo"], tool=obj["herramienta"], is_terminal=is_terminal)
151
155
  elif tipo == "respuesta de equipo":
152
156
  nuevo_nodo = ResponseNode(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
157
+ elif tipo == "salta a":
158
+ nuevo_nodo = GotoNode(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
153
159
  else:
154
160
  nuevo_nodo = Node(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
155
161
 
@@ -168,8 +174,10 @@ def recorrer_interacciones(obj):
168
174
  nodos.extend(resultado)
169
175
  else:
170
176
  nodos.append(resultado)
177
+ # Devolvemos la lista de nodos encontrados
171
178
  return nodos if nodos else None
172
179
  else:
180
+ # Si no es ni lista ni diccionario, devolvemos None
173
181
  return None
174
182
  except Exception as e:
175
183
  print(f"Error al recorrer interacciones: {e}")
@@ -188,7 +188,7 @@ class DispatcherController(Agent):
188
188
  @param event: Event
189
189
  @param data: Data
190
190
  """
191
- from pbesa.kernel.system.adm import Adm
191
+ from ..mas import Adm
192
192
  for agent_id in self.__agent_list:
193
193
  Adm().send_event(agent_id, event, data)
194
194
 
File without changes
File without changes
@@ -57,18 +57,18 @@ class TimeoutAction(Action):
57
57
  """ Execute the action
58
58
  @param data: Event data
59
59
  """
60
- logging.info(f"[TimeoutAction][{self.agent.id}]: Execute {data}")
60
+ logging.debug(f"[TimeoutAction][{self.agent.id}]: Execute {data}")
61
61
  if data['command'] == 'start':
62
62
  if not self.agent.is_timeout():
63
63
  self.agent.set_timeout(True)
64
64
  self.__timer = Timer(data['time'], self.handler)
65
65
  self.__timer.start()
66
- logging.info(f"[TimeoutAction][{self.agent.id}]: Timer started")
66
+ logging.debug(f"[TimeoutAction][{self.agent.id}]: Timer started")
67
67
  else:
68
68
  if self.__timer:
69
69
  self.__timer.cancel()
70
70
  self.__timer = None
71
- logging.info(f"[TimeoutAction][{self.agent.id}]: Timer stopped")
71
+ logging.debug(f"[TimeoutAction][{self.agent.id}]: Timer stopped")
72
72
 
73
73
  # --------------------------------------------------------
74
74
  # Define Task Action
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.5
3
+ Version: 4.0.7
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo==4.6.3
@@ -8,3 +8,4 @@ Requires-Dist: requests==2.32.3
8
8
  Requires-Dist: azure-ai-projects==1.0.0b6
9
9
  Requires-Dist: azure-ai-inference==1.0.0b9
10
10
  Requires-Dist: azure-identity==1.20.0
11
+ Dynamic: requires-dist
File without changes
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name='pbesa',
7
- version='4.0.5',
7
+ version='4.0.7',
8
8
  packages=find_packages(),
9
9
  install_requires=[
10
10
  'pymongo==4.6.3',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes