mojentic 0.5.0__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. {mojentic-0.5.0/src/mojentic.egg-info → mojentic-0.5.2}/PKG-INFO +1 -1
  2. {mojentic-0.5.0 → mojentic-0.5.2}/pyproject.toml +1 -1
  3. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/message_composers.py +53 -1
  4. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/message_composers_spec.py +89 -0
  5. {mojentic-0.5.0 → mojentic-0.5.2/src/mojentic.egg-info}/PKG-INFO +1 -1
  6. {mojentic-0.5.0 → mojentic-0.5.2}/LICENSE.md +0 -0
  7. {mojentic-0.5.0 → mojentic-0.5.2}/README.md +0 -0
  8. {mojentic-0.5.0 → mojentic-0.5.2}/setup.cfg +0 -0
  9. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/__init__.py +0 -0
  10. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/broker_as_tool.py +0 -0
  11. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/broker_examples.py +0 -0
  12. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/characterize_ollama.py +0 -0
  13. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/characterize_openai.py +0 -0
  14. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/chat_session.py +0 -0
  15. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/chat_session_with_tool.py +0 -0
  16. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/coding_file_tool.py +0 -0
  17. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/current_datetime_tool_example.py +0 -0
  18. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/design_analysis.py +0 -0
  19. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/embeddings.py +0 -0
  20. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/ensures_files_exist.py +0 -0
  21. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/file_deduplication.py +0 -0
  22. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/file_tool.py +0 -0
  23. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/image_analysis.py +0 -0
  24. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/image_broker.py +0 -0
  25. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/image_broker_splat.py +0 -0
  26. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/iterative_solver.py +0 -0
  27. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/list_models.py +0 -0
  28. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/raw.py +0 -0
  29. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/__init__.py +0 -0
  30. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/agents/__init__.py +0 -0
  31. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/agents/decisioning_agent.py +0 -0
  32. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/agents/thinking_agent.py +0 -0
  33. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/formatters.py +0 -0
  34. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/models/__init__.py +0 -0
  35. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/models/base.py +0 -0
  36. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react/models/events.py +0 -0
  37. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/react.py +0 -0
  38. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/recursive_agent.py +0 -0
  39. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/routed_send_response.py +0 -0
  40. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/simple_llm.py +0 -0
  41. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/simple_llm_repl.py +0 -0
  42. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/simple_structured.py +0 -0
  43. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/simple_tool.py +0 -0
  44. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/solver_chat_session.py +0 -0
  45. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/streaming.py +0 -0
  46. {mojentic-0.5.0 → mojentic-0.5.2}/src/_examples/working_memory.py +0 -0
  47. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/__init__.py +0 -0
  48. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/__init__.py +0 -0
  49. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/agent_broker.py +0 -0
  50. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/base_agent.py +0 -0
  51. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/base_llm_agent.py +0 -0
  52. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/base_llm_agent_spec.py +0 -0
  53. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/correlation_aggregator_agent.py +0 -0
  54. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/iterative_problem_solver.py +0 -0
  55. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/output_agent.py +0 -0
  56. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/agents/simple_recursive_agent.py +0 -0
  57. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/audit/event_store.py +0 -0
  58. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/audit/event_store_spec.py +0 -0
  59. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/context/__init__.py +0 -0
  60. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/context/shared_working_memory.py +0 -0
  61. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/dispatcher.py +0 -0
  62. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/event.py +0 -0
  63. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/__init__.py +0 -0
  64. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/chat_session.py +0 -0
  65. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/chat_session_spec.py +0 -0
  66. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/__init__.py +0 -0
  67. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/anthropic.py +0 -0
  68. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/anthropic_messages_adapter.py +0 -0
  69. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/embeddings_gateway.py +0 -0
  70. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/file_gateway.py +0 -0
  71. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/llm_gateway.py +0 -0
  72. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/models.py +0 -0
  73. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/ollama.py +0 -0
  74. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/ollama_messages_adapter.py +0 -0
  75. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/ollama_messages_adapter_spec.py +0 -0
  76. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/openai.py +0 -0
  77. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/openai_message_adapter_spec.py +0 -0
  78. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/openai_messages_adapter.py +0 -0
  79. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/gateways/tokenizer_gateway.py +0 -0
  80. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/llm_broker.py +0 -0
  81. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/llm_broker_spec.py +0 -0
  82. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/registry/__init__.py +0 -0
  83. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/registry/llm_registry.py +0 -0
  84. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/registry/models.py +0 -0
  85. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/registry/populate_registry_from_ollama.py +0 -0
  86. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/__init__.py +0 -0
  87. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/ask_user_tool.py +0 -0
  88. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/current_datetime.py +0 -0
  89. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/date_resolver.py +0 -0
  90. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/date_resolver_spec.py +0 -0
  91. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/file_manager.py +0 -0
  92. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/llm_tool.py +0 -0
  93. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/tool_wrapper.py +0 -0
  94. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/tool_wrapper_spec.py +0 -0
  95. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/llm/tools/web_search.py +0 -0
  96. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/router.py +0 -0
  97. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/router_spec.py +0 -0
  98. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/utils/__init__.py +0 -0
  99. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic/utils/formatting.py +0 -0
  100. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic.egg-info/SOURCES.txt +0 -0
  101. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic.egg-info/dependency_links.txt +0 -0
  102. {mojentic-0.5.0 → mojentic-0.5.2}/src/mojentic.egg-info/requires.txt +0 -0
  103. {mojentic-0.5.0 → mojentic-0.5.2}/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.5.0
3
+ Version: 0.5.2
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/mojility/mojentic
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mojentic"
3
- version = "0.5.0"
3
+ version = "0.5.2"
4
4
  authors = [
5
5
  { name = "Stacey Vetzal", email = "stacey@vetzal.com" },
6
6
  ]
@@ -126,7 +126,7 @@ class MessageBuilder():
126
126
  content = self.file_gateway.read(file_path)
127
127
  return (f"File: {file_path}\n"
128
128
  f"```{self.type_sensor.get_language(file_path)}\n"
129
- f"{content}\n"
129
+ f"{content.strip()}\n"
130
130
  f"```\n")
131
131
 
132
132
 
@@ -253,6 +253,58 @@ class MessageBuilder():
253
253
 
254
254
  return self
255
255
 
256
+ def load_content(self, file_path: Union[str, Path], template_values: Optional[Dict[str, Union[str, Path]]] = None) -> "MessageBuilder":
257
+ """
258
+ Load content from a file into the content field of the MessageBuilder.
259
+
260
+ This method reads the content of the specified file and sets it as the content
261
+ of the MessageBuilder, replacing any existing content. If template_values is provided,
262
+ placeholders in the content will be replaced with the corresponding values.
263
+
264
+ Parameters
265
+ ----------
266
+ file_path : Union[str, Path]
267
+ Path to the file to load content from. Can be a string or Path object.
268
+ template_values : Optional[Dict[str, Union[str, Path]]], optional
269
+ Dictionary of values used to replace placeholders in the content.
270
+ For example, if the content contains "{greeting}" and template_values is
271
+ {"greeting": "Hello, World!"}, then "{greeting}" will be replaced with
272
+ "Hello, World!".
273
+ If a value is a Path object, it will be treated as a file reference and the
274
+ content of that file will be used to replace the placeholder.
275
+ Default is None.
276
+
277
+ Returns
278
+ -------
279
+ MessageBuilder
280
+ The MessageBuilder instance for method chaining.
281
+
282
+ Raises
283
+ ------
284
+ FileNotFoundError
285
+ If the specified file does not exist.
286
+ """
287
+ if isinstance(file_path, str):
288
+ file_path = Path(file_path)
289
+ if not self.file_gateway.exists(file_path):
290
+ raise FileNotFoundError(f"File not found: {file_path}")
291
+ self.content = self.file_gateway.read(file_path)
292
+
293
+ # Replace placeholders with template values if provided
294
+ if template_values:
295
+ for key, value in template_values.items():
296
+ if isinstance(value, Path):
297
+ # If value is a Path, read the content of the file
298
+ if not self.file_gateway.exists(value):
299
+ raise FileNotFoundError(f"Template file not found: {value}")
300
+ file_content = self.file_gateway.read(value).strip()
301
+ self.content = self.content.replace(f"{{{key}}}", file_content)
302
+ else:
303
+ # If value is a string, use it directly
304
+ self.content = self.content.replace(f"{{{key}}}", value)
305
+
306
+ return self
307
+
256
308
  def build(self) -> LLMMessage:
257
309
  """
258
310
  Build the final LLMMessage from the accumulated content, images, and files.
@@ -14,6 +14,14 @@ def file_gateway(mocker):
14
14
  file_gateway.is_binary.return_value = False
15
15
  return file_gateway
16
16
 
17
+ @pytest.fixture
18
+ def file_path():
19
+ return Path("/path/to/file.txt")
20
+
21
+ @pytest.fixture
22
+ def whitespace_file_content():
23
+ return "\n\n \n test file content with whitespace \n\n \n"
24
+
17
25
 
18
26
  @pytest.fixture
19
27
  def message_builder(file_gateway):
@@ -144,6 +152,30 @@ class DescribeMessageBuilder:
144
152
  assert "test file content" in result
145
153
  assert "```" in result
146
154
 
155
+ def should_strip_whitespace_from_file_content(self, message_builder, file_gateway, file_path, whitespace_file_content, mocker):
156
+ """
157
+ Given a MessageBuilder
158
+ When _file_content_partial is called with content that has whitespace above and below
159
+ Then it should strip the whitespace when putting it in code fences
160
+ """
161
+ # Use the fixtures instead of creating file path and content directly
162
+ file_gateway.read.return_value = whitespace_file_content
163
+ mocker.patch.object(message_builder.type_sensor, 'get_language', return_value='text')
164
+
165
+ result = message_builder._file_content_partial(file_path)
166
+
167
+ file_gateway.read.assert_called_with(file_path)
168
+ assert "File: /path/to/file.txt" in result
169
+ assert "```text" in result
170
+ assert "test file content with whitespace" in result
171
+ assert "```" in result
172
+ # Verify that the content in the code fence doesn't have leading/trailing whitespace
173
+ lines = result.split('\n')
174
+ code_fence_start_index = lines.index("```text")
175
+ code_fence_end_index = lines.index("```", code_fence_start_index + 1)
176
+ code_content = lines[code_fence_start_index + 1:code_fence_end_index]
177
+ assert code_content == ["test file content with whitespace"]
178
+
147
179
  class DescribeAddImageMethod:
148
180
  """
149
181
  Specifications for the add_image method
@@ -238,6 +270,63 @@ class DescribeMessageBuilder:
238
270
  assert matching_files[0] in message_builder.image_paths
239
271
  assert matching_files[1] in message_builder.image_paths
240
272
 
273
+ class DescribeLoadContentMethod:
274
+ """
275
+ Specifications for the load_content method
276
+ """
277
+
278
+ def should_load_content_from_file(self, message_builder, file_gateway, file_path):
279
+ """
280
+ Given a MessageBuilder
281
+ When load_content is called with a file path
282
+ Then it should load the content from the file and set it as the content
283
+ """
284
+ result = message_builder.load_content(file_path)
285
+
286
+ file_gateway.read.assert_called_once_with(file_path)
287
+ assert message_builder.content == "test file content"
288
+ assert result is message_builder # Returns self for method chaining
289
+
290
+ def should_convert_string_path_to_path_object(self, message_builder, file_gateway):
291
+ """
292
+ Given a MessageBuilder
293
+ When load_content is called with a string path
294
+ Then it should convert the string to a Path object
295
+ """
296
+ file_path_str = "/path/to/file.txt"
297
+
298
+ message_builder.load_content(file_path_str)
299
+
300
+ file_gateway.read.assert_called_once_with(Path(file_path_str))
301
+
302
+ def should_raise_error_if_file_not_found(self, message_builder, file_gateway, file_path):
303
+ """
304
+ Given a MessageBuilder
305
+ When load_content is called with a non-existent file
306
+ Then it should raise a FileNotFoundError
307
+ """
308
+ file_gateway.exists.return_value = False
309
+
310
+ with pytest.raises(FileNotFoundError):
311
+ message_builder.load_content(file_path)
312
+
313
+ def should_replace_placeholders_with_template_values(self, message_builder, file_gateway, file_path):
314
+ """
315
+ Given a MessageBuilder
316
+ When load_content is called with a file path and template values
317
+ Then it should replace placeholders in the content with the corresponding values
318
+ """
319
+ # Set up the file content with placeholders
320
+ file_gateway.read.return_value = "Hello, {name}! Today is {day}."
321
+
322
+ # Call load_content with template values
323
+ template_values = {"name": "World", "day": "Monday"}
324
+ result = message_builder.load_content(file_path, template_values)
325
+
326
+ # Verify that placeholders were replaced
327
+ assert message_builder.content == "Hello, World! Today is Monday."
328
+ assert result is message_builder # Returns self for method chaining
329
+
241
330
 
242
331
  class DescribeTypeSensor:
243
332
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mojentic
3
- Version: 0.5.0
3
+ Version: 0.5.2
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/mojility/mojentic
File without changes
File without changes
File without changes
File without changes
File without changes