mojentic 0.9.0__tar.gz → 1.0.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 (168) hide show
  1. {mojentic-0.9.0/src/mojentic.egg-info → mojentic-1.0.0}/PKG-INFO +44 -26
  2. {mojentic-0.9.0 → mojentic-1.0.0}/README.md +21 -3
  3. {mojentic-0.9.0 → mojentic-1.0.0}/pyproject.toml +23 -23
  4. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/async_dispatcher_example.py +12 -4
  5. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/async_llm_example.py +1 -2
  6. mojentic-1.0.0/src/_examples/broker_as_tool.py +83 -0
  7. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/broker_examples.py +4 -6
  8. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/characterize_ollama.py +1 -1
  9. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/characterize_openai.py +1 -1
  10. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/chat_session.py +1 -1
  11. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/chat_session_with_tool.py +1 -1
  12. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/coding_file_tool.py +1 -3
  13. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/current_datetime_tool_example.py +1 -1
  14. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/embeddings.py +1 -1
  15. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/ephemeral_task_manager_example.py +13 -9
  16. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/fetch_openai_models.py +10 -3
  17. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/file_deduplication.py +6 -6
  18. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/image_analysis.py +2 -3
  19. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/image_broker.py +1 -1
  20. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/image_broker_splat.py +1 -1
  21. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/model_characterization.py +2 -0
  22. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/openai_gateway_enhanced_demo.py +15 -5
  23. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/raw.py +1 -1
  24. mojentic-1.0.0/src/_examples/react/agents/decisioning_agent.py +190 -0
  25. mojentic-1.0.0/src/_examples/react/agents/summarization_agent.py +89 -0
  26. mojentic-1.0.0/src/_examples/react/agents/thinking_agent.py +107 -0
  27. mojentic-1.0.0/src/_examples/react/agents/tool_call_agent.py +83 -0
  28. mojentic-1.0.0/src/_examples/react/formatters.py +64 -0
  29. mojentic-1.0.0/src/_examples/react/models/base.py +78 -0
  30. mojentic-1.0.0/src/_examples/react/models/events.py +96 -0
  31. mojentic-1.0.0/src/_examples/react.py +82 -0
  32. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/recursive_agent.py +1 -1
  33. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/solver_chat_session.py +1 -7
  34. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/streaming.py +7 -4
  35. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/tell_user_example.py +3 -3
  36. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/tracer_demo.py +15 -17
  37. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/tracer_qt_viewer.py +49 -46
  38. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/__init__.py +3 -3
  39. mojentic-1.0.0/src/mojentic/agents/__init__.py +34 -0
  40. mojentic-0.9.0/src/mojentic/agents/agent_broker.py → mojentic-1.0.0/src/mojentic/agents/agent_event_adapter.py +3 -3
  41. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/async_aggregator_agent_spec.py +32 -33
  42. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/async_llm_agent.py +9 -5
  43. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/async_llm_agent_spec.py +21 -22
  44. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/base_async_agent.py +2 -2
  45. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/base_llm_agent.py +6 -2
  46. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/iterative_problem_solver.py +11 -5
  47. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/simple_recursive_agent.py +11 -10
  48. mojentic-1.0.0/src/mojentic/agents/simple_recursive_agent_spec.py +423 -0
  49. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/async_dispatcher.py +0 -1
  50. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/async_dispatcher_spec.py +1 -1
  51. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/context/__init__.py +0 -2
  52. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/dispatcher.py +7 -8
  53. mojentic-1.0.0/src/mojentic/llm/__init__.py +16 -0
  54. mojentic-1.0.0/src/mojentic/llm/gateways/__init__.py +26 -0
  55. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/anthropic.py +1 -0
  56. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/anthropic_messages_adapter.py +0 -1
  57. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/llm_gateway.py +1 -1
  58. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/ollama.py +2 -0
  59. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai.py +62 -58
  60. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_message_adapter_spec.py +3 -3
  61. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_model_registry.py +7 -6
  62. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_model_registry_spec.py +1 -2
  63. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_temperature_handling_spec.py +2 -2
  64. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/llm_broker.py +7 -5
  65. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/llm_broker_spec.py +7 -2
  66. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/message_composers.py +6 -3
  67. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/message_composers_spec.py +5 -1
  68. mojentic-1.0.0/src/mojentic/llm/registry/__init__.py +3 -0
  69. mojentic-1.0.0/src/mojentic/llm/tools/__init__.py +9 -0
  70. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ask_user_tool.py +11 -5
  71. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/current_datetime.py +9 -6
  72. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/date_resolver.py +10 -4
  73. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/date_resolver_spec.py +0 -1
  74. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/append_task_tool.py +4 -1
  75. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/ephemeral_task_list.py +1 -1
  76. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/insert_task_after_tool.py +4 -1
  77. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/prepend_task_tool.py +5 -2
  78. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/file_manager.py +131 -28
  79. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/file_manager_spec.py +0 -3
  80. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/llm_tool.py +1 -1
  81. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/llm_tool_spec.py +0 -2
  82. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/organic_web_search.py +4 -2
  83. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/tell_user_tool.py +6 -2
  84. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/tool_wrapper.py +2 -2
  85. mojentic-1.0.0/src/mojentic/tracer/__init__.py +12 -0
  86. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/event_store.py +7 -8
  87. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/event_store_spec.py +1 -2
  88. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/null_tracer.py +37 -43
  89. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/tracer_events.py +8 -2
  90. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/tracer_events_spec.py +6 -7
  91. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/tracer_system.py +37 -36
  92. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/tracer/tracer_system_spec.py +21 -6
  93. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/utils/__init__.py +1 -1
  94. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/utils/formatting.py +1 -0
  95. {mojentic-0.9.0 → mojentic-1.0.0/src/mojentic.egg-info}/PKG-INFO +44 -26
  96. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic.egg-info/SOURCES.txt +4 -1
  97. mojentic-1.0.0/src/mojentic.egg-info/requires.txt +27 -0
  98. mojentic-0.9.0/src/_examples/broker_as_tool.py +0 -58
  99. mojentic-0.9.0/src/_examples/react/agents/decisioning_agent.py +0 -32
  100. mojentic-0.9.0/src/_examples/react/agents/thinking_agent.py +0 -37
  101. mojentic-0.9.0/src/_examples/react/formatters.py +0 -30
  102. mojentic-0.9.0/src/_examples/react/models/base.py +0 -29
  103. mojentic-0.9.0/src/_examples/react/models/events.py +0 -28
  104. mojentic-0.9.0/src/_examples/react.py +0 -32
  105. mojentic-0.9.0/src/mojentic/agents/__init__.py +0 -16
  106. mojentic-0.9.0/src/mojentic/llm/__init__.py +0 -16
  107. mojentic-0.9.0/src/mojentic/llm/gateways/__init__.py +0 -25
  108. mojentic-0.9.0/src/mojentic/llm/registry/__init__.py +0 -6
  109. mojentic-0.9.0/src/mojentic/llm/tools/__init__.py +0 -18
  110. mojentic-0.9.0/src/mojentic/tracer/__init__.py +0 -21
  111. mojentic-0.9.0/src/mojentic.egg-info/requires.txt +0 -27
  112. {mojentic-0.9.0 → mojentic-1.0.0}/LICENSE.md +0 -0
  113. {mojentic-0.9.0 → mojentic-1.0.0}/setup.cfg +0 -0
  114. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/__init__.py +0 -0
  115. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/broker_image_examples.py +0 -0
  116. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/design_analysis.py +0 -0
  117. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/ensures_files_exist.py +0 -0
  118. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/file_tool.py +0 -0
  119. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/iterative_solver.py +2 -2
  120. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/list_models.py +0 -0
  121. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/oversized_embeddings.py +0 -0
  122. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/react/__init__.py +0 -0
  123. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/react/agents/__init__.py +0 -0
  124. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/react/models/__init__.py +0 -0
  125. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/routed_send_response.py +0 -0
  126. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/simple_llm.py +0 -0
  127. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/simple_llm_repl.py +0 -0
  128. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/simple_structured.py +0 -0
  129. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/simple_tool.py +0 -0
  130. {mojentic-0.9.0 → mojentic-1.0.0}/src/_examples/working_memory.py +0 -0
  131. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/async_aggregator_agent.py +0 -0
  132. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/base_agent.py +0 -0
  133. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/base_llm_agent_spec.py +0 -0
  134. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/correlation_aggregator_agent.py +0 -0
  135. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/agents/output_agent.py +0 -0
  136. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/context/shared_working_memory.py +0 -0
  137. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/event.py +0 -0
  138. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/chat_session.py +0 -0
  139. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/chat_session_spec.py +0 -0
  140. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/embeddings_gateway.py +0 -0
  141. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/file_gateway.py +0 -0
  142. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/models.py +0 -0
  143. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/ollama_messages_adapter.py +0 -0
  144. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/ollama_messages_adapter_spec.py +0 -0
  145. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_messages_adapter.py +0 -0
  146. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/openai_spec.py +0 -0
  147. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/gateways/tokenizer_gateway.py +0 -0
  148. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/registry/llm_registry.py +0 -0
  149. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/registry/models.py +0 -0
  150. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/registry/populate_registry_from_ollama.py +0 -0
  151. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/__init__.py +0 -0
  152. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/append_task_tool_spec.py +0 -0
  153. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/clear_tasks_tool.py +0 -0
  154. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/clear_tasks_tool_spec.py +0 -0
  155. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/complete_task_tool.py +0 -0
  156. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/complete_task_tool_spec.py +0 -0
  157. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/ephemeral_task_list_spec.py +0 -0
  158. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/insert_task_after_tool_spec.py +0 -0
  159. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/list_tasks_tool.py +0 -0
  160. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/list_tasks_tool_spec.py +0 -0
  161. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/prepend_task_tool_spec.py +0 -0
  162. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/start_task_tool.py +0 -0
  163. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/ephemeral_task_manager/start_task_tool_spec.py +0 -0
  164. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/llm/tools/tool_wrapper_spec.py +0 -0
  165. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/router.py +0 -0
  166. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic/router_spec.py +0 -0
  167. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic.egg-info/dependency_links.txt +0 -0
  168. {mojentic-0.9.0 → mojentic-1.0.0}/src/mojentic.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mojentic
3
- Version: 0.9.0
3
+ Version: 1.0.0
4
4
  Summary: Mojentic is an agentic framework that aims to provide a simple and flexible way to assemble teams of agents to solve complex problems.
5
5
  Author-email: Stacey Vetzal <stacey@vetzal.com>
6
6
  Project-URL: Homepage, https://github.com/svetzal/mojentic
@@ -11,32 +11,32 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: pydantic
15
- Requires-Dist: structlog
16
- Requires-Dist: numpy
17
- Requires-Dist: ollama
18
- Requires-Dist: openai
19
- Requires-Dist: anthropic
20
- Requires-Dist: tiktoken
21
- Requires-Dist: parsedatetime
22
- Requires-Dist: pytz
23
- Requires-Dist: serpapi
24
- Requires-Dist: colorama
14
+ Requires-Dist: pydantic>=2.8.0
15
+ Requires-Dist: structlog>=25.5.0
16
+ Requires-Dist: numpy>=2.3.5
17
+ Requires-Dist: ollama>=0.1.6
18
+ Requires-Dist: openai>=2.8.1
19
+ Requires-Dist: anthropic>=0.74.1
20
+ Requires-Dist: tiktoken>=0.12.0
21
+ Requires-Dist: parsedatetime>=2.6
22
+ Requires-Dist: pytz>=2025.2
23
+ Requires-Dist: serpapi>=0.1.5
24
+ Requires-Dist: colorama>=0.4.6
25
25
  Provides-Extra: dev
26
- Requires-Dist: pytest>=7.0.0; extra == "dev"
27
- Requires-Dist: pytest-asyncio; extra == "dev"
28
- Requires-Dist: pytest-spec; extra == "dev"
29
- Requires-Dist: pytest-cov; extra == "dev"
26
+ Requires-Dist: pytest>=9.0.1; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
28
+ Requires-Dist: pytest-spec>=5.2.0; extra == "dev"
29
+ Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
30
30
  Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
31
- Requires-Dist: flake8>=6.0.0; extra == "dev"
31
+ Requires-Dist: flake8>=7.3.0; extra == "dev"
32
32
  Requires-Dist: bandit>=1.7.0; extra == "dev"
33
33
  Requires-Dist: pip-audit>=2.0.0; extra == "dev"
34
- Requires-Dist: mkdocs; extra == "dev"
35
- Requires-Dist: mkdocs-material; extra == "dev"
36
- Requires-Dist: mkdocs-llmstxt; extra == "dev"
37
- Requires-Dist: mkdocstrings[python]; extra == "dev"
38
- Requires-Dist: griffe-fieldz; extra == "dev"
39
- Requires-Dist: pymdown-extensions; extra == "dev"
34
+ Requires-Dist: mkdocs>=1.5.2; extra == "dev"
35
+ Requires-Dist: mkdocs-material>=9.6.10; extra == "dev"
36
+ Requires-Dist: mkdocs-llmstxt>=0.4.0; extra == "dev"
37
+ Requires-Dist: mkdocstrings[python]>=0.21.0; extra == "dev"
38
+ Requires-Dist: griffe-fieldz>=0.3.0; extra == "dev"
39
+ Requires-Dist: pymdown-extensions>=10.3; extra == "dev"
40
40
  Dynamic: license-file
41
41
 
42
42
  # Mojentic
@@ -66,16 +66,26 @@ Mojentic is a framework that provides a simple and flexible way to interact with
66
66
 
67
67
  ## 🔧 Installation
68
68
 
69
+ We recommend using [uv](https://docs.astral.sh/uv/) for fast, reliable Python project management.
70
+
69
71
  ```bash
70
- # Install from PyPI
72
+ # Install from PyPI using uv
73
+ uv pip install mojentic
74
+
75
+ # Or with pip
71
76
  pip install mojentic
72
77
  ```
73
78
 
74
- Or install from source
79
+ Or install from source:
75
80
 
76
81
  ```bash
77
82
  git clone https://github.com/svetzal/mojentic.git
78
83
  cd mojentic
84
+
85
+ # Using uv (recommended)
86
+ uv sync
87
+
88
+ # Or with pip
79
89
  pip install -e .
80
90
  ```
81
91
 
@@ -194,11 +204,19 @@ Visit [the documentation](https://svetzal.github.io/mojentic/) for comprehensive
194
204
  git clone https://github.com/svetzal/mojentic.git
195
205
  cd mojentic
196
206
 
197
- # Install dependencies
207
+ # Using uv (recommended)
208
+ uv sync --extra dev
209
+
210
+ # Or with pip
198
211
  pip install -e ".[dev]"
199
212
 
200
213
  # Run tests
201
214
  pytest
215
+
216
+ # Quality checks
217
+ flake8 src # Linting
218
+ bandit -r src # Security scan
219
+ pip-audit # Dependency vulnerabilities
202
220
  ```
203
221
 
204
222
  ## ✅ Project Status
@@ -25,16 +25,26 @@ Mojentic is a framework that provides a simple and flexible way to interact with
25
25
 
26
26
  ## 🔧 Installation
27
27
 
28
+ We recommend using [uv](https://docs.astral.sh/uv/) for fast, reliable Python project management.
29
+
28
30
  ```bash
29
- # Install from PyPI
31
+ # Install from PyPI using uv
32
+ uv pip install mojentic
33
+
34
+ # Or with pip
30
35
  pip install mojentic
31
36
  ```
32
37
 
33
- Or install from source
38
+ Or install from source:
34
39
 
35
40
  ```bash
36
41
  git clone https://github.com/svetzal/mojentic.git
37
42
  cd mojentic
43
+
44
+ # Using uv (recommended)
45
+ uv sync
46
+
47
+ # Or with pip
38
48
  pip install -e .
39
49
  ```
40
50
 
@@ -153,11 +163,19 @@ Visit [the documentation](https://svetzal.github.io/mojentic/) for comprehensive
153
163
  git clone https://github.com/svetzal/mojentic.git
154
164
  cd mojentic
155
165
 
156
- # Install dependencies
166
+ # Using uv (recommended)
167
+ uv sync --extra dev
168
+
169
+ # Or with pip
157
170
  pip install -e ".[dev]"
158
171
 
159
172
  # Run tests
160
173
  pytest
174
+
175
+ # Quality checks
176
+ flake8 src # Linting
177
+ bandit -r src # Security scan
178
+ pip-audit # Dependency vulnerabilities
161
179
  ```
162
180
 
163
181
  ## ✅ Project Status
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mojentic"
3
- version = "0.9.0"
3
+ version = "1.0.0"
4
4
  authors = [
5
5
  { name = "Stacey Vetzal", email = "stacey@vetzal.com" },
6
6
  ]
@@ -14,35 +14,35 @@ classifiers = [
14
14
  ]
15
15
 
16
16
  dependencies = [
17
- "pydantic",
18
- "structlog",
19
- "numpy",
20
- "ollama",
21
- "openai",
22
- "anthropic",
23
- "tiktoken",
24
- "parsedatetime",
25
- "pytz",
26
- "serpapi",
27
- "colorama",
17
+ "pydantic>=2.8.0",
18
+ "structlog>=25.5.0",
19
+ "numpy>=2.3.5",
20
+ "ollama>=0.1.6",
21
+ "openai>=2.8.1",
22
+ "anthropic>=0.74.1",
23
+ "tiktoken>=0.12.0",
24
+ "parsedatetime>=2.6",
25
+ "pytz>=2025.2",
26
+ "serpapi>=0.1.5",
27
+ "colorama>=0.4.6",
28
28
  ]
29
29
 
30
30
  [project.optional-dependencies]
31
31
  dev = [
32
- "pytest>=7.0.0",
33
- "pytest-asyncio",
34
- "pytest-spec",
35
- "pytest-cov",
32
+ "pytest>=9.0.1",
33
+ "pytest-asyncio>=1.3.0",
34
+ "pytest-spec>=5.2.0",
35
+ "pytest-cov>=7.0.0",
36
36
  "pytest-mock>=3.10.0",
37
- "flake8>=6.0.0",
37
+ "flake8>=7.3.0",
38
38
  "bandit>=1.7.0",
39
39
  "pip-audit>=2.0.0",
40
- "mkdocs",
41
- "mkdocs-material",
42
- "mkdocs-llmstxt",
43
- "mkdocstrings[python]",
44
- "griffe-fieldz",
45
- "pymdown-extensions",
40
+ "mkdocs>=1.5.2",
41
+ "mkdocs-material>=9.6.10",
42
+ "mkdocs-llmstxt>=0.4.0",
43
+ "mkdocstrings[python]>=0.21.0",
44
+ "griffe-fieldz>=0.3.0",
45
+ "pymdown-extensions>=10.3",
46
46
  ]
47
47
 
48
48
  [build-system]
@@ -62,7 +62,11 @@ class TextAnalyzerAgent(BaseAsyncLLMAgent):
62
62
  def __init__(self, llm: LLMBroker):
63
63
  super().__init__(
64
64
  llm=llm,
65
- behaviour="You are a text analysis assistant. Your job is to provide a detailed analysis of the given text, including key themes, structure, and notable elements.",
65
+ behaviour=(
66
+ "You are a text analysis assistant. "
67
+ "Your job is to provide a detailed analysis of the given text, "
68
+ "including key themes, structure, and notable elements."
69
+ ),
66
70
  response_model=AnalysisResponse
67
71
  )
68
72
 
@@ -93,7 +97,11 @@ class TextSummarizerAgent(BaseAsyncLLMAgent):
93
97
  def __init__(self, llm: LLMBroker):
94
98
  super().__init__(
95
99
  llm=llm,
96
- behaviour="You are a text summarization assistant. Your job is to provide concise, accurate summaries of texts while preserving the key information and main points.",
100
+ behaviour=(
101
+ "You are a text summarization assistant. "
102
+ "Your job is to provide concise, accurate summaries of texts "
103
+ "while preserving the key information and main points."
104
+ ),
97
105
  response_model=SummaryResponse
98
106
  )
99
107
 
@@ -143,8 +151,8 @@ Analysis: {analysis_event.analysis}
143
151
 
144
152
  Summary: {summary_event.summary}
145
153
 
146
- Please create a well-structured, insightful report that integrates the analysis and summary,
147
- highlighting the most important aspects of the text. The report should provide a comprehensive
154
+ Please create a well-structured, insightful report that integrates the analysis and summary,
155
+ highlighting the most important aspects of the text. The report should provide a comprehensive
148
156
  understanding of the text's content, structure, and significance.
149
157
  """
150
158
  # Create a temporary LLM agent to generate the response
@@ -5,14 +5,13 @@ This script shows how to create and use asynchronous LLM agents with the AsyncDi
5
5
  """
6
6
 
7
7
  import asyncio
8
- from typing import List, Optional
8
+ from typing import List
9
9
 
10
10
  from pydantic import BaseModel, Field
11
11
 
12
12
  from mojentic.agents.async_aggregator_agent import AsyncAggregatorAgent
13
13
  from mojentic.agents.async_llm_agent import BaseAsyncLLMAgent
14
14
  from mojentic.async_dispatcher import AsyncDispatcher
15
- from mojentic.context.shared_working_memory import SharedWorkingMemory
16
15
  from mojentic.event import Event
17
16
  from mojentic.llm import LLMBroker
18
17
  from mojentic.router import Router
@@ -0,0 +1,83 @@
1
+ import os
2
+ from mojentic.agents.base_llm_agent import BaseLLMAgent
3
+ from mojentic.llm.llm_broker import LLMBroker
4
+ from mojentic.llm.tools.date_resolver import ResolveDateTool
5
+ from mojentic.llm.tools.file_manager import ListFilesTool, ReadFileTool, WriteFileTool, FilesystemGateway
6
+ from mojentic.llm.tools.tool_wrapper import ToolWrapper
7
+
8
+ #
9
+ # This is largely a fail, but it was interesting.
10
+ #
11
+
12
+ temporal_specialist = BaseLLMAgent(
13
+ llm=LLMBroker(model="qwen3:7b"),
14
+ tools=[ResolveDateTool()],
15
+ behaviour=(
16
+ "You are a historian and sociologist who focuses on sorting out temporal events, "
17
+ "determining what happened or will happen when."
18
+ )
19
+ )
20
+
21
+ if not os.path.exists("local"):
22
+ os.mkdir("local")
23
+
24
+ # Create a filesystem gateway for the local directory
25
+ fs = FilesystemGateway(base_path="local")
26
+
27
+ knowledge_specialist = BaseLLMAgent(
28
+ llm=LLMBroker(model="qwen3:32b"),
29
+ tools=[
30
+ ListFilesTool(fs),
31
+ ReadFileTool(fs),
32
+ WriteFileTool(fs),
33
+ ],
34
+ behaviour=(
35
+ "You are a knowledge management agent who focuses on sorting out facts and information, "
36
+ "able to organize elemental ideas and make connections between them. You can list files "
37
+ "to find out where you stored information, read files to review that information, and "
38
+ "write files to store that information for later retrieval."
39
+ )
40
+ )
41
+
42
+
43
+ coordinator = BaseLLMAgent(
44
+ llm=LLMBroker(model="qwen3:32b"),
45
+ behaviour="You are a coordinator who can manage multiple agents and delegate tasks to them to solve problems.",
46
+ tools=[
47
+ ToolWrapper(
48
+ temporal_specialist,
49
+ "temporal_specialist",
50
+ "A historian and sociologist who focuses on sorting out temporal events, figuring out "
51
+ "dates, determining what happened or will happen when."
52
+ ),
53
+ ToolWrapper(
54
+ knowledge_specialist,
55
+ "knowledge_specialist",
56
+ "A knowledge management specialist who focuses on sorting out facts and information, "
57
+ "able to organize elemental ideas and make connections between them. Can list files to "
58
+ "find out where you stored information, read files to review that information, and "
59
+ "write files to store that information for later retrieval."
60
+ ),
61
+ ]
62
+ )
63
+
64
+ result = coordinator.generate_response(
65
+ """
66
+ I have several things I need to do this week:
67
+
68
+ - On Monday, I need to ensure that I have called Scotiabank and ordered replacement cards for "
69
+ "my current, credit, and line of credit accounts.
70
+ - On Wednesday, I need to drive into Toronto for work. While in Toronto I need to pick up "
71
+ "razors. I need to make sure I see Gregg, Britney and Vikram.
72
+ - On Thursday, I need to ensure I'm up by 7am so that I can be showered and ready for work by 9.
73
+ - On Friday, I need to ensure that I have my laundry done and my bags packed for my trip to "
74
+ "Ottawa.
75
+
76
+ Create me a markdown file for each day of the week, named "YYYY-MM-DD-ToDo.md" where the date "
77
+ "is the date of that day.
78
+ Make a list of to-do items in the markdown file, and add a section for the day's daily notes that "
79
+ "I can fill out each day.
80
+ """
81
+ )
82
+
83
+ print(result)
@@ -1,18 +1,16 @@
1
1
  import logging
2
2
  import os
3
-
4
- from mojentic.llm import LLMBroker
5
- from mojentic.llm.gateways import OpenAIGateway
6
-
7
- logging.basicConfig(level=logging.WARN)
8
-
9
3
  from pathlib import Path
10
4
 
11
5
  from pydantic import BaseModel, Field
12
6
 
7
+ from mojentic.llm import LLMBroker
8
+ from mojentic.llm.gateways import OpenAIGateway
13
9
  from mojentic.llm.gateways.models import LLMMessage
14
10
  from mojentic.llm.tools.date_resolver import ResolveDateTool
15
11
 
12
+ logging.basicConfig(level=logging.WARN)
13
+
16
14
 
17
15
  def openai_llm(model="gpt-5"):
18
16
  api_key = os.getenv("OPENAI_API_KEY")
@@ -1,7 +1,7 @@
1
1
  from ollama import chat
2
2
  from pydantic import BaseModel, Field
3
3
 
4
- from mojentic.llm.gateways.models import LLMMessage, MessageRole
4
+ from mojentic.llm.gateways.models import LLMMessage
5
5
  from mojentic.llm.gateways.ollama import OllamaGateway
6
6
  from mojentic.llm.tools.date_resolver import ResolveDateTool
7
7
 
@@ -2,7 +2,7 @@ import os
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
- from mojentic.llm.gateways.models import LLMMessage, MessageRole
5
+ from mojentic.llm.gateways.models import LLMMessage
6
6
  from mojentic.llm.gateways.openai import OpenAIGateway
7
7
 
8
8
  api_key = os.getenv("OPENAI_API_KEY")
@@ -9,4 +9,4 @@ while True:
9
9
  break
10
10
  else:
11
11
  response = chat_session.send(query)
12
- print(response)
12
+ print(response)
@@ -10,4 +10,4 @@ while True:
10
10
  break
11
11
  else:
12
12
  response = chat_session.send(query)
13
- print(response)
13
+ print(response)
@@ -30,7 +30,7 @@ from mojentic.llm.tools.file_manager import (
30
30
  EditFileWithDiffTool, CreateDirectoryTool, FilesystemGateway
31
31
  )
32
32
 
33
- base_dir = Path(__file__).parent.parent.parent.parent / "code-playground2"
33
+ base_dir = Path(__file__).parent.parent.parent.parent / "code-playground3"
34
34
 
35
35
  # Initialize the LLM broker
36
36
 
@@ -38,9 +38,7 @@ api_key = os.getenv("OPENAI_API_KEY")
38
38
  gateway = OpenAIGateway(api_key)
39
39
  llm = LLMBroker(model="o4-mini", gateway=gateway)
40
40
 
41
- # llm = LLMBroker("qwen3-coder:30b")
42
41
  llm = LLMBroker("qwen3-coder:30b")
43
- # llm = LLMBroker(model="qwen3-128k:32b")
44
42
 
45
43
  # Create a filesystem gateway for the sandbox
46
44
  fs = FilesystemGateway(base_path=str(base_dir))
@@ -25,4 +25,4 @@ result = llm.generate(
25
25
  )
26
26
 
27
27
  print("\nLLM Response with custom format:")
28
- print(result)
28
+ print(result)
@@ -6,4 +6,4 @@ ollama = OllamaGateway()
6
6
  print(len(ollama.calculate_embeddings("Hello, world!")))
7
7
 
8
8
  openai = OpenAIGateway(os.environ["OPENAI_API_KEY"])
9
- print(len(openai.calculate_embeddings("Hello, world!")))
9
+ print(len(openai.calculate_embeddings("Hello, world!")))
@@ -2,13 +2,6 @@
2
2
  Example script demonstrating the usage of the ephemeral task manager tools.
3
3
  """
4
4
  import logging
5
- import os
6
-
7
- from mojentic.llm.gateways import OpenAIGateway
8
-
9
- logging.basicConfig(
10
- level=logging.WARN
11
- )
12
5
 
13
6
  from mojentic.llm import LLMBroker
14
7
  from mojentic.llm.gateways.models import LLMMessage
@@ -24,13 +17,24 @@ from mojentic.llm.tools.ephemeral_task_manager import (
24
17
  )
25
18
  from mojentic.llm.tools.tell_user_tool import TellUserTool
26
19
 
20
+ logging.basicConfig(
21
+ level=logging.WARN
22
+ )
23
+
27
24
  # llm = LLMBroker(model="qwen3:30b-a3b-q4_K_M")
28
25
  # llm = LLMBroker(model="qwen3:32b")
29
26
  llm = LLMBroker(model="qwen3:7b")
30
27
  # llm = LLMBroker(model="qwen3:72b")
31
28
  # llm = LLMBroker(model="o4-mini", gateway=OpenAIGateway(os.environ["OPENAI_API_KEY"]))
32
29
  message = LLMMessage(
33
- content="I want you to count from 1 to 10. Break that request down into individual tasks, track them using available tools, and perform them one by one until you're finished. Interrupt me to tell the user as you complete every task.")
30
+ content=(
31
+ "I want you to count from 1 to 10. "
32
+ "Break that request down into individual tasks, "
33
+ "track them using available tools, "
34
+ "and perform them one by one until you're finished. "
35
+ "Interrupt me to tell the user as you complete every task."
36
+ )
37
+ )
34
38
  task_list = EphemeralTaskList()
35
39
  tools = [
36
40
  AppendTaskTool(task_list),
@@ -45,4 +49,4 @@ tools = [
45
49
 
46
50
  result = llm.generate(messages=[message], tools=tools, temperature=0.0)
47
51
  print(result)
48
- print(task_list.list_tasks())
52
+ print(task_list.list_tasks())
@@ -5,6 +5,7 @@ Script to fetch current OpenAI models and update the registry with up-to-date mo
5
5
  import os
6
6
  from mojentic.llm.gateways.openai import OpenAIGateway
7
7
 
8
+
8
9
  def fetch_current_openai_models():
9
10
  """Fetch the current list of OpenAI models."""
10
11
  api_key = os.getenv("OPENAI_API_KEY")
@@ -20,6 +21,7 @@ def fetch_current_openai_models():
20
21
  print(f"ERROR: Failed to fetch models from OpenAI API: {e}")
21
22
  return None
22
23
 
24
+
23
25
  def categorize_models(models):
24
26
  """Categorize models by type based on naming patterns."""
25
27
  reasoning_models = []
@@ -32,7 +34,7 @@ def categorize_models(models):
32
34
 
33
35
  # Reasoning models: o1, o3, o4, and gpt-5 series
34
36
  if (any(pattern in model_lower for pattern in ['o1-', 'o3-', 'o4-', 'gpt-5']) or
35
- model_lower in ['o1', 'o3', 'o4', 'gpt-5']):
37
+ model_lower in ['o1', 'o3', 'o4', 'gpt-5']):
36
38
  reasoning_models.append(model)
37
39
  elif 'embedding' in model_lower:
38
40
  embedding_models.append(model)
@@ -48,6 +50,7 @@ def categorize_models(models):
48
50
  'other': sorted(other_models)
49
51
  }
50
52
 
53
+
51
54
  def print_model_lists(categorized_models):
52
55
  """Print the categorized models in a format ready for the registry."""
53
56
  print("=== Current OpenAI Models ===\n")
@@ -84,6 +87,7 @@ def print_model_lists(categorized_models):
84
87
  print(f'# "{model}",')
85
88
  print("# ]\n")
86
89
 
90
+
87
91
  if __name__ == "__main__":
88
92
  print("Fetching current OpenAI models...")
89
93
  models = fetch_current_openai_models()
@@ -99,6 +103,9 @@ if __name__ == "__main__":
99
103
  print(f"Embedding models: {len(categorized['embedding'])}")
100
104
  print(f"Other models: {len(categorized['other'])}")
101
105
 
102
- print("\nCopy the model lists above and update the _initialize_default_models() method in openai_model_registry.py")
106
+ print(
107
+ "\nCopy the model lists above and update the "
108
+ "_initialize_default_models() method in openai_model_registry.py"
109
+ )
103
110
  else:
104
- print("Failed to fetch models. Please check your API key and try again.")
111
+ print("Failed to fetch models. Please check your API key and try again.")
@@ -14,9 +14,9 @@ message_builder.add_images(image_path, image_path) # Adding the same image twic
14
14
 
15
15
  # Build the message and check the number of images
16
16
  message = message_builder.build()
17
- print(f"Number of images in message: {len(message.image_paths)}")
18
- print(f"Expected number of images: 1")
19
- print(f"De-duplication working: {len(message.image_paths) == 1}")
17
+ print("Number of images in message: {len(message.image_paths)}")
18
+ print("Expected number of images: 1")
19
+ print("De-duplication working: {len(message.image_paths) == 1}")
20
20
 
21
21
  # Test de-duplication of files
22
22
  print("\nTesting file de-duplication:")
@@ -31,8 +31,8 @@ message_builder.add_files(file_path, file_path) # Adding the same file twice mo
31
31
  # Build the message and check the number of files
32
32
  message = message_builder.build()
33
33
  # Since we're using the file content in the message, we need to check file_paths directly
34
- print(f"Number of files in message_builder.file_paths: {len(message_builder.file_paths)}")
35
- print(f"Expected number of files: 1")
36
- print(f"De-duplication working: {len(message_builder.file_paths) == 1}")
34
+ print("Number of files in message_builder.file_paths: {len(message_builder.file_paths)}")
35
+ print("Expected number of files: 1")
36
+ print("De-duplication working: {len(message_builder.file_paths) == 1}")
37
37
 
38
38
  print("\nTest completed.")
@@ -1,7 +1,6 @@
1
- import os
2
1
  from pathlib import Path
3
2
 
4
- from mojentic.llm.gateways import OllamaGateway, OpenAIGateway
3
+ from mojentic.llm.gateways import OllamaGateway
5
4
  from mojentic.llm.gateways.models import LLMMessage
6
5
 
7
6
  llmg = OllamaGateway()
@@ -18,4 +17,4 @@ response = llmg.complete(
18
17
  ],
19
18
  )
20
19
 
21
- print(response)
20
+ print(response)
@@ -1,7 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
3
  from mojentic.llm import LLMBroker
4
- from mojentic.llm.message_composers import MessagesBuilder, MessageBuilder
4
+ from mojentic.llm.message_composers import MessageBuilder
5
5
 
6
6
  llm = LLMBroker(model="gemma3:27b")
7
7
 
@@ -47,4 +47,4 @@ print(f"Example 4: Added {len(message4.image_paths)} image(s)")
47
47
  # Generate a response using one of the messages (e.g., message1)
48
48
  print("\nGenerating response for Example 1...")
49
49
  result = llm.generate(messages=[message1])
50
- print(result)
50
+ print(result)
@@ -2,6 +2,7 @@ import os
2
2
  from mojentic.llm.gateways.openai import OpenAIGateway
3
3
  from mojentic.llm.gateways.models import LLMMessage, MessageRole
4
4
 
5
+
5
6
  def check_model_characterization():
6
7
  """
7
8
  Test the model characterization functionality with different OpenAI models.
@@ -69,5 +70,6 @@ def check_model_characterization():
69
70
  print("\n" + "=" * 60)
70
71
  print("Model characterization test completed!")
71
72
 
73
+
72
74
  if __name__ == "__main__":
73
75
  check_model_characterization()