besser-agentic-framework 4.4.2__tar.gz → 4.5.0__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 (216) hide show
  1. {besser_agentic_framework-4.4.2/besser_agentic_framework.egg-info → besser_agentic_framework-4.5.0}/PKG-INFO +3 -3
  2. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/agent.py +15 -2
  3. besser_agentic_framework-4.5.0/baf/core/gui/agent_gui.py +291 -0
  4. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/gui/gui_deserializer.py +40 -7
  5. besser_agentic_framework-4.5.0/baf/core/gui/gui_llm.py +118 -0
  6. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/gui/gui_schema.py +69 -8
  7. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/gui/gui_serializer.py +92 -42
  8. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/message.py +4 -4
  9. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/session.py +10 -0
  10. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/state.py +22 -2
  11. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/condition_functions.py +26 -0
  12. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/conditions.py +24 -1
  13. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/events/base_events.py +31 -0
  14. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/__init__.py +11 -0
  15. besser_agentic_framework-4.5.0/baf/nlp/llm/llm_ollama.py +193 -0
  16. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/payload.py +18 -7
  17. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/websocket_platform.py +52 -18
  18. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0/besser_agentic_framework.egg-info}/PKG-INFO +3 -3
  19. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/besser_agentic_framework.egg-info/SOURCES.txt +3 -0
  20. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/besser_agentic_framework.egg-info/requires.txt +2 -2
  21. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-torch.txt +1 -1
  22. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/setup.cfg +1 -1
  23. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/LICENSE +0 -0
  24. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/MANIFEST.in +0 -0
  25. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/README.md +0 -0
  26. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/__init__.py +0 -0
  27. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/__init__.py +0 -0
  28. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/entity/__init__.py +0 -0
  29. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/entity/entity.py +0 -0
  30. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/entity/entity_entry.py +0 -0
  31. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/file.py +0 -0
  32. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/gui/__init__.py +0 -0
  33. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/intent/__init__.py +0 -0
  34. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/intent/intent.py +0 -0
  35. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/intent/intent_parameter.py +0 -0
  36. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/processors/__init__.py +0 -0
  37. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/processors/audio_language_detection_processor.py +0 -0
  38. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/processors/language_detection_processor.py +0 -0
  39. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/processors/processor.py +0 -0
  40. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/processors/user_adaptation_processor.py +0 -0
  41. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/property.py +0 -0
  42. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/transition/__init__.py +0 -0
  43. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/transition/condition.py +0 -0
  44. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/transition/event.py +0 -0
  45. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/transition/transition.py +0 -0
  46. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/core/transition/transition_builder.py +0 -0
  47. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/__init__.py +0 -0
  48. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/db_handler.py +0 -0
  49. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_db.py +0 -0
  50. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/__init__.py +0 -0
  51. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/db_connection.py +0 -0
  52. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/flow_graph.py +0 -0
  53. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/home.py +0 -0
  54. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/intent_details.py +0 -0
  55. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/monitoring_ui.py +0 -0
  56. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/sidebar.py +0 -0
  57. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/table_overview.py +0 -0
  58. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/db/monitoring_ui/utils.py +0 -0
  59. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/exceptions/__init__.py +0 -0
  60. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/exceptions/exceptions.py +0 -0
  61. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/exceptions/logger.py +0 -0
  62. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/__init__.py +0 -0
  63. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/coroutine/__init__.py +0 -0
  64. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/coroutine/async_helpers.py +0 -0
  65. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/entity/__init__.py +0 -0
  66. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/entity/base_entities.py +0 -0
  67. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/intent/__init__.py +0 -0
  68. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/intent/intent_library.py +0 -0
  69. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/state/__init__.py +0 -0
  70. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/state/reasoning_state_library.py +0 -0
  71. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/state/state_library.py +0 -0
  72. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/tool/__init__.py +0 -0
  73. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/tool/task_tools.py +0 -0
  74. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/tool/workspace_tools.py +0 -0
  75. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/__init__.py +0 -0
  76. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/events/__init__.py +0 -0
  77. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/events/github_webhooks_events.py +0 -0
  78. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/library/transition/events/gitlab_webhooks_events.py +0 -0
  79. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/__init__.py +0 -0
  80. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/intent_classifier.py +0 -0
  81. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/intent_classifier_configuration.py +0 -0
  82. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/intent_classifier_prediction.py +0 -0
  83. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/llm_intent_classifier.py +0 -0
  84. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/simple_intent_classifier_pytorch.py +0 -0
  85. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/intent_classifier/simple_intent_classifier_tensorflow.py +0 -0
  86. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/__init__.py +0 -0
  87. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/llm.py +0 -0
  88. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/llm_huggingface.py +0 -0
  89. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/llm_huggingface_api.py +0 -0
  90. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/llm_openai_api.py +0 -0
  91. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/llm/llm_replicate_api.py +0 -0
  92. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/__init__.py +0 -0
  93. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/base/__init__.py +0 -0
  94. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/base/any.py +0 -0
  95. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/base/datetime.py +0 -0
  96. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/base/number.py +0 -0
  97. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/matched_parameter.py +0 -0
  98. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/ner.py +0 -0
  99. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/ner_prediction.py +0 -0
  100. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/ner/simple_ner.py +0 -0
  101. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/nlp_engine.py +0 -0
  102. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/preprocessing/__init__.py +0 -0
  103. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/preprocessing/pipelines.py +0 -0
  104. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/preprocessing/text_preprocessing.py +0 -0
  105. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/rag/__init__.py +0 -0
  106. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/rag/rag.py +0 -0
  107. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/__init__.py +0 -0
  108. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/api_speech2text.py +0 -0
  109. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/hf_speech2text.py +0 -0
  110. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/luxasr_speech2text.py +0 -0
  111. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/openai_speech2text.py +0 -0
  112. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/speech2text/speech2text.py +0 -0
  113. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/text2speech/__init__.py +0 -0
  114. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/text2speech/hf_text2speech.py +0 -0
  115. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/text2speech/openai_text2speech.py +0 -0
  116. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/text2speech/piper_text2speech.py +0 -0
  117. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/text2speech/text2speech.py +0 -0
  118. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/nlp/utils.py +0 -0
  119. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/__init__.py +0 -0
  120. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/__init__.py +0 -0
  121. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/a2a_platform.py +0 -0
  122. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/agent_card.py +0 -0
  123. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/agent_registry.py +0 -0
  124. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/client.py +0 -0
  125. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/error_handler.py +0 -0
  126. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/message_router.py +0 -0
  127. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/server.py +0 -0
  128. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/a2a/task_protocol.py +0 -0
  129. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/github/__init__.py +0 -0
  130. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/github/github_actions.py +0 -0
  131. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/github/github_objects.py +0 -0
  132. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/github/github_platform.py +0 -0
  133. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/gitlab/__init__.py +0 -0
  134. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/gitlab/gitlab_actions.py +0 -0
  135. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/gitlab/gitlab_objects.py +0 -0
  136. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/gitlab/gitlab_platform.py +0 -0
  137. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/platform.py +0 -0
  138. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/telegram/__init__.py +0 -0
  139. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/telegram/telegram_platform.py +0 -0
  140. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/__init__.py +0 -0
  141. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/__init__.py +0 -0
  142. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/audio_queue.py +0 -0
  143. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/chat.py +0 -0
  144. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/chat_interface_style.py +0 -0
  145. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/initialization.py +0 -0
  146. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/login.py +0 -0
  147. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/message_input.py +0 -0
  148. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/profile_selector.py +0 -0
  149. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/reasoning.py +0 -0
  150. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/session_management.py +0 -0
  151. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/sidebar.py +0 -0
  152. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/streamlit_ui.py +0 -0
  153. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/user_db.py +0 -0
  154. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/vars.py +0 -0
  155. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/platforms/websocket/streamlit_ui/websocket_callbacks.py +0 -0
  156. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/reasoning/__init__.py +0 -0
  157. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/reasoning/skill.py +0 -0
  158. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/reasoning/tool.py +0 -0
  159. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/reasoning/workspace.py +0 -0
  160. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/__init__.py +0 -0
  161. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/__init__.py +0 -0
  162. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/conftest.py +0 -0
  163. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_agent.py +0 -0
  164. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_intent_entity.py +0 -0
  165. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_message.py +0 -0
  166. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_processor.py +0 -0
  167. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_property.py +0 -0
  168. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_session.py +0 -0
  169. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_state.py +0 -0
  170. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_core_transition.py +0 -0
  171. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_library_events.py +0 -0
  172. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_nlp_configurations.py +0 -0
  173. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_nlp_engine.py +0 -0
  174. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_nlp_preprocessing.py +0 -0
  175. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_platforms.py +0 -0
  176. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/components/test_workflows.py +0 -0
  177. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/__init__.py +0 -0
  178. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/conftest.py +0 -0
  179. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_core.py +0 -0
  180. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_docs.py +0 -0
  181. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_extras.py +0 -0
  182. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_framework.py +0 -0
  183. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_llms.py +0 -0
  184. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_tensorflow.py +0 -0
  185. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/dependencies/test_torch.py +0 -0
  186. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/__init__.py +0 -0
  187. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/a2a_multiagent.py +0 -0
  188. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/api_speech2text_agent.py +0 -0
  189. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/github_agent.py +0 -0
  190. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/gitlab_agent.py +0 -0
  191. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/greetings_agent.py +0 -0
  192. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/llm_agent.py +0 -0
  193. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/multiagent/__init__.py +0 -0
  194. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/multiagent/coder_agent.py +0 -0
  195. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/multiagent/main_agent.py +0 -0
  196. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/multiagent/reviewer_agent.py +0 -0
  197. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/rag_agent.py +0 -0
  198. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/reasoning_agent.py +0 -0
  199. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/speech2speech_agent.py +0 -0
  200. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/speech2text_agent.py +0 -0
  201. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/stargazer_agent.py +0 -0
  202. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/telegram_agent.py +0 -0
  203. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/text2speech_agent.py +0 -0
  204. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/weather_agent.py +0 -0
  205. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/test/examples/web_crawl_agent.py +0 -0
  206. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/utils/__init__.py +0 -0
  207. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/baf/utils/web_crawl.py +0 -0
  208. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/besser_agentic_framework.egg-info/dependency_links.txt +0 -0
  209. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/besser_agentic_framework.egg-info/top_level.txt +0 -0
  210. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/pyproject.toml +0 -0
  211. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-core.txt +0 -0
  212. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-docs.txt +0 -0
  213. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-extras.txt +0 -0
  214. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-llms.txt +0 -0
  215. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/requirements/requirements-tensorflow.txt +0 -0
  216. {besser_agentic_framework-4.4.2 → besser_agentic_framework-4.5.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: besser-agentic-framework
3
- Version: 4.4.2
3
+ Version: 4.5.0
4
4
  Summary: BESSER Agentic Framework (BAF)
5
5
  Author: Luxembourg Institute of Science and Technology
6
6
  License: MIT
@@ -61,7 +61,7 @@ Provides-Extra: tensorflow
61
61
  Requires-Dist: keras==3.12.0; extra == "tensorflow"
62
62
  Requires-Dist: tensorflow-cpu==2.20.0; extra == "tensorflow"
63
63
  Provides-Extra: torch
64
- Requires-Dist: torch==2.6.0+cpu; extra == "torch"
64
+ Requires-Dist: torch==2.6.0; extra == "torch"
65
65
  Requires-Dist: scikit-learn>=1.7.0; extra == "torch"
66
66
  Provides-Extra: docs
67
67
  Requires-Dist: sphinx==7.2.3; extra == "docs"
@@ -91,7 +91,7 @@ Requires-Dist: replicate==0.23.1; extra == "all"
91
91
  Requires-Dist: transformers==4.53.0; extra == "all"
92
92
  Requires-Dist: keras==3.12.0; extra == "all"
93
93
  Requires-Dist: tensorflow-cpu==2.20.0; extra == "all"
94
- Requires-Dist: torch==2.6.0+cpu; extra == "all"
94
+ Requires-Dist: torch==2.6.0; extra == "all"
95
95
  Requires-Dist: scikit-learn>=1.7.0; extra == "all"
96
96
  Dynamic: license-file
97
97
  Dynamic: provides-extra
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
  from typing import Any, Callable, get_type_hints
10
10
 
11
11
  import yaml
12
-
12
+ from baf.core.gui.agent_gui import AgentGUI
13
13
  from baf.core.transition.event import Event
14
14
  from baf.core.message import Message, MessageType
15
15
  from baf.core.entity.entity import Entity
@@ -26,7 +26,7 @@ from baf.db.monitoring_db import MonitoringDB
26
26
  from baf.exceptions.exceptions import AgentNotTrainedError, DuplicatedEntityError, DuplicatedInitialStateError, \
27
27
  DuplicatedIntentError, DuplicatedStateError, InitialStateNotFound
28
28
  from baf.exceptions.logger import logger
29
- from baf.library.transition.events.base_events import ReceiveMessageEvent, ReceiveJSONEvent, ReceiveFileEvent
29
+ from baf.library.transition.events.base_events import ReceiveMessageEvent, ReceiveJSONEvent, ReceiveFileEvent, GUIEvent
30
30
  from baf.nlp.intent_classifier.intent_classifier_configuration import IntentClassifierConfiguration, \
31
31
  SimpleIntentClassifierConfiguration
32
32
  from baf.nlp.intent_classifier.intent_classifier_prediction import IntentClassifierPrediction
@@ -138,6 +138,7 @@ class Agent:
138
138
  """dict[str, Any]: The agent configuration parameters."""
139
139
  return self._config
140
140
 
141
+
141
142
  def load_properties(self, path: str) -> None:
142
143
  """Read a properties file and store its properties in the agent configuration.
143
144
 
@@ -818,6 +819,18 @@ class Agent:
818
819
  session.save_message(Message(t=t, content=event.message, is_user=True, timestamp=datetime.now()))
819
820
  if isinstance(event, ReceiveFileEvent):
820
821
  session.save_message(Message(t=MessageType.FILE, content=event.file.get_json_string(), is_user=True, timestamp=datetime.now()))
822
+ if isinstance(event, GUIEvent) and not event.is_broadcasted():
823
+ message_id = event.message_id
824
+ if message_id and message_id in session.gui_inputs:
825
+ action = event.event_data.get('action')
826
+ value = event.event_data.get('value')
827
+ if action == 'onChange':
828
+ field_name = event.event_data.get('name')
829
+ if field_name is not None:
830
+ session.gui_inputs[message_id][field_name] = value
831
+ elif action == 'onSubmit':
832
+ if isinstance(value, dict):
833
+ session.gui_inputs[message_id].update(value)
821
834
 
822
835
  logger.info(f'Received event: {event.log()}')
823
836
 
@@ -0,0 +1,291 @@
1
+ """AgentGUI: BAF's interface to besser's GUIModel, with optional-dependency handling."""
2
+ from __future__ import annotations
3
+
4
+ import copy
5
+ import uuid
6
+
7
+ from baf.exceptions.logger import logger
8
+
9
+ try:
10
+ from besser.BUML.metamodel.gui.graphical_ui import GUIModel, ViewContainer
11
+ _BESSER_AVAILABLE = True
12
+ except ImportError:
13
+ logger.warning(
14
+ "besser GUI dependencies could not be imported. GUI features will be unavailable. "
15
+ "Install with 'pip install --no-deps besser'."
16
+ )
17
+ GUIModel = None
18
+ ViewContainer = None
19
+ _BESSER_AVAILABLE = False
20
+
21
+
22
+ class AgentGUI:
23
+ """BAF's interface to besser's :class:`GUIModel`, with helper methods for common GUI operations.
24
+
25
+ Handles the case where besser is not installed: all methods log a warning and return
26
+ ``None``/``False`` instead of raising an error. When besser *is* installed, attribute
27
+ access is transparently delegated to the inner model so that existing code that uses
28
+ ``gui.modules``, ``gui.name``, etc. continues to work unchanged.
29
+
30
+ Args:
31
+ model: the :class:`GUIModel` instance to wrap, or ``None``.
32
+ gui_id: identifier for the AgentGUI.
33
+ persist: whether to store GUI updates in the session or not. Defaults to true
34
+
35
+ Attributes:
36
+ _model: the inner :class:`GUIModel`, or ``None`` when besser is not installed or
37
+ no model has been set.
38
+ _id: identifier for the AgentGUI.
39
+ _persist: whether to store GUI updates in the session or not. Defaults to true
40
+ """
41
+
42
+ def __init__(self, model: GUIModel, gui_id: str | None = None, persist: bool = True, width: str | None = None):
43
+ self._model: GUIModel = model
44
+ if gui_id is None:
45
+ gui_id = str(uuid.uuid4())
46
+ self._id: str = gui_id
47
+ self._persist: bool = persist
48
+ self._width: str | None = width
49
+
50
+ # ------------------------------------------------------------------
51
+ # Core proxy behaviour
52
+ # ------------------------------------------------------------------
53
+
54
+ @property
55
+ def model(self):
56
+ """The underlying GUIModel instance, or None."""
57
+ return self._model
58
+
59
+ @property
60
+ def id(self) -> str:
61
+ """Unique identifier for this GUI reply message."""
62
+ return self._id
63
+
64
+ @property
65
+ def persist(self) -> bool:
66
+ """bool: If True, input values from GUI events for this component are persisted in the session's gui_inputs."""
67
+ return self._persist
68
+
69
+ @persist.setter
70
+ def persist(self, value: bool) -> None:
71
+ self._persist = value
72
+
73
+ @property
74
+ def width(self) -> str | None:
75
+ """str | None: CSS width applied to the GUI bubble in chat mode (e.g. '600px', '80%').
76
+ Overrides the default 78% max-width cap. None means use the default."""
77
+ return self._width
78
+
79
+ @width.setter
80
+ def width(self, value: str | None) -> None:
81
+ self._width = value
82
+
83
+ def __getattr__(self, name: str):
84
+ """Delegate attribute access to the inner GUIModel."""
85
+ model = self._model
86
+ if model is None:
87
+ if not _BESSER_AVAILABLE:
88
+ logger.warning(
89
+ f"Cannot access attribute '{name}': besser is not installed. "
90
+ "Install with 'pip install --no-deps besser'."
91
+ )
92
+ else:
93
+ logger.warning(f"Cannot access attribute '{name}': no GUI model set.")
94
+ return None
95
+ return getattr(model, name)
96
+
97
+ def __setattr__(self, name: str, value):
98
+ """Delegate attribute assignment to the inner GUIModel for non-private names."""
99
+ if name.startswith('_'):
100
+ super().__setattr__(name, value)
101
+ return
102
+ model = self._model
103
+ if model is None:
104
+ logger.warning(f"Cannot set attribute '{name}': no GUI model set.")
105
+ return
106
+ setattr(model, name, value)
107
+
108
+ def __bool__(self) -> bool:
109
+ return self._model is not None
110
+
111
+ # ------------------------------------------------------------------
112
+ # Helper: deep copy
113
+ # ------------------------------------------------------------------
114
+
115
+ def deep_copy(self) -> 'AgentGUI':
116
+ """Return a deep copy of this :class:`AgentGUI` and its inner model.
117
+
118
+ Returns:
119
+ AgentGUI: a new instance wrapping a deep-copied model.
120
+ """
121
+ model = self._model
122
+ if model is None:
123
+ return AgentGUI(None)
124
+ try:
125
+ return AgentGUI(copy.deepcopy(model))
126
+ except Exception as e:
127
+ logger.warning(f"Could not deep-copy GUI model: {e}. Returning a shallow reference.")
128
+ return AgentGUI(model)
129
+
130
+ # ------------------------------------------------------------------
131
+ # Helper: find
132
+ # ------------------------------------------------------------------
133
+
134
+ def find_components(self, field: str, value) -> list:
135
+ """Find all components in the model where ``getattr(component, field) == value``.
136
+
137
+ Recursively searches through all modules → screens → containers.
138
+
139
+ Args:
140
+ field (str): the attribute name to match (e.g. ``'component_id'``,
141
+ ``'name'``, ``'content'``).
142
+ value: the value to look for.
143
+
144
+ Returns:
145
+ list: all matching :class:`ViewElement` instances (empty list if none found).
146
+ """
147
+ model: GUIModel = self._model
148
+ if model is None:
149
+ logger.warning("Cannot find components: no GUI model set.")
150
+ return []
151
+ results = []
152
+ for module in model.modules:
153
+ for screen in module.screens:
154
+ self._collect_matching(screen.view_elements, field, value, results)
155
+ return results
156
+
157
+ def find_component(self, field: str, value):
158
+ """Find the first component in the model where ``getattr(component, field) == value``.
159
+
160
+ Recursively searches through all modules → screens → containers.
161
+
162
+ Args:
163
+ field (str): the attribute name to match (e.g. ``'component_id'``,
164
+ ``'name'``, ``'content'``).
165
+ value: the value to look for.
166
+
167
+ Returns:
168
+ The first matching :class:`ViewElement`, or ``None`` if not found.
169
+ """
170
+ results = self.find_components(field, value)
171
+ return results[0] if results else None
172
+
173
+ def _collect_matching(self, elements, field: str, value, results: list) -> None:
174
+ """Recursively collect into *results* every element where ``getattr(el, field) == value``."""
175
+ for el in elements:
176
+ if getattr(el, field, None) == value:
177
+ results.append(el)
178
+ child_elements = getattr(el, 'view_elements', None)
179
+ if child_elements:
180
+ self._collect_matching(child_elements, field, value, results)
181
+
182
+ # ------------------------------------------------------------------
183
+ # Helper: update
184
+ # ------------------------------------------------------------------
185
+
186
+ def update_component_by_id(self, component_id: str, **kwargs):
187
+ """Update attributes of a component located by its ``component_id``.
188
+
189
+ Args:
190
+ component_id (str): identifies the component to update.
191
+ **kwargs: attribute names and their new values.
192
+
193
+ Returns:
194
+ The updated component if found, or ``None``.
195
+ """
196
+ model = self._model
197
+ if model is None:
198
+ logger.warning("Cannot update component: no GUI model set.")
199
+ return None
200
+ component = self.find_component('component_id', component_id)
201
+ if component is None:
202
+ logger.warning(f"Component with id '{component_id}' not found in GUI model.")
203
+ return None
204
+ for attr, value in kwargs.items():
205
+ setattr(component, attr, value)
206
+ return component
207
+
208
+ # ------------------------------------------------------------------
209
+ # Helper: add
210
+ # ------------------------------------------------------------------
211
+
212
+ def add_component(self, component, parent_id: str = None, screen_name: str = None) -> bool:
213
+ """Add a component to the GUI model.
214
+
215
+ Resolution order:
216
+
217
+ 1. If *parent_id* is given, the component is added to the container that has
218
+ that ``component_id`` (must be a container with ``view_elements``).
219
+ 2. If *screen_name* is given, the component is added to the top-level
220
+ ``view_elements`` of the named screen.
221
+ 3. Otherwise the component is added to the main screen (``is_main_page=True``),
222
+ or to the first screen when no main screen exists.
223
+
224
+ Args:
225
+ component: the :class:`ViewElement` to add.
226
+ parent_id (str | None): ``component_id`` of the target container.
227
+ screen_name (str | None): name of the target screen (used when *parent_id* is
228
+ not given).
229
+
230
+ Returns:
231
+ bool: ``True`` if the component was added, ``False`` otherwise.
232
+ """
233
+ model = self._model
234
+ if model is None:
235
+ logger.warning("Cannot add component: no GUI model set.")
236
+ return False
237
+
238
+ if parent_id is not None:
239
+ parent = self.find_component('component_id', parent_id)
240
+ if parent is None:
241
+ logger.warning(f"Parent container with id '{parent_id}' not found.")
242
+ return False
243
+ if not hasattr(parent, 'view_elements'):
244
+ logger.warning(f"Component '{parent_id}' is not a container (no view_elements).")
245
+ return False
246
+ parent.view_elements = parent.view_elements | {component}
247
+ return True
248
+
249
+ target = self.get_screen(screen_name)
250
+ if target is None:
251
+ logger.warning("No screen found to add the component to.")
252
+ return False
253
+ target.view_elements = target.view_elements | {component}
254
+ return True
255
+
256
+ # ------------------------------------------------------------------
257
+ # Helper: screens
258
+ # ------------------------------------------------------------------
259
+
260
+ def get_screen(self, screen_name: str = None):
261
+ """Retrieve a screen by name, or the main screen when no name is given.
262
+
263
+ Falls back to the first screen when there is no screen marked as main.
264
+
265
+ Args:
266
+ screen_name (str | None): the screen name to look for, or ``None`` to get
267
+ the main/first screen.
268
+
269
+ Returns:
270
+ The :class:`Screen`, or ``None`` if not found.
271
+ """
272
+ model = self._model
273
+ if model is None:
274
+ logger.warning("Cannot get screen: no GUI model set.")
275
+ return None
276
+
277
+ first = None
278
+ for module in model.modules:
279
+ for screen in module.screens:
280
+ if first is None:
281
+ first = screen
282
+ if screen_name is not None:
283
+ if screen.name == screen_name:
284
+ return screen
285
+ elif getattr(screen, 'is_main_page', False):
286
+ return screen
287
+
288
+ # Fallbacks
289
+ if screen_name is None:
290
+ return first
291
+ return None
@@ -1,7 +1,8 @@
1
- """Deserialization helpers: JSON string → GUIModel."""
1
+ """Deserialization helpers: JSON string → AgentGUI."""
2
2
  import json
3
3
  from types import SimpleNamespace
4
4
 
5
+ from baf.core.gui.agent_gui import AgentGUI
5
6
  from baf.exceptions.logger import logger
6
7
 
7
8
  try:
@@ -10,6 +11,7 @@ try:
10
11
  ViewElement, ViewContainer, ViewComponent,
11
12
  Button, Text, Image, InputField, Form, Menu, MenuItem,
12
13
  DataList, EmbeddedContent, Link,
14
+ Alert, AlertSeverity, SelectOption,
13
15
  )
14
16
  from besser.BUML.metamodel.gui.style import Styling, Size, Position, Color, Layout
15
17
  from besser.BUML.metamodel.gui.dashboard import (
@@ -302,8 +304,22 @@ def _deserialize_view_element(d: dict) -> ViewElement:
302
304
  )
303
305
 
304
306
  if t == "InputField":
307
+ options_data = d.get("options") or []
308
+ options = [SelectOption(label=o.get("label", ""), value=o.get("value", "")) for o in options_data]
305
309
  return InputField(
306
- field_type=d.get("field_type", "text"),
310
+ field_type=d.get("field_type", "Text"),
311
+ label=d.get("label", ""),
312
+ placeholder=d.get("placeholder", ""),
313
+ required=d.get("required", False),
314
+ default_value=d.get("default_value"),
315
+ options=options if options else None,
316
+ min_value=d.get("min_value"),
317
+ max_value=d.get("max_value"),
318
+ step=d.get("step"),
319
+ help_text=d.get("help_text"),
320
+ disabled=d.get("disabled", False),
321
+ readonly=d.get("readonly", False),
322
+ multiple=d.get("multiple", False),
307
323
  validationRules=d.get("validationRules"),
308
324
  **base,
309
325
  )
@@ -311,6 +327,11 @@ def _deserialize_view_element(d: dict) -> ViewElement:
311
327
  if t == "Form":
312
328
  return Form(
313
329
  inputFields=set(_deserialize_view_element(f) for f in d.get("inputFields", [])),
330
+ title=d.get("title"),
331
+ submit_label=d.get("submit_label", "Submit"),
332
+ show_cancel=d.get("show_cancel", False),
333
+ cancel_label=d.get("cancel_label", "Cancel"),
334
+ columns=d.get("columns", 1),
314
335
  **base,
315
336
  )
316
337
 
@@ -329,6 +350,18 @@ def _deserialize_view_element(d: dict) -> ViewElement:
329
350
  if t == "DataList":
330
351
  return DataList(list_sources=set(), **base)
331
352
 
353
+ if t == "Alert":
354
+ severity_str = d.get("severity", "info")
355
+ _severity_map = {s.value: s for s in AlertSeverity}
356
+ severity = _severity_map.get(severity_str, AlertSeverity.Info)
357
+ return Alert(
358
+ content=d.get("content", ""),
359
+ severity=severity,
360
+ title=d.get("title"),
361
+ dismissible=d.get("dismissible", False),
362
+ **base,
363
+ )
364
+
332
365
  if t == "EmbeddedContent":
333
366
  return EmbeddedContent(
334
367
  source=d.get("source", ""),
@@ -367,14 +400,14 @@ def _deserialize_screen(d: dict) -> Screen:
367
400
  return Screen(**base)
368
401
 
369
402
 
370
- def json_to_gui(json_str: str) -> GUIModel:
371
- """Deserialize a JSON string produced by :func:`gui_to_json` back into a :class:`GUIModel`.
403
+ def json_to_gui(json_str: str, gui_id: str | None = None) -> AgentGUI:
404
+ """Deserialize a JSON string produced by :func:`gui_to_json` back into an :class:`~baf.core.gui.agent_gui.AgentGUI`.
372
405
 
373
406
  Args:
374
407
  json_str: JSON string representing the GUI model.
375
408
 
376
409
  Returns:
377
- A reconstructed :class:`GUIModel` instance.
410
+ A reconstructed :class:`~baf.core.gui.agent_gui.AgentGUI` instance wrapping the rebuilt model.
378
411
  """
379
412
  data = json.loads(json_str)
380
413
  modules = set()
@@ -392,7 +425,7 @@ def json_to_gui(json_str: str) -> GUIModel:
392
425
  style_entries = data.get("style_entries")
393
426
  if style_entries is not None:
394
427
  try:
395
- return GUIModel(**gui_kwargs, style_entries=style_entries)
428
+ return AgentGUI(GUIModel(**gui_kwargs, style_entries=style_entries))
396
429
  except TypeError:
397
430
  pass
398
- return GUIModel(**gui_kwargs)
431
+ return AgentGUI(GUIModel(**gui_kwargs), gui_id=gui_id)
@@ -0,0 +1,118 @@
1
+ """LLM-assisted GUI generation utilities."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import re
6
+ from typing import TYPE_CHECKING
7
+
8
+ from baf.core.gui.agent_gui import AgentGUI
9
+ from baf.core.gui.gui_deserializer import json_to_gui
10
+ from baf.core.gui.gui_schema import get_json_schema
11
+ from baf.exceptions.logger import logger
12
+
13
+ if TYPE_CHECKING:
14
+ from baf.nlp.llm.llm import LLM
15
+
16
+ _SYSTEM_PROMPT_TEMPLATE = (
17
+ "You are a GUI model generator. Given a user request, respond with a single valid JSON object "
18
+ "that conforms to the JSON Schema below. Output raw JSON only — no explanation, no markdown "
19
+ "code fences, no prose before or after.\n\n"
20
+ "JSON Schema:\n{schema}\n\n"
21
+ "Rules:\n"
22
+ "- The top-level object must contain 'name' and 'modules'.\n"
23
+ "- Each module must have 'name' and 'screens'.\n"
24
+ "- Each screen must have 'name' and 'view_elements'.\n"
25
+ "- Every view element must have a 'type' field discriminating its kind.\n"
26
+ "- Keep the model minimal but meaningful for the user request.\n"
27
+ "- Use realistic placeholder content (titles, labels, button labels, etc.)."
28
+ )
29
+
30
+ _RETRY_PROMPT_TEMPLATE = (
31
+ "The previous response could not be deserialized. Error: {error}\n\n"
32
+ "Please fix the JSON and respond again with a single valid JSON object only. "
33
+ "Original request: {prompt}"
34
+ )
35
+
36
+
37
+ def _build_system_prompt() -> str:
38
+ return _SYSTEM_PROMPT_TEMPLATE.format(schema=json.dumps(get_json_schema(), indent=2))
39
+
40
+
41
+ def _extract_json(text: str) -> str:
42
+ """Strip markdown code fences and return the raw JSON string from LLM output."""
43
+ match = re.search(r'```(?:json)?\s*([\s\S]*?)\s*```', text)
44
+ if match:
45
+ return match.group(1).strip()
46
+ match = re.search(r'(\{[\s\S]*\})', text)
47
+ if match:
48
+ return match.group(1).strip()
49
+ return text.strip()
50
+
51
+
52
+ def create_gui_with_llm(
53
+ llm: 'LLM',
54
+ prompt: str,
55
+ gui_id: str | None = None,
56
+ max_retries: int = 2,
57
+ ) -> AgentGUI:
58
+ """Generate an :class:`~baf.core.gui.agent_gui.AgentGUI` from a natural-language description.
59
+
60
+ The LLM is instructed via a system prompt to produce a JSON object conforming to
61
+ the AgentGUI JSON Schema. The JSON is then deserialized into a full
62
+ :class:`~baf.core.gui.agent_gui.AgentGUI` instance. If the first response fails to
63
+ parse or deserialize, the error is fed back to the LLM and the call is retried up to
64
+ *max_retries* times.
65
+
66
+ Args:
67
+ llm (LLM): any BAF :class:`~baf.nlp.llm.llm.LLM` instance with a ``predict`` method.
68
+ prompt (str): natural-language description of the GUI to generate (e.g.
69
+ ``"A login form with email, password fields and a Submit button."``).
70
+ gui_id (str | None): optional identifier forwarded to the returned
71
+ :class:`~baf.core.gui.agent_gui.AgentGUI`. A random UUID is used when
72
+ ``None`` (default).
73
+ max_retries (int): number of correction attempts when the LLM returns invalid or
74
+ non-deserializable JSON. Defaults to ``2``.
75
+
76
+ Returns:
77
+ AgentGUI | None: the generated GUI model, or ``None`` if generation failed after
78
+ all retries.
79
+
80
+ Example::
81
+
82
+ from baf.core.gui.gui_llm import create_gui_with_llm
83
+
84
+ gui = create_gui_with_llm(
85
+ llm=gpt,
86
+ prompt="A dashboard with a line chart and two metric cards.",
87
+ )
88
+ if gui is not None:
89
+ session.set_gui(gui)
90
+ """
91
+ system_prompt = _build_system_prompt()
92
+ current_prompt = prompt
93
+ last_error: Exception | None = None
94
+
95
+ for attempt in range(1 + max_retries):
96
+ raw = llm.predict(current_prompt, system_message=system_prompt)
97
+ try:
98
+ gui = json_to_gui(_extract_json(raw), gui_id=gui_id)
99
+ if attempt > 0:
100
+ logger.info(f"create_gui_with_llm: succeeded on attempt {attempt + 1}.")
101
+ return gui
102
+ except Exception as exc:
103
+ last_error = exc
104
+ if attempt < max_retries:
105
+ logger.warning(
106
+ f"create_gui_with_llm: attempt {attempt + 1} failed — {exc}. Retrying..."
107
+ )
108
+ current_prompt = _RETRY_PROMPT_TEMPLATE.format(error=exc, prompt=prompt)
109
+ else:
110
+ logger.warning(
111
+ f"create_gui_with_llm: attempt {attempt + 1} failed — {exc}. No more retries."
112
+ )
113
+
114
+ logger.error(
115
+ f"create_gui_with_llm: could not generate a valid GUI after {1 + max_retries} "
116
+ f"attempt(s). Last error: {last_error}"
117
+ )
118
+ return None