besser-agentic-framework 4.3.2__tar.gz → 4.4.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 (212) hide show
  1. {besser_agentic_framework-4.3.2/besser_agentic_framework.egg-info → besser_agentic_framework-4.4.0}/PKG-INFO +23 -15
  2. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/agent.py +327 -8
  3. besser_agentic_framework-4.4.0/baf/core/message.py +115 -0
  4. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/session.py +74 -0
  5. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/state.py +5 -1
  6. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/transition/transition_builder.py +1 -1
  7. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_db.py +214 -5
  8. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/table_overview.py +4 -1
  9. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/exceptions/logger.py +1 -1
  10. besser_agentic_framework-4.4.0/baf/library/state/__init__.py +23 -0
  11. besser_agentic_framework-4.4.0/baf/library/state/reasoning_state_library.py +788 -0
  12. besser_agentic_framework-4.4.0/baf/library/tool/__init__.py +27 -0
  13. besser_agentic_framework-4.4.0/baf/library/tool/task_tools.py +143 -0
  14. besser_agentic_framework-4.4.0/baf/library/tool/workspace_tools.py +123 -0
  15. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/transition/events/base_events.py +8 -5
  16. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/llm/llm.py +50 -1
  17. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/llm/llm_openai_api.py +49 -1
  18. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/payload.py +30 -1
  19. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/chat.py +14 -0
  20. besser_agentic_framework-4.4.0/baf/platforms/websocket/streamlit_ui/reasoning.py +242 -0
  21. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/websocket_callbacks.py +18 -0
  22. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/websocket_platform.py +169 -40
  23. besser_agentic_framework-4.4.0/baf/reasoning/__init__.py +5 -0
  24. besser_agentic_framework-4.4.0/baf/reasoning/skill.py +172 -0
  25. besser_agentic_framework-4.4.0/baf/reasoning/tool.py +382 -0
  26. besser_agentic_framework-4.4.0/baf/reasoning/workspace.py +309 -0
  27. besser_agentic_framework-4.4.0/baf/test/components/conftest.py +56 -0
  28. besser_agentic_framework-4.4.0/baf/test/components/test_core_agent.py +104 -0
  29. besser_agentic_framework-4.4.0/baf/test/components/test_core_intent_entity.py +106 -0
  30. besser_agentic_framework-4.4.0/baf/test/components/test_core_message.py +82 -0
  31. besser_agentic_framework-4.4.0/baf/test/components/test_core_processor.py +47 -0
  32. besser_agentic_framework-4.4.0/baf/test/components/test_core_property.py +71 -0
  33. besser_agentic_framework-4.4.0/baf/test/components/test_core_session.py +67 -0
  34. besser_agentic_framework-4.4.0/baf/test/components/test_core_state.py +123 -0
  35. besser_agentic_framework-4.4.0/baf/test/components/test_core_transition.py +81 -0
  36. besser_agentic_framework-4.4.0/baf/test/components/test_library_events.py +78 -0
  37. besser_agentic_framework-4.4.0/baf/test/components/test_nlp_configurations.py +80 -0
  38. besser_agentic_framework-4.4.0/baf/test/components/test_nlp_engine.py +65 -0
  39. besser_agentic_framework-4.4.0/baf/test/components/test_nlp_preprocessing.py +68 -0
  40. besser_agentic_framework-4.4.0/baf/test/components/test_platforms.py +63 -0
  41. besser_agentic_framework-4.4.0/baf/test/components/test_workflows.py +132 -0
  42. besser_agentic_framework-4.4.0/baf/test/dependencies/conftest.py +6 -0
  43. besser_agentic_framework-4.4.0/baf/test/dependencies/test_core.py +136 -0
  44. besser_agentic_framework-4.4.0/baf/test/dependencies/test_docs.py +26 -0
  45. besser_agentic_framework-4.4.0/baf/test/dependencies/test_extras.py +92 -0
  46. besser_agentic_framework-4.4.0/baf/test/dependencies/test_framework.py +184 -0
  47. besser_agentic_framework-4.4.0/baf/test/dependencies/test_llms.py +21 -0
  48. besser_agentic_framework-4.4.0/baf/test/dependencies/test_tensorflow.py +21 -0
  49. besser_agentic_framework-4.4.0/baf/test/dependencies/test_torch.py +27 -0
  50. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/greetings_agent.py +1 -1
  51. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/llm_agent.py +1 -1
  52. besser_agentic_framework-4.4.0/baf/test/examples/reasoning_agent.py +84 -0
  53. besser_agentic_framework-4.4.0/baf/utils/__init__.py +0 -0
  54. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0/besser_agentic_framework.egg-info}/PKG-INFO +23 -15
  55. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/besser_agentic_framework.egg-info/SOURCES.txt +35 -0
  56. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/besser_agentic_framework.egg-info/requires.txt +33 -13
  57. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/requirements/requirements-core.txt +4 -2
  58. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/requirements/requirements-extras.txt +7 -4
  59. besser_agentic_framework-4.4.0/requirements/requirements-tensorflow.txt +2 -0
  60. besser_agentic_framework-4.4.0/requirements/requirements-torch.txt +3 -0
  61. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/setup.cfg +1 -1
  62. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/setup.py +10 -2
  63. besser_agentic_framework-4.3.2/baf/core/message.py +0 -53
  64. besser_agentic_framework-4.3.2/requirements/requirements-tensorflow.txt +0 -2
  65. besser_agentic_framework-4.3.2/requirements/requirements-torch.txt +0 -2
  66. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/LICENSE +0 -0
  67. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/MANIFEST.in +0 -0
  68. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/README.md +0 -0
  69. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/__init__.py +0 -0
  70. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/__init__.py +0 -0
  71. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/entity/__init__.py +0 -0
  72. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/entity/entity.py +0 -0
  73. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/entity/entity_entry.py +0 -0
  74. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/file.py +0 -0
  75. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/intent/__init__.py +0 -0
  76. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/intent/intent.py +0 -0
  77. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/intent/intent_parameter.py +0 -0
  78. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/processors/__init__.py +0 -0
  79. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/processors/audio_language_detection_processor.py +0 -0
  80. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/processors/language_detection_processor.py +0 -0
  81. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/processors/processor.py +0 -0
  82. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/processors/user_adaptation_processor.py +0 -0
  83. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/property.py +0 -0
  84. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/transition/__init__.py +0 -0
  85. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/transition/condition.py +0 -0
  86. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/transition/event.py +0 -0
  87. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/core/transition/transition.py +0 -0
  88. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/__init__.py +0 -0
  89. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/db_handler.py +0 -0
  90. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/__init__.py +0 -0
  91. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/db_connection.py +0 -0
  92. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/flow_graph.py +0 -0
  93. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/home.py +0 -0
  94. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/intent_details.py +0 -0
  95. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/monitoring_ui.py +0 -0
  96. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/sidebar.py +0 -0
  97. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/db/monitoring_ui/utils.py +0 -0
  98. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/exceptions/__init__.py +0 -0
  99. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/exceptions/exceptions.py +0 -0
  100. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/__init__.py +0 -0
  101. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/coroutine/__init__.py +0 -0
  102. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/coroutine/async_helpers.py +0 -0
  103. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/entity/__init__.py +0 -0
  104. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/entity/base_entities.py +0 -0
  105. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/intent/__init__.py +0 -0
  106. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/intent/intent_library.py +0 -0
  107. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/state/state_library.py +0 -0
  108. {besser_agentic_framework-4.3.2/baf/library/state → besser_agentic_framework-4.4.0/baf/library/transition}/__init__.py +0 -0
  109. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/transition/condition_functions.py +0 -0
  110. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/transition/conditions.py +0 -0
  111. {besser_agentic_framework-4.3.2/baf/library/transition → besser_agentic_framework-4.4.0/baf/library/transition/events}/__init__.py +0 -0
  112. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/transition/events/github_webhooks_events.py +0 -0
  113. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/library/transition/events/gitlab_webhooks_events.py +0 -0
  114. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/__init__.py +0 -0
  115. {besser_agentic_framework-4.3.2/baf/library/transition/events → besser_agentic_framework-4.4.0/baf/nlp/intent_classifier}/__init__.py +0 -0
  116. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/intent_classifier.py +0 -0
  117. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/intent_classifier_configuration.py +0 -0
  118. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/intent_classifier_prediction.py +0 -0
  119. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/llm_intent_classifier.py +0 -0
  120. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/simple_intent_classifier_pytorch.py +0 -0
  121. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/intent_classifier/simple_intent_classifier_tensorflow.py +0 -0
  122. {besser_agentic_framework-4.3.2/baf/nlp/intent_classifier → besser_agentic_framework-4.4.0/baf/nlp/llm}/__init__.py +0 -0
  123. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/llm/llm_huggingface.py +0 -0
  124. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/llm/llm_huggingface_api.py +0 -0
  125. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/llm/llm_replicate_api.py +0 -0
  126. {besser_agentic_framework-4.3.2/baf/nlp/llm → besser_agentic_framework-4.4.0/baf/nlp/ner}/__init__.py +0 -0
  127. {besser_agentic_framework-4.3.2/baf/nlp/ner → besser_agentic_framework-4.4.0/baf/nlp/ner/base}/__init__.py +0 -0
  128. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/base/any.py +0 -0
  129. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/base/datetime.py +0 -0
  130. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/base/number.py +0 -0
  131. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/matched_parameter.py +0 -0
  132. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/ner.py +0 -0
  133. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/ner_prediction.py +0 -0
  134. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/ner/simple_ner.py +0 -0
  135. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/nlp_engine.py +0 -0
  136. {besser_agentic_framework-4.3.2/baf/nlp/ner/base → besser_agentic_framework-4.4.0/baf/nlp/preprocessing}/__init__.py +0 -0
  137. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/preprocessing/pipelines.py +0 -0
  138. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/preprocessing/text_preprocessing.py +0 -0
  139. {besser_agentic_framework-4.3.2/baf/nlp/preprocessing → besser_agentic_framework-4.4.0/baf/nlp/rag}/__init__.py +0 -0
  140. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/rag/rag.py +0 -0
  141. {besser_agentic_framework-4.3.2/baf/nlp/rag → besser_agentic_framework-4.4.0/baf/nlp/speech2text}/__init__.py +0 -0
  142. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/speech2text/api_speech2text.py +0 -0
  143. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/speech2text/hf_speech2text.py +0 -0
  144. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/speech2text/luxasr_speech2text.py +0 -0
  145. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/speech2text/openai_speech2text.py +0 -0
  146. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/speech2text/speech2text.py +0 -0
  147. {besser_agentic_framework-4.3.2/baf/nlp/speech2text → besser_agentic_framework-4.4.0/baf/nlp/text2speech}/__init__.py +0 -0
  148. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/text2speech/hf_text2speech.py +0 -0
  149. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/text2speech/openai_text2speech.py +0 -0
  150. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/text2speech/piper_text2speech.py +0 -0
  151. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/text2speech/text2speech.py +0 -0
  152. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/nlp/utils.py +0 -0
  153. {besser_agentic_framework-4.3.2/baf/nlp/text2speech → besser_agentic_framework-4.4.0/baf/platforms}/__init__.py +0 -0
  154. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/__init__.py +0 -0
  155. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/a2a_platform.py +0 -0
  156. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/agent_card.py +0 -0
  157. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/agent_registry.py +0 -0
  158. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/client.py +0 -0
  159. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/error_handler.py +0 -0
  160. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/message_router.py +0 -0
  161. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/server.py +0 -0
  162. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/a2a/task_protocol.py +0 -0
  163. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/github/__init__.py +0 -0
  164. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/github/github_actions.py +0 -0
  165. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/github/github_objects.py +0 -0
  166. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/github/github_platform.py +0 -0
  167. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/gitlab/__init__.py +0 -0
  168. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/gitlab/gitlab_actions.py +0 -0
  169. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/gitlab/gitlab_objects.py +0 -0
  170. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/gitlab/gitlab_platform.py +0 -0
  171. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/platform.py +0 -0
  172. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/telegram/__init__.py +0 -0
  173. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/telegram/telegram_platform.py +0 -0
  174. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/__init__.py +0 -0
  175. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/__init__.py +0 -0
  176. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/audio_queue.py +0 -0
  177. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/chat_interface_style.py +0 -0
  178. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/initialization.py +0 -0
  179. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/login.py +0 -0
  180. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/message_input.py +0 -0
  181. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/profile_selector.py +0 -0
  182. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/session_management.py +0 -0
  183. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/sidebar.py +0 -0
  184. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/streamlit_ui.py +0 -0
  185. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/user_db.py +0 -0
  186. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/platforms/websocket/streamlit_ui/vars.py +0 -0
  187. {besser_agentic_framework-4.3.2/baf/platforms → besser_agentic_framework-4.4.0/baf/test}/__init__.py +0 -0
  188. {besser_agentic_framework-4.3.2/baf/test → besser_agentic_framework-4.4.0/baf/test/components}/__init__.py +0 -0
  189. {besser_agentic_framework-4.3.2/baf/test/examples → besser_agentic_framework-4.4.0/baf/test/dependencies}/__init__.py +0 -0
  190. {besser_agentic_framework-4.3.2/baf/test/examples/multiagent → besser_agentic_framework-4.4.0/baf/test/examples}/__init__.py +0 -0
  191. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/a2a_multiagent.py +0 -0
  192. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/api_speech2text_agent.py +0 -0
  193. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/github_agent.py +0 -0
  194. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/gitlab_agent.py +0 -0
  195. {besser_agentic_framework-4.3.2/baf/utils → besser_agentic_framework-4.4.0/baf/test/examples/multiagent}/__init__.py +0 -0
  196. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/multiagent/coder_agent.py +0 -0
  197. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/multiagent/main_agent.py +0 -0
  198. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/multiagent/reviewer_agent.py +0 -0
  199. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/rag_agent.py +0 -0
  200. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/speech2speech_agent.py +0 -0
  201. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/speech2text_agent.py +0 -0
  202. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/stargazer_agent.py +0 -0
  203. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/telegram_agent.py +0 -0
  204. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/text2speech_agent.py +0 -0
  205. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/weather_agent.py +0 -0
  206. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/test/examples/web_crawl_agent.py +0 -0
  207. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/baf/utils/web_crawl.py +0 -0
  208. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/besser_agentic_framework.egg-info/dependency_links.txt +0 -0
  209. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/besser_agentic_framework.egg-info/top_level.txt +0 -0
  210. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/pyproject.toml +0 -0
  211. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/requirements/requirements-docs.txt +0 -0
  212. {besser_agentic_framework-4.3.2 → besser_agentic_framework-4.4.0}/requirements/requirements-llms.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: besser-agentic-framework
3
- Version: 4.3.2
3
+ Version: 4.4.0
4
4
  Summary: BESSER Agentic Framework (BAF)
5
5
  Author: Luxembourg Institute of Science and Technology
6
6
  License: MIT
@@ -18,7 +18,8 @@ Requires-Dist: dateparser==1.1.8
18
18
  Requires-Dist: langdetect==1.0.9
19
19
  Requires-Dist: markdownify==1.2.2
20
20
  Requires-Dist: nltk==3.9.1
21
- Requires-Dist: numpy==1.26.4
21
+ Requires-Dist: numpy==1.26.4; python_version < "3.13"
22
+ Requires-Dist: numpy<3,>=2.1; python_version >= "3.13"
22
23
  Requires-Dist: pandas==2.3.3
23
24
  Requires-Dist: python-telegram-bot==21.0
24
25
  Requires-Dist: psycopg2-binary>=2.9.10
@@ -27,7 +28,8 @@ Requires-Dist: pyvis==0.3.2
27
28
  Requires-Dist: PyYAML==6.0.2
28
29
  Requires-Dist: requests==2.31.0
29
30
  Requires-Dist: snowballstemmer==2.2.0
30
- Requires-Dist: sqlalchemy==2.0.29
31
+ Requires-Dist: sqlalchemy==2.0.29; python_version < "3.13"
32
+ Requires-Dist: sqlalchemy<2.1,>=2.0.31; python_version >= "3.13"
31
33
  Requires-Dist: streamlit==1.40.0
32
34
  Requires-Dist: streamlit-antd-components==0.3.2
33
35
  Requires-Dist: text2num==2.5.0
@@ -35,16 +37,19 @@ Requires-Dist: websocket-client==1.6.4
35
37
  Requires-Dist: websockets==11.0.3
36
38
  Requires-Dist: bcrypt==4.0.1
37
39
  Provides-Extra: extras
38
- Requires-Dist: spacy==3.7.2; extra == "extras"
40
+ Requires-Dist: spacy==3.8.7; extra == "extras"
39
41
  Requires-Dist: scikit-learn>=1.7.0; extra == "extras"
40
42
  Requires-Dist: librosa==0.10.1; extra == "extras"
41
43
  Requires-Dist: SpeechRecognition==3.10.0; extra == "extras"
42
44
  Requires-Dist: soundfile==0.13.1; extra == "extras"
43
45
  Requires-Dist: opencv-python==4.10.0.84; extra == "extras"
44
46
  Requires-Dist: plotly==5.18.0; extra == "extras"
45
- Requires-Dist: chromadb==0.5.4; extra == "extras"
46
- Requires-Dist: langchain==0.2.9; extra == "extras"
47
- Requires-Dist: langchain-community==0.2.7; extra == "extras"
47
+ Requires-Dist: chromadb==0.5.4; python_version < "3.13" and extra == "extras"
48
+ Requires-Dist: chromadb==1.0.0; python_version >= "3.13" and extra == "extras"
49
+ Requires-Dist: langchain==0.2.9; python_version < "3.13" and extra == "extras"
50
+ Requires-Dist: langchain-community==0.2.7; python_version < "3.13" and extra == "extras"
51
+ Requires-Dist: langchain==0.3.10; python_version >= "3.13" and extra == "extras"
52
+ Requires-Dist: langchain-community==0.3.10; python_version >= "3.13" and extra == "extras"
48
53
  Requires-Dist: pypdf==4.3.1; extra == "extras"
49
54
  Requires-Dist: tiktoken==0.9.0; extra == "extras"
50
55
  Provides-Extra: llms
@@ -53,9 +58,9 @@ Requires-Dist: replicate==0.23.1; extra == "llms"
53
58
  Requires-Dist: transformers==4.53.0; extra == "llms"
54
59
  Provides-Extra: tensorflow
55
60
  Requires-Dist: keras==3.12.0; extra == "tensorflow"
56
- Requires-Dist: tensorflow==2.20.0; extra == "tensorflow"
61
+ Requires-Dist: tensorflow-cpu==2.20.0; extra == "tensorflow"
57
62
  Provides-Extra: torch
58
- Requires-Dist: torch==2.5.1; extra == "torch"
63
+ Requires-Dist: torch==2.6.0+cpu; extra == "torch"
59
64
  Requires-Dist: scikit-learn>=1.7.0; extra == "torch"
60
65
  Provides-Extra: docs
61
66
  Requires-Dist: sphinx==7.2.3; extra == "docs"
@@ -64,24 +69,27 @@ Requires-Dist: sphinx-paramlinks==0.6.0; extra == "docs"
64
69
  Requires-Dist: furo==2023.8.19; extra == "docs"
65
70
  Requires-Dist: m2r2==0.3.3; extra == "docs"
66
71
  Provides-Extra: all
67
- Requires-Dist: spacy==3.7.2; extra == "all"
72
+ Requires-Dist: spacy==3.8.7; extra == "all"
68
73
  Requires-Dist: scikit-learn>=1.7.0; extra == "all"
69
74
  Requires-Dist: librosa==0.10.1; extra == "all"
70
75
  Requires-Dist: SpeechRecognition==3.10.0; extra == "all"
71
76
  Requires-Dist: soundfile==0.13.1; extra == "all"
72
77
  Requires-Dist: opencv-python==4.10.0.84; extra == "all"
73
78
  Requires-Dist: plotly==5.18.0; extra == "all"
74
- Requires-Dist: chromadb==0.5.4; extra == "all"
75
- Requires-Dist: langchain==0.2.9; extra == "all"
76
- Requires-Dist: langchain-community==0.2.7; extra == "all"
79
+ Requires-Dist: chromadb==0.5.4; python_version < "3.13" and extra == "all"
80
+ Requires-Dist: chromadb==1.0.0; python_version >= "3.13" and extra == "all"
81
+ Requires-Dist: langchain==0.2.9; python_version < "3.13" and extra == "all"
82
+ Requires-Dist: langchain-community==0.2.7; python_version < "3.13" and extra == "all"
83
+ Requires-Dist: langchain==0.3.10; python_version >= "3.13" and extra == "all"
84
+ Requires-Dist: langchain-community==0.3.10; python_version >= "3.13" and extra == "all"
77
85
  Requires-Dist: pypdf==4.3.1; extra == "all"
78
86
  Requires-Dist: tiktoken==0.9.0; extra == "all"
79
87
  Requires-Dist: openai==1.93.0; extra == "all"
80
88
  Requires-Dist: replicate==0.23.1; extra == "all"
81
89
  Requires-Dist: transformers==4.53.0; extra == "all"
82
90
  Requires-Dist: keras==3.12.0; extra == "all"
83
- Requires-Dist: tensorflow==2.20.0; extra == "all"
84
- Requires-Dist: torch==2.5.1; extra == "all"
91
+ Requires-Dist: tensorflow-cpu==2.20.0; extra == "all"
92
+ Requires-Dist: torch==2.6.0+cpu; extra == "all"
85
93
  Requires-Dist: scikit-learn>=1.7.0; extra == "all"
86
94
  Dynamic: license-file
87
95
  Dynamic: provides-extra
@@ -1,4 +1,6 @@
1
1
  import asyncio
2
+ import importlib
3
+ import inspect
2
4
  import json
3
5
  import operator
4
6
  import threading
@@ -24,7 +26,7 @@ from baf.db.monitoring_db import MonitoringDB
24
26
  from baf.exceptions.exceptions import AgentNotTrainedError, DuplicatedEntityError, DuplicatedInitialStateError, \
25
27
  DuplicatedIntentError, DuplicatedStateError, InitialStateNotFound
26
28
  from baf.exceptions.logger import logger
27
- from baf.library.transition.events.base_events import ReceiveMessageEvent, ReceiveJSONEvent
29
+ from baf.library.transition.events.base_events import ReceiveMessageEvent, ReceiveJSONEvent, ReceiveFileEvent
28
30
  from baf.nlp.intent_classifier.intent_classifier_configuration import IntentClassifierConfiguration, \
29
31
  SimpleIntentClassifierConfiguration
30
32
  from baf.nlp.intent_classifier.intent_classifier_prediction import IntentClassifierPrediction
@@ -35,6 +37,7 @@ from baf.platforms.websocket.websocket_platform import WebSocketPlatform
35
37
  from baf.platforms.github.github_platform import GitHubPlatform
36
38
  from baf.platforms.gitlab.gitlab_platform import GitLabPlatform
37
39
  from baf.platforms.a2a.a2a_platform import A2APlatform
40
+ from baf.reasoning import Tool, Skill, Workspace
38
41
 
39
42
 
40
43
  class Agent:
@@ -66,6 +69,22 @@ class Agent:
66
69
  global_state_component (dict[State, list[State]]): Dictionary of global state components, where key is initial
67
70
  global state and values is set of states in corresponding global component
68
71
  processors (list[Processors]): List of processors used by the agent
72
+ _tools (dict[str, Tool]): Tools registered on the agent and exposed
73
+ to the predefined reasoning state. Keyed by tool name. Populated
74
+ by :meth:`add_tool` / :meth:`new_tool` / :meth:`load_tools`, the
75
+ ``@agent.tool`` decorator, and indirectly by :meth:`add_workspace`
76
+ / :meth:`new_workspace` (which register the universal
77
+ ``list_directory`` / ``read_file`` and — when at least one
78
+ workspace is writable — ``write_file`` / ``create_file`` /
79
+ ``delete_file`` tools).
80
+ _skills (dict[str, Skill]): Markdown-based playbooks the reasoning
81
+ state injects into the system prompt. Keyed by skill name.
82
+ Populated by :meth:`add_skill` / :meth:`new_skill` /
83
+ :meth:`load_skills`.
84
+ _workspaces (dict[str, Workspace]): Filesystem workspaces the agent
85
+ can browse and (when ``writable=True``) modify through the
86
+ universal workspace tools. Keyed by workspace name. Populated
87
+ by :meth:`add_workspace` / :meth:`new_workspace`.
69
88
  """
70
89
 
71
90
  def __init__(
@@ -94,6 +113,9 @@ class Agent:
94
113
  self.processors: list[Processor] = []
95
114
  self._user_profiles: Any = None
96
115
  self._agent_configurations: dict[str, Any] = {}
116
+ self._tools: dict[str, Tool] = {}
117
+ self._skills: dict[str, Skill] = {}
118
+ self._workspaces: dict[str, Workspace] = {}
97
119
 
98
120
  if user_profiles_path:
99
121
  self.load_user_profiles(user_profiles_path)
@@ -121,9 +143,8 @@ class Agent:
121
143
 
122
144
  Supported formats are YAML (``.yaml``, ``.yml``).
123
145
 
124
- Example YAML properties file, ``config.yaml``:
125
-
126
- .. literalinclude:: ../../../../baf/agent/test/examples/config.yaml
146
+ See ``baf/test/examples/config.yaml`` in the repository for a complete
147
+ example of an agent configuration file.
127
148
 
128
149
  Args:
129
150
  path (str): the path to the properties file
@@ -316,6 +337,267 @@ class Agent:
316
337
  self.states.append(new_state)
317
338
  return new_state
318
339
 
340
+ # --- Reasoning extension ----------------------------------------------- #
341
+
342
+ def add_tool(self, tool: Tool) -> Tool:
343
+ """Add an already-constructed :class:`~baf.reasoning.tool.Tool` to the agent.
344
+
345
+ Mirrors :meth:`add_intent`: the caller builds the wrapper, this method
346
+ registers it. Use :meth:`new_tool` when you want to skip the explicit
347
+ ``Tool(...)`` construction.
348
+
349
+ Args:
350
+ tool (Tool): the tool wrapper to register.
351
+
352
+ Returns:
353
+ Tool: the registered tool wrapper.
354
+ """
355
+ if tool.name in self._tools:
356
+ logger.warning(f"[Agent] Replacing existing tool '{tool.name}'")
357
+ self._tools[tool.name] = tool
358
+ logger.info(f"[Agent] Registered tool: {tool.name}")
359
+ return tool
360
+
361
+ def new_tool(self, fn: Callable, name: str = None, description: str = None) -> Tool:
362
+ """Build a :class:`~baf.reasoning.tool.Tool` from a callable and register it.
363
+
364
+ See :class:`baf.reasoning.tool.Tool` for the auto-introspection rules.
365
+
366
+ Args:
367
+ fn (Callable): the function to expose. May be a bound method.
368
+ name (str): override the tool's public name. Defaults to ``fn.__name__``.
369
+ description (str): override the description shown to the LLM.
370
+ Defaults to the first line of ``fn.__doc__``.
371
+
372
+ Returns:
373
+ Tool: the registered tool wrapper.
374
+ """
375
+ return self.add_tool(Tool(fn, name=name, description=description))
376
+
377
+ def load_tools(self, path: str) -> list[Tool]:
378
+ """Load every public top-level callable from a Python module or folder of modules.
379
+
380
+ ``path`` may be a single ``.py`` file or a folder (non-recursive). For
381
+ each module, every callable whose name does not start with ``_`` is
382
+ registered as a tool. Callables imported from other modules are skipped
383
+ — only those *defined* in the loaded module are considered, so importing
384
+ helpers in ``tools.py`` does not pollute the tool registry.
385
+
386
+ Args:
387
+ path (str): path to a ``.py`` file or to a folder containing them.
388
+
389
+ Returns:
390
+ list[Tool]: the tools that were registered (may be empty).
391
+ """
392
+ target = Path(path)
393
+ if not target.exists():
394
+ raise FileNotFoundError(f"load_tools: path does not exist: {path}")
395
+
396
+ if target.is_file():
397
+ files = [target]
398
+ else:
399
+ files = sorted(p for p in target.iterdir() if p.is_file() and p.suffix == ".py")
400
+
401
+ registered: list = []
402
+ for file in files:
403
+ module_name = f"baf_loaded_tools_{file.stem}"
404
+ spec = importlib.util.spec_from_file_location(module_name, file)
405
+ if spec is None or spec.loader is None:
406
+ logger.warning(f"[Agent] Could not load tools from {file}: no spec")
407
+ continue
408
+ module = importlib.util.module_from_spec(spec)
409
+ try:
410
+ spec.loader.exec_module(module)
411
+ except Exception as e:
412
+ logger.warning(f"[Agent] Failed to import tools from {file}: {e}")
413
+ continue
414
+ for member_name, member in inspect.getmembers(module):
415
+ if member_name.startswith("_"):
416
+ continue
417
+ if not callable(member):
418
+ continue
419
+ # Skip classes and members imported from other modules.
420
+ if inspect.isclass(member):
421
+ continue
422
+ if getattr(member, "__module__", None) != module.__name__:
423
+ continue
424
+ registered.append(self.new_tool(member))
425
+ return registered
426
+
427
+ def tool(self, fn: Callable = None, *, name: str = None, description: str = None):
428
+ """Decorator form of :meth:`new_tool`.
429
+
430
+ Usable bare (``@agent.tool``) or with arguments (``@agent.tool(name='x')``).
431
+ """
432
+ def _wrap(f: Callable) -> Callable:
433
+ self.new_tool(f, name=name, description=description)
434
+ return f
435
+ if fn is None:
436
+ return _wrap
437
+ return _wrap(fn)
438
+
439
+ def add_skill(self, skill: Skill) -> Skill:
440
+ """Add an already-constructed :class:`~baf.reasoning.skill.Skill` to the agent.
441
+
442
+ Mirrors :meth:`add_intent`. Use :meth:`new_skill` to skip the explicit
443
+ ``Skill(...)`` construction (especially convenient for loading from a
444
+ ``.md`` file path).
445
+
446
+ Args:
447
+ skill (Skill): the skill to register.
448
+
449
+ Returns:
450
+ Skill: the registered skill.
451
+ """
452
+ if skill.name in self._skills:
453
+ logger.warning(f"[Agent] Replacing existing skill '{skill.name}'")
454
+ self._skills[skill.name] = skill
455
+ logger.info(f"[Agent] Registered skill: {skill.name}")
456
+ return skill
457
+
458
+ def new_skill(self, source: str, name: str = None, description: str = None) -> Skill:
459
+ """Build a :class:`~baf.reasoning.skill.Skill` and register it.
460
+
461
+ ``source`` is either a path to an existing ``.md`` file (loaded via
462
+ :meth:`Skill.from_file`) or a literal markdown string. The path
463
+ detection is automatic.
464
+
465
+ Args:
466
+ source (str): path to a ``.md`` file or the markdown content as a string.
467
+ name (str): override the skill name (otherwise taken from frontmatter,
468
+ a leading H1, or the filename stem).
469
+ description (str): override the description (otherwise taken from
470
+ frontmatter).
471
+
472
+ Returns:
473
+ Skill: the registered skill.
474
+ """
475
+ candidate = Path(source) if isinstance(source, str) else None
476
+ if candidate is not None and candidate.is_file() and candidate.suffix.lower() == ".md":
477
+ skill = Skill.from_file(str(candidate))
478
+ if name:
479
+ skill.name = name
480
+ if description:
481
+ skill.description = description
482
+ else:
483
+ skill = Skill(source, name=name, description=description)
484
+ return self.add_skill(skill)
485
+
486
+ def load_skills(self, folder: str) -> list[Skill]:
487
+ """Register every ``*.md`` file in ``folder`` (non-recursive) as a skill.
488
+
489
+ Args:
490
+ folder (str): path to a folder containing markdown files.
491
+
492
+ Returns:
493
+ list[Skill]: the skills that were registered.
494
+ """
495
+ return [self.add_skill(s) for s in Skill.from_folder(folder)]
496
+
497
+ def add_workspace(self, workspace: Workspace) -> Workspace:
498
+ """Add an already-constructed :class:`~baf.reasoning.workspace.Workspace` to the agent.
499
+
500
+ The first call also registers the universal ``list_directory`` /
501
+ ``read_file`` tools, and — if at least one registered workspace has
502
+ ``writable=True`` — the ``write_file`` / ``create_file`` /
503
+ ``delete_file`` tools.
504
+
505
+ Mirrors :meth:`add_intent`. Use :meth:`new_workspace` to skip the
506
+ explicit ``Workspace(...)`` construction.
507
+
508
+ Args:
509
+ workspace (Workspace): the workspace to register.
510
+
511
+ Returns:
512
+ Workspace: the registered workspace.
513
+
514
+ Raises:
515
+ ValueError: if a workspace with the same name is already registered.
516
+ """
517
+ if workspace.name in self._workspaces:
518
+ raise ValueError(f"Workspace '{workspace.name}' is already registered")
519
+ self._workspaces[workspace.name] = workspace
520
+ self._ensure_workspace_tools_registered()
521
+ logger.info(f"[Agent] Registered workspace: {workspace.name} "
522
+ f"(root={workspace.root}, writable={workspace.writable})")
523
+ return workspace
524
+
525
+ def new_workspace(self, path: str, name: str = "workspace",
526
+ description: str = None,
527
+ writable: bool = True,
528
+ max_read_bytes: int = 200_000) -> Workspace:
529
+ """Build a :class:`~baf.reasoning.workspace.Workspace` and register it.
530
+
531
+ Args:
532
+ path (str): the workspace root path.
533
+ name (str): the workspace identifier the LLM passes as the
534
+ ``workspace`` tool argument. Must be unique within the agent.
535
+ description (str): a short human-readable explanation of *what* the
536
+ workspace contains. Strongly recommended — without it the LLM
537
+ only sees the name and root path and may not realise it should
538
+ browse the workspace.
539
+ writable (bool): whether mutating operations are allowed on this
540
+ workspace (``write_file`` / ``create_file`` / ``delete_file``).
541
+ Defaults to True.
542
+ max_read_bytes (int): cap on ``read_file`` output, in bytes.
543
+
544
+ Returns:
545
+ Workspace: the registered workspace.
546
+ """
547
+ return self.add_workspace(Workspace(
548
+ path, name=name, description=description,
549
+ writable=writable, max_read_bytes=max_read_bytes,
550
+ ))
551
+
552
+ def _resolve_workspace(self, name: str = None) -> 'Workspace':
553
+ """Look up a workspace by name, or pick the only one when ``name`` is None.
554
+
555
+ Raises a ``ValueError`` (which the Tool wrapper turns into an LLM-readable
556
+ ERROR string) on missing or ambiguous lookups.
557
+ """
558
+ if name is None:
559
+ if len(self._workspaces) == 1:
560
+ return next(iter(self._workspaces.values()))
561
+ if not self._workspaces:
562
+ raise ValueError("No workspaces are registered")
563
+ raise ValueError(
564
+ f"Multiple workspaces are registered, please specify one of: "
565
+ f"{list(self._workspaces.keys())}"
566
+ )
567
+ if name not in self._workspaces:
568
+ raise ValueError(
569
+ f"Workspace '{name}' not found. Available: {list(self._workspaces.keys())}"
570
+ )
571
+ return self._workspaces[name]
572
+
573
+ def _ensure_workspace_tools_registered(self) -> None:
574
+ """Register the universal workspace tools.
575
+
576
+ Read tools (``list_directory``, ``read_file``) are registered as soon
577
+ as any workspace exists. Write tools (``write_file``, ``create_file``,
578
+ ``delete_file``) are registered only once at least one workspace has
579
+ ``writable=True`` — read-only-only setups never expose them to the LLM.
580
+
581
+ The tool callables themselves live in
582
+ :mod:`baf.library.tool.workspace_tools`. This method only owns the
583
+ gating policy (which family to expose, when) plus the dedup check.
584
+ Idempotent — already-registered tools are skipped.
585
+ """
586
+ # Imported lazily to avoid pulling baf.library.tool at module load time.
587
+ from baf.library.tool.workspace_tools import (
588
+ build_workspace_read_tools,
589
+ build_workspace_write_tools,
590
+ )
591
+
592
+ for fn in build_workspace_read_tools(self):
593
+ if fn.__name__ not in self._tools:
594
+ self.new_tool(fn)
595
+
596
+ if any(ws.writable for ws in self._workspaces.values()):
597
+ for fn in build_workspace_write_tools(self):
598
+ if fn.__name__ not in self._tools:
599
+ self.new_tool(fn)
600
+
319
601
  def add_intent(self, intent: Intent) -> Intent:
320
602
  """Add an intent to the agent.
321
603
 
@@ -534,6 +816,9 @@ class Agent:
534
816
  else:
535
817
  t = MessageType.STR
536
818
  session.save_message(Message(t=t, content=event.message, is_user=True, timestamp=datetime.now()))
819
+ if isinstance(event, ReceiveFileEvent):
820
+ session.save_message(Message(t=MessageType.FILE, content=event.file.get_json_string(), is_user=True, timestamp=datetime.now()))
821
+
537
822
  logger.info(f'Received event: {event.log()}')
538
823
 
539
824
  def process(self, session: Session, message: Any, is_user_message: bool) -> Any:
@@ -602,12 +887,14 @@ class Agent:
602
887
  else:
603
888
  return None
604
889
 
605
- def _new_session(self, session_id: str, platform: Platform) -> Session:
890
+ def _new_session(self, session_id: str, platform: Platform, username: str or None = None, session_name: str or None = None) -> Session:
606
891
  """Create a new session for the agent.
607
892
 
608
893
  Args:
609
894
  session_id (str): the session id
610
895
  platform (Platform): the platform where the session is to be created and used
896
+ username (str): the name of the session user (optional)
897
+ session_name (str): the name of the session (optional)
611
898
 
612
899
  Returns:
613
900
  Session: the session
@@ -616,7 +903,7 @@ class Agent:
616
903
  raise ValueError(f'Trying to create a new session with an existing id" {session_id}')
617
904
  if platform not in self._platforms:
618
905
  raise ValueError(f"Platform {platform.__class__.__name__} not found in agent '{self.name}'")
619
- session = Session(session_id, self, platform)
906
+ session = Session(session_id, self, platform, username, session_name)
620
907
  self._sessions[session_id] = session
621
908
  if self._persist_sessions and self._monitoring_db_session_exists(session_id, platform):
622
909
  dest_state = self._monitoring_db_get_last_state_of_session(session_id, platform)
@@ -635,10 +922,10 @@ class Agent:
635
922
  session._run_event_thread()
636
923
  return session
637
924
 
638
- def get_or_create_session(self, session_id: str, platform: Platform) -> Session:
925
+ def get_or_create_session(self, session_id: str, platform: Platform, username: str or None = None, session_name: str or None = None) -> Session:
639
926
  session = self._get_session(session_id)
640
927
  if session is None:
641
- session = self._new_session(session_id, platform)
928
+ session = self._new_session(session_id, platform, username, session_name)
642
929
  return session
643
930
 
644
931
  def close_session(self, session_id: str) -> None:
@@ -854,6 +1141,38 @@ class Agent:
854
1141
  thread = threading.Thread(target=self._monitoring_db.insert_chat, args=(session, message))
855
1142
  thread.start()
856
1143
 
1144
+ def _monitoring_db_insert_reasoning_event(
1145
+ self,
1146
+ session: Session,
1147
+ kind: str,
1148
+ payload: Any,
1149
+ ) -> None:
1150
+ """Insert a reasoning-state event (step or task-list snapshot) into the
1151
+ dedicated ``reasoning_step`` table. Synchronous on purpose so a
1152
+ subsequent ``link_pending_reasoning_events`` call sees the row.
1153
+ """
1154
+ if self.get_property(DB_MONITORING) and self._monitoring_db.connected:
1155
+ self._monitoring_db.insert_reasoning_event(session, kind, payload)
1156
+
1157
+ def _monitoring_db_select_reasoning_events(
1158
+ self,
1159
+ session: Session,
1160
+ until_timestamp=None,
1161
+ ):
1162
+ """Fetch all reasoning events for a session, in chronological order."""
1163
+ if self.get_property(DB_MONITORING) and self._monitoring_db.connected:
1164
+ return self._monitoring_db.select_reasoning_events(
1165
+ session, until_timestamp=until_timestamp,
1166
+ )
1167
+ return None
1168
+
1169
+ def _monitoring_db_link_pending_reasoning_events(self, session: Session) -> None:
1170
+ """Attach reasoning events with chat_id IS NULL to the most recent
1171
+ chat row for ``session``. Best-effort, called at the end of every
1172
+ reasoning loop."""
1173
+ if self.get_property(DB_MONITORING) and self._monitoring_db.connected:
1174
+ self._monitoring_db.link_pending_reasoning_events(session)
1175
+
857
1176
  def _monitoring_db_insert_event(self, event: Event) -> None:
858
1177
  """Insert an event record into the monitoring database.
859
1178
 
@@ -0,0 +1,115 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+ from typing import Any
4
+
5
+ from baf.platforms.payload import PayloadAction
6
+
7
+
8
+ class MessageType(Enum):
9
+ """Enumeration of the different message types in :class:`Message`."""
10
+
11
+ STR = 'str'
12
+ JSON = 'json'
13
+ MARKDOWN = 'markdown'
14
+ HTML = 'html'
15
+ FILE = 'file'
16
+ IMAGE = 'image'
17
+ DATAFRAME = 'dataframe'
18
+ PLOTLY = 'plotly'
19
+ LOCATION = 'location'
20
+ OPTIONS = 'options'
21
+ AUDIO = 'audio'
22
+ RAG_ANSWER = 'rag_answer'
23
+ UI = 'ui'
24
+ REASONING_TRACE = 'reasoning_trace' # UI-internal synthetic type aggregating streamed reasoning_step / task_list_update events
25
+
26
+
27
+ def get_message_type(value: str):
28
+ for message_type in MessageType:
29
+ if message_type.value == value:
30
+ return message_type
31
+ return None
32
+
33
+
34
+ class Message:
35
+ """
36
+ A conversation message. It is used by the streamlit UI to display the messages properly, depending on the sender
37
+ (i.e., user or agent) and the type (string, audio, file, DataFrame, plot, etc.)
38
+
39
+ Args:
40
+ t (MessageType): The type of the message
41
+ content (Any): The message content
42
+ is_user (bool): Whether the message comes from the user (true) or the agent (false)
43
+ timestamp (datetime): The timestamp of the message (when the message was sent)
44
+
45
+ Attributes:
46
+ type (MessageType): The type of the message
47
+ content (Any): The message content
48
+ is_user (bool): Whether the message comes from the user (true) or the agent (false)
49
+ timestamp (datetime): The timestamp of the message (when the message was sent)
50
+ """
51
+
52
+ def __init__(self, t: MessageType, content: Any, is_user: bool, timestamp: datetime):
53
+ self.type: MessageType = t
54
+ self.content: Any = content
55
+ self.is_user: bool = is_user
56
+ self.timestamp: datetime = timestamp
57
+ # TODO: Parse content to specific type (in DB, messages are stored a str)
58
+
59
+ def get_action(self):
60
+ if self.is_user:
61
+ match self.type:
62
+ case MessageType.STR:
63
+ return PayloadAction.USER_MESSAGE
64
+ case MessageType.JSON:
65
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
66
+ case MessageType.MARKDOWN:
67
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
68
+ case MessageType.HTML:
69
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
70
+ case MessageType.FILE:
71
+ return PayloadAction.USER_FILE
72
+ case MessageType.IMAGE:
73
+ return PayloadAction.USER_FILE # TODO: Not implemented
74
+ case MessageType.DATAFRAME:
75
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
76
+ case MessageType.PLOTLY:
77
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
78
+ case MessageType.LOCATION:
79
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
80
+ case MessageType.OPTIONS:
81
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
82
+ case MessageType.AUDIO:
83
+ return PayloadAction.USER_VOICE
84
+ case MessageType.RAG_ANSWER:
85
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
86
+ case MessageType.UI:
87
+ return PayloadAction.USER_MESSAGE # TODO: Not implemented
88
+ else:
89
+ match self.type:
90
+ case MessageType.STR:
91
+ return PayloadAction.AGENT_REPLY_STR
92
+ case MessageType.JSON:
93
+ return PayloadAction.AGENT_REPLY_STR # TODO: Not implemented
94
+ case MessageType.MARKDOWN:
95
+ return PayloadAction.AGENT_REPLY_MARKDOWN
96
+ case MessageType.HTML:
97
+ return PayloadAction.AGENT_REPLY_HTML
98
+ case MessageType.FILE:
99
+ return PayloadAction.AGENT_REPLY_FILE
100
+ case MessageType.IMAGE:
101
+ return PayloadAction.AGENT_REPLY_IMAGE
102
+ case MessageType.DATAFRAME:
103
+ return PayloadAction.AGENT_REPLY_DF
104
+ case MessageType.PLOTLY:
105
+ return PayloadAction.AGENT_REPLY_PLOTLY
106
+ case MessageType.LOCATION:
107
+ return PayloadAction.AGENT_REPLY_LOCATION
108
+ case MessageType.OPTIONS:
109
+ return PayloadAction.AGENT_REPLY_OPTIONS
110
+ case MessageType.AUDIO:
111
+ return PayloadAction.AGENT_REPLY_AUDIO
112
+ case MessageType.RAG_ANSWER:
113
+ return PayloadAction.AGENT_REPLY_RAG
114
+ case MessageType.UI:
115
+ return PayloadAction.AGENT_REPLY_UI