aient 1.1.94__tar.gz → 1.1.95__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 (56) hide show
  1. {aient-1.1.94 → aient-1.1.95}/PKG-INFO +1 -1
  2. {aient-1.1.94 → aient-1.1.95}/aient/architext/architext/core.py +36 -4
  3. {aient-1.1.94 → aient-1.1.95}/aient/architext/test/test.py +65 -3
  4. {aient-1.1.94 → aient-1.1.95}/aient.egg-info/PKG-INFO +1 -1
  5. {aient-1.1.94 → aient-1.1.95}/pyproject.toml +1 -1
  6. {aient-1.1.94 → aient-1.1.95}/LICENSE +0 -0
  7. {aient-1.1.94 → aient-1.1.95}/README.md +0 -0
  8. {aient-1.1.94 → aient-1.1.95}/aient/__init__.py +0 -0
  9. {aient-1.1.94 → aient-1.1.95}/aient/architext/architext/__init__.py +0 -0
  10. {aient-1.1.94 → aient-1.1.95}/aient/architext/test/openai_client.py +0 -0
  11. {aient-1.1.94 → aient-1.1.95}/aient/architext/test/test_save_load.py +0 -0
  12. {aient-1.1.94 → aient-1.1.95}/aient/core/__init__.py +0 -0
  13. {aient-1.1.94 → aient-1.1.95}/aient/core/log_config.py +0 -0
  14. {aient-1.1.94 → aient-1.1.95}/aient/core/models.py +0 -0
  15. {aient-1.1.94 → aient-1.1.95}/aient/core/request.py +0 -0
  16. {aient-1.1.94 → aient-1.1.95}/aient/core/response.py +0 -0
  17. {aient-1.1.94 → aient-1.1.95}/aient/core/test/test_base_api.py +0 -0
  18. {aient-1.1.94 → aient-1.1.95}/aient/core/test/test_geminimask.py +0 -0
  19. {aient-1.1.94 → aient-1.1.95}/aient/core/test/test_image.py +0 -0
  20. {aient-1.1.94 → aient-1.1.95}/aient/core/test/test_payload.py +0 -0
  21. {aient-1.1.94 → aient-1.1.95}/aient/core/utils.py +0 -0
  22. {aient-1.1.94 → aient-1.1.95}/aient/models/__init__.py +0 -0
  23. {aient-1.1.94 → aient-1.1.95}/aient/models/audio.py +0 -0
  24. {aient-1.1.94 → aient-1.1.95}/aient/models/base.py +0 -0
  25. {aient-1.1.94 → aient-1.1.95}/aient/models/chatgpt.py +0 -0
  26. {aient-1.1.94 → aient-1.1.95}/aient/plugins/__init__.py +0 -0
  27. {aient-1.1.94 → aient-1.1.95}/aient/plugins/arXiv.py +0 -0
  28. {aient-1.1.94 → aient-1.1.95}/aient/plugins/config.py +0 -0
  29. {aient-1.1.94 → aient-1.1.95}/aient/plugins/excute_command.py +0 -0
  30. {aient-1.1.94 → aient-1.1.95}/aient/plugins/get_time.py +0 -0
  31. {aient-1.1.94 → aient-1.1.95}/aient/plugins/image.py +0 -0
  32. {aient-1.1.94 → aient-1.1.95}/aient/plugins/list_directory.py +0 -0
  33. {aient-1.1.94 → aient-1.1.95}/aient/plugins/read_file.py +0 -0
  34. {aient-1.1.94 → aient-1.1.95}/aient/plugins/read_image.py +0 -0
  35. {aient-1.1.94 → aient-1.1.95}/aient/plugins/readonly.py +0 -0
  36. {aient-1.1.94 → aient-1.1.95}/aient/plugins/registry.py +0 -0
  37. {aient-1.1.94 → aient-1.1.95}/aient/plugins/run_python.py +0 -0
  38. {aient-1.1.94 → aient-1.1.95}/aient/plugins/websearch.py +0 -0
  39. {aient-1.1.94 → aient-1.1.95}/aient/plugins/write_file.py +0 -0
  40. {aient-1.1.94 → aient-1.1.95}/aient/utils/__init__.py +0 -0
  41. {aient-1.1.94 → aient-1.1.95}/aient/utils/prompt.py +0 -0
  42. {aient-1.1.94 → aient-1.1.95}/aient/utils/scripts.py +0 -0
  43. {aient-1.1.94 → aient-1.1.95}/aient.egg-info/SOURCES.txt +0 -0
  44. {aient-1.1.94 → aient-1.1.95}/aient.egg-info/dependency_links.txt +0 -0
  45. {aient-1.1.94 → aient-1.1.95}/aient.egg-info/requires.txt +0 -0
  46. {aient-1.1.94 → aient-1.1.95}/aient.egg-info/top_level.txt +0 -0
  47. {aient-1.1.94 → aient-1.1.95}/setup.cfg +0 -0
  48. {aient-1.1.94 → aient-1.1.95}/test/test_Web_crawler.py +0 -0
  49. {aient-1.1.94 → aient-1.1.95}/test/test_ddg_search.py +0 -0
  50. {aient-1.1.94 → aient-1.1.95}/test/test_google_search.py +0 -0
  51. {aient-1.1.94 → aient-1.1.95}/test/test_ollama.py +0 -0
  52. {aient-1.1.94 → aient-1.1.95}/test/test_plugin.py +0 -0
  53. {aient-1.1.94 → aient-1.1.95}/test/test_search.py +0 -0
  54. {aient-1.1.94 → aient-1.1.95}/test/test_url.py +0 -0
  55. {aient-1.1.94 → aient-1.1.95}/test/test_whisper.py +0 -0
  56. {aient-1.1.94 → aient-1.1.95}/test/test_yjh.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.1.94
3
+ Version: 1.1.95
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -63,8 +63,11 @@ class Texts(ContextProvider):
63
63
 
64
64
  async def render(self) -> Optional[str]:
65
65
  if self._is_dynamic:
66
- return self._text()
67
- return self._text
66
+ # Ensure dynamic content returns a string, even if empty
67
+ result = self._text()
68
+ return result if result is not None else ""
69
+ # Ensure static content returns a string, even if empty
70
+ return self._text if self._text is not None else ""
68
71
 
69
72
  class Tools(ContextProvider):
70
73
  def __init__(self, tools_json: List[Dict]): super().__init__("tools"); self._tools_json = tools_json
@@ -201,8 +204,37 @@ class Message(ABC):
201
204
  self._parent_messages: Optional['Messages'] = None
202
205
 
203
206
  def _render_content(self) -> str:
204
- blocks = [item.get_content_block() for item in self._items]
205
- return "\n\n".join(b.content for b in blocks if b and b.content)
207
+ # Get all blocks and their provider types first
208
+ blocks_with_types = []
209
+ for item in self._items:
210
+ block = item.get_content_block()
211
+ if block and (block.content or block.content == ""): # Consider blocks with empty string content
212
+ # We only care about non-multimodal Texts providers for concatenation
213
+ provider_type = Texts if type(item) is Texts else type(item)
214
+ blocks_with_types.append((block, provider_type))
215
+
216
+ if not blocks_with_types:
217
+ return ""
218
+
219
+ # Build the final content string
220
+ # Start with the first block's content
221
+ final_content_parts = [blocks_with_types[0][0].content]
222
+
223
+ for i in range(1, len(blocks_with_types)):
224
+ current_block, current_type = blocks_with_types[i]
225
+ _, prev_type = blocks_with_types[i-1]
226
+
227
+ # If both the previous and current rendered blocks are simple text, concatenate them.
228
+ # Otherwise, join with newlines.
229
+ if prev_type is Texts and current_type is Texts:
230
+ separator = ""
231
+ else:
232
+ separator = "\n\n"
233
+
234
+ final_content_parts.append(separator)
235
+ final_content_parts.append(current_block.content)
236
+
237
+ return "".join(final_content_parts)
206
238
 
207
239
  def pop(self, name: str) -> Optional[ContextProvider]:
208
240
  popped_item = None
@@ -143,11 +143,12 @@ class TestContextManagement(unittest.IsolatedAsyncioTestCase):
143
143
  popped_image = messages.pop("image")
144
144
  self.assertIsNotNone(popped_image)
145
145
 
146
- # 3. Render again, should fall back to string content
146
+ # 3. Render again, should fall back to string content and seamlessly join texts
147
147
  rendered_str = messages.render() # No refresh needed
148
148
  content_str = rendered_str[0]['content']
149
149
  self.assertIsInstance(content_str, str)
150
- self.assertEqual(content_str, "Look at this:\n\nAny thoughts?")
150
+ # With the new render logic, adjacent texts are joined with ""
151
+ self.assertEqual(content_str, "Look at this:Any thoughts?")
151
152
 
152
153
  # Clean up
153
154
  import os
@@ -884,7 +885,11 @@ class TestContextManagement(unittest.IsolatedAsyncioTestCase):
884
885
  # If there's no content, the message itself might not be rendered.
885
886
  # Let's assume an empty provider results in the message not rendering.
886
887
  await deferred_text_provider.refresh()
887
- self.assertIsNone(deferred_text_provider.get_content_block())
888
+ # With the new logic, it should return a block with an empty string
889
+ content_block = deferred_text_provider.get_content_block()
890
+ self.assertIsNotNone(content_block)
891
+ self.assertEqual(content_block.content, "")
892
+
888
893
 
889
894
  rendered_initial = await messages.render_latest()
890
895
  self.assertEqual(len(rendered_initial), 0)
@@ -899,6 +904,63 @@ class TestContextManagement(unittest.IsolatedAsyncioTestCase):
899
904
  self.assertEqual(len(rendered_updated), 1)
900
905
  self.assertEqual(rendered_updated[0]['content'], "This is the new content.")
901
906
 
907
+ async def test_z4_fstring_deferred_population(self):
908
+ """测试 f-string 内容是否可以延迟填充"""
909
+ # 1. 初始化一个带有 f-string 占位符的 UserMessage
910
+ # 注意:这里的 f-string 会立即求值,所以我们需要模拟一个假的 Texts 对象
911
+ # 让它看起来像是 f-string 的一部分。正确的用法是直接在 f-string 中创建 Texts 对象。
912
+ user_info_provider = Texts(name="user_info")
913
+
914
+ # This is how the user wants to use it. The f-string is evaluated immediately.
915
+ # The Texts object inside it is created but has no text yet.
916
+ raw_fstring_text = f"""
917
+ <user_info>
918
+ The user's OS version is {Texts(name="os_version")}. The absolute path of the user's workspace is {Texts(name="workspace_path")} which is also the project root directory. The user's shell is {Texts(name="shell")}.
919
+ </user_info>
920
+ """
921
+ # The above f-string evaluates to a string containing reprs of Texts objects.
922
+ # This is not how the library is designed to work.
923
+ # A more correct approach is to build the message programmatically.
924
+
925
+ # Let's test the intended-like usage pattern.
926
+ # We create a template and providers separately.
927
+
928
+ os_provider = Texts(name="os_version")
929
+ path_provider = Texts(name="workspace_path")
930
+ shell_provider = Texts(name="shell")
931
+
932
+ messages = Messages(
933
+ UserMessage(
934
+ "<user_info>\n"
935
+ "The user's OS version is ", os_provider, ". The absolute path of the user's workspace is ",
936
+ path_provider, " which is also the project root directory. The user's shell is ", shell_provider, ".\n"
937
+ "</user_info>"
938
+ )
939
+ )
940
+
941
+ # 2. 初始渲染,此时 placeholders 应该为空字符串
942
+ rendered_initial = await messages.render_latest()
943
+ expected_initial_content = (
944
+ "<user_info>\n"
945
+ "The user's OS version is . The absolute path of the user's workspace is "
946
+ " which is also the project root directory. The user's shell is .\n"
947
+ "</user_info>"
948
+ )
949
+ self.assertEqual(rendered_initial[0]['content'], expected_initial_content)
950
+
951
+ # 3. 获取 providers 并更新它们的值
952
+ messages.provider("os_version").update("macOS 14.5")
953
+ messages.provider("workspace_path").update("/Users/yanyuming/Downloads/GitHub/architext")
954
+ messages.provider("shell").update("/bin/zsh")
955
+
956
+ # 4. 再次渲染,验证 placeholders 是否已填充
957
+ rendered_final = await messages.render_latest()
958
+ final_content = rendered_final[0]['content']
959
+
960
+ self.assertIn("The user's OS version is macOS 14.5.", final_content)
961
+ self.assertIn("The absolute path of the user's workspace is /Users/yanyuming/Downloads/GitHub/architext which is also the project root directory.", final_content)
962
+ self.assertIn("The user's shell is /bin/zsh.", final_content)
963
+
902
964
 
903
965
  # ==============================================================================
904
966
  # 6. 演示
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.1.94
3
+ Version: 1.1.95
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aient"
3
- version = "1.1.94"
3
+ version = "1.1.95"
4
4
  description = "Aient: The Awakening of Agent."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes