lionagi 0.1.2__py3-none-any.whl → 0.2.1__py3-none-any.whl

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 (268) hide show
  1. lionagi/__init__.py +60 -5
  2. lionagi/core/__init__.py +0 -25
  3. lionagi/core/_setting/_setting.py +59 -0
  4. lionagi/core/action/__init__.py +14 -0
  5. lionagi/core/action/function_calling.py +136 -0
  6. lionagi/core/action/manual.py +1 -0
  7. lionagi/core/action/node.py +109 -0
  8. lionagi/core/action/tool.py +114 -0
  9. lionagi/core/action/tool_manager.py +356 -0
  10. lionagi/core/agent/base_agent.py +27 -13
  11. lionagi/core/agent/eval/evaluator.py +1 -0
  12. lionagi/core/agent/eval/vote.py +40 -0
  13. lionagi/core/agent/learn/learner.py +59 -0
  14. lionagi/core/agent/plan/unit_template.py +1 -0
  15. lionagi/core/collections/__init__.py +17 -0
  16. lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
  17. lionagi/core/collections/abc/__init__.py +53 -0
  18. lionagi/core/collections/abc/component.py +615 -0
  19. lionagi/core/collections/abc/concepts.py +297 -0
  20. lionagi/core/collections/abc/exceptions.py +150 -0
  21. lionagi/core/collections/abc/util.py +45 -0
  22. lionagi/core/collections/exchange.py +161 -0
  23. lionagi/core/collections/flow.py +426 -0
  24. lionagi/core/collections/model.py +419 -0
  25. lionagi/core/collections/pile.py +913 -0
  26. lionagi/core/collections/progression.py +236 -0
  27. lionagi/core/collections/util.py +64 -0
  28. lionagi/core/director/direct.py +314 -0
  29. lionagi/core/director/director.py +2 -0
  30. lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
  31. lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
  32. lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
  33. lionagi/core/executor/base_executor.py +90 -0
  34. lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
  35. lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
  36. lionagi/core/generic/__init__.py +3 -33
  37. lionagi/core/generic/edge.py +29 -79
  38. lionagi/core/generic/edge_condition.py +16 -0
  39. lionagi/core/generic/graph.py +236 -0
  40. lionagi/core/generic/hyperedge.py +1 -0
  41. lionagi/core/generic/node.py +156 -221
  42. lionagi/core/generic/tree.py +48 -0
  43. lionagi/core/generic/tree_node.py +79 -0
  44. lionagi/core/mail/__init__.py +12 -0
  45. lionagi/core/mail/mail.py +25 -0
  46. lionagi/core/mail/mail_manager.py +139 -58
  47. lionagi/core/mail/package.py +45 -0
  48. lionagi/core/mail/start_mail.py +36 -0
  49. lionagi/core/message/__init__.py +19 -0
  50. lionagi/core/message/action_request.py +133 -0
  51. lionagi/core/message/action_response.py +135 -0
  52. lionagi/core/message/assistant_response.py +95 -0
  53. lionagi/core/message/instruction.py +234 -0
  54. lionagi/core/message/message.py +101 -0
  55. lionagi/core/message/system.py +86 -0
  56. lionagi/core/message/util.py +283 -0
  57. lionagi/core/report/__init__.py +4 -0
  58. lionagi/core/report/base.py +217 -0
  59. lionagi/core/report/form.py +231 -0
  60. lionagi/core/report/report.py +166 -0
  61. lionagi/core/report/util.py +28 -0
  62. lionagi/core/rule/_default.py +16 -0
  63. lionagi/core/rule/action.py +99 -0
  64. lionagi/core/rule/base.py +238 -0
  65. lionagi/core/rule/boolean.py +56 -0
  66. lionagi/core/rule/choice.py +47 -0
  67. lionagi/core/rule/mapping.py +96 -0
  68. lionagi/core/rule/number.py +71 -0
  69. lionagi/core/rule/rulebook.py +109 -0
  70. lionagi/core/rule/string.py +52 -0
  71. lionagi/core/rule/util.py +35 -0
  72. lionagi/core/session/branch.py +431 -0
  73. lionagi/core/session/directive_mixin.py +287 -0
  74. lionagi/core/session/session.py +229 -903
  75. lionagi/core/structure/__init__.py +1 -0
  76. lionagi/core/structure/chain.py +1 -0
  77. lionagi/core/structure/forest.py +1 -0
  78. lionagi/core/structure/graph.py +1 -0
  79. lionagi/core/structure/tree.py +1 -0
  80. lionagi/core/unit/__init__.py +5 -0
  81. lionagi/core/unit/parallel_unit.py +245 -0
  82. lionagi/core/unit/template/action.py +81 -0
  83. lionagi/core/unit/template/base.py +51 -0
  84. lionagi/core/unit/template/plan.py +84 -0
  85. lionagi/core/unit/template/predict.py +109 -0
  86. lionagi/core/unit/template/score.py +124 -0
  87. lionagi/core/unit/template/select.py +104 -0
  88. lionagi/core/unit/unit.py +362 -0
  89. lionagi/core/unit/unit_form.py +305 -0
  90. lionagi/core/unit/unit_mixin.py +1168 -0
  91. lionagi/core/unit/util.py +71 -0
  92. lionagi/core/validator/validator.py +364 -0
  93. lionagi/core/work/work.py +76 -0
  94. lionagi/core/work/work_function.py +101 -0
  95. lionagi/core/work/work_queue.py +103 -0
  96. lionagi/core/work/worker.py +258 -0
  97. lionagi/core/work/worklog.py +120 -0
  98. lionagi/experimental/compressor/base.py +46 -0
  99. lionagi/experimental/compressor/llm_compressor.py +247 -0
  100. lionagi/experimental/compressor/llm_summarizer.py +61 -0
  101. lionagi/experimental/compressor/util.py +70 -0
  102. lionagi/experimental/directive/__init__.py +19 -0
  103. lionagi/experimental/directive/parser/base_parser.py +69 -2
  104. lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
  105. lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
  106. lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
  107. lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
  108. lionagi/experimental/knowledge/base.py +10 -0
  109. lionagi/experimental/memory/__init__.py +0 -0
  110. lionagi/experimental/strategies/__init__.py +0 -0
  111. lionagi/experimental/strategies/base.py +1 -0
  112. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  113. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  114. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  115. lionagi/integrations/chunker/chunk.py +161 -24
  116. lionagi/integrations/config/oai_configs.py +34 -3
  117. lionagi/integrations/config/openrouter_configs.py +14 -2
  118. lionagi/integrations/loader/load.py +122 -21
  119. lionagi/integrations/loader/load_util.py +6 -77
  120. lionagi/integrations/provider/_mapping.py +46 -0
  121. lionagi/integrations/provider/litellm.py +2 -1
  122. lionagi/integrations/provider/mlx_service.py +16 -9
  123. lionagi/integrations/provider/oai.py +91 -4
  124. lionagi/integrations/provider/ollama.py +6 -5
  125. lionagi/integrations/provider/openrouter.py +115 -8
  126. lionagi/integrations/provider/services.py +2 -2
  127. lionagi/integrations/provider/transformers.py +18 -22
  128. lionagi/integrations/storage/__init__.py +3 -3
  129. lionagi/integrations/storage/neo4j.py +52 -60
  130. lionagi/integrations/storage/storage_util.py +44 -46
  131. lionagi/integrations/storage/structure_excel.py +43 -26
  132. lionagi/integrations/storage/to_excel.py +11 -4
  133. lionagi/libs/__init__.py +22 -1
  134. lionagi/libs/ln_api.py +75 -20
  135. lionagi/libs/ln_context.py +37 -0
  136. lionagi/libs/ln_convert.py +21 -9
  137. lionagi/libs/ln_func_call.py +69 -28
  138. lionagi/libs/ln_image.py +107 -0
  139. lionagi/libs/ln_nested.py +26 -11
  140. lionagi/libs/ln_parse.py +82 -23
  141. lionagi/libs/ln_queue.py +16 -0
  142. lionagi/libs/ln_tokenize.py +164 -0
  143. lionagi/libs/ln_validate.py +16 -0
  144. lionagi/libs/special_tokens.py +172 -0
  145. lionagi/libs/sys_util.py +95 -24
  146. lionagi/lions/coder/code_form.py +13 -0
  147. lionagi/lions/coder/coder.py +50 -3
  148. lionagi/lions/coder/util.py +30 -25
  149. lionagi/tests/libs/test_func_call.py +23 -21
  150. lionagi/tests/libs/test_nested.py +36 -21
  151. lionagi/tests/libs/test_parse.py +1 -1
  152. lionagi/tests/test_core/collections/__init__.py +0 -0
  153. lionagi/tests/test_core/collections/test_component.py +206 -0
  154. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  155. lionagi/tests/test_core/collections/test_flow.py +145 -0
  156. lionagi/tests/test_core/collections/test_pile.py +171 -0
  157. lionagi/tests/test_core/collections/test_progression.py +129 -0
  158. lionagi/tests/test_core/generic/test_edge.py +67 -0
  159. lionagi/tests/test_core/generic/test_graph.py +96 -0
  160. lionagi/tests/test_core/generic/test_node.py +106 -0
  161. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  162. lionagi/tests/test_core/test_branch.py +115 -294
  163. lionagi/tests/test_core/test_form.py +46 -0
  164. lionagi/tests/test_core/test_report.py +105 -0
  165. lionagi/tests/test_core/test_validator.py +111 -0
  166. lionagi/version.py +1 -1
  167. lionagi-0.2.1.dist-info/LICENSE +202 -0
  168. lionagi-0.2.1.dist-info/METADATA +272 -0
  169. lionagi-0.2.1.dist-info/RECORD +240 -0
  170. lionagi/core/branch/base.py +0 -653
  171. lionagi/core/branch/branch.py +0 -474
  172. lionagi/core/branch/flow_mixin.py +0 -96
  173. lionagi/core/branch/util.py +0 -323
  174. lionagi/core/direct/__init__.py +0 -19
  175. lionagi/core/direct/cot.py +0 -123
  176. lionagi/core/direct/plan.py +0 -164
  177. lionagi/core/direct/predict.py +0 -166
  178. lionagi/core/direct/react.py +0 -171
  179. lionagi/core/direct/score.py +0 -279
  180. lionagi/core/direct/select.py +0 -170
  181. lionagi/core/direct/sentiment.py +0 -1
  182. lionagi/core/direct/utils.py +0 -110
  183. lionagi/core/direct/vote.py +0 -64
  184. lionagi/core/execute/base_executor.py +0 -47
  185. lionagi/core/flow/baseflow.py +0 -23
  186. lionagi/core/flow/monoflow/ReAct.py +0 -240
  187. lionagi/core/flow/monoflow/__init__.py +0 -9
  188. lionagi/core/flow/monoflow/chat.py +0 -95
  189. lionagi/core/flow/monoflow/chat_mixin.py +0 -253
  190. lionagi/core/flow/monoflow/followup.py +0 -215
  191. lionagi/core/flow/polyflow/__init__.py +0 -1
  192. lionagi/core/flow/polyflow/chat.py +0 -251
  193. lionagi/core/form/action_form.py +0 -26
  194. lionagi/core/form/field_validator.py +0 -287
  195. lionagi/core/form/form.py +0 -302
  196. lionagi/core/form/mixin.py +0 -214
  197. lionagi/core/form/scored_form.py +0 -13
  198. lionagi/core/generic/action.py +0 -26
  199. lionagi/core/generic/component.py +0 -532
  200. lionagi/core/generic/condition.py +0 -46
  201. lionagi/core/generic/mail.py +0 -90
  202. lionagi/core/generic/mailbox.py +0 -36
  203. lionagi/core/generic/relation.py +0 -70
  204. lionagi/core/generic/signal.py +0 -22
  205. lionagi/core/generic/structure.py +0 -362
  206. lionagi/core/generic/transfer.py +0 -20
  207. lionagi/core/generic/work.py +0 -40
  208. lionagi/core/graph/graph.py +0 -126
  209. lionagi/core/graph/tree.py +0 -190
  210. lionagi/core/mail/schema.py +0 -63
  211. lionagi/core/messages/schema.py +0 -325
  212. lionagi/core/tool/__init__.py +0 -5
  213. lionagi/core/tool/tool.py +0 -28
  214. lionagi/core/tool/tool_manager.py +0 -283
  215. lionagi/experimental/report/form.py +0 -64
  216. lionagi/experimental/report/report.py +0 -138
  217. lionagi/experimental/report/util.py +0 -47
  218. lionagi/experimental/tool/function_calling.py +0 -43
  219. lionagi/experimental/tool/manual.py +0 -66
  220. lionagi/experimental/tool/schema.py +0 -59
  221. lionagi/experimental/tool/tool_manager.py +0 -138
  222. lionagi/experimental/tool/util.py +0 -16
  223. lionagi/experimental/validator/rule.py +0 -139
  224. lionagi/experimental/validator/validator.py +0 -56
  225. lionagi/experimental/work/__init__.py +0 -10
  226. lionagi/experimental/work/async_queue.py +0 -54
  227. lionagi/experimental/work/schema.py +0 -73
  228. lionagi/experimental/work/work_function.py +0 -67
  229. lionagi/experimental/work/worker.py +0 -56
  230. lionagi/experimental/work2/form.py +0 -371
  231. lionagi/experimental/work2/report.py +0 -289
  232. lionagi/experimental/work2/schema.py +0 -30
  233. lionagi/experimental/work2/tests.py +0 -72
  234. lionagi/experimental/work2/work_function.py +0 -89
  235. lionagi/experimental/work2/worker.py +0 -12
  236. lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
  237. lionagi/tests/test_core/generic/test_component.py +0 -89
  238. lionagi/tests/test_core/test_base_branch.py +0 -426
  239. lionagi/tests/test_core/test_chat_flow.py +0 -63
  240. lionagi/tests/test_core/test_mail_manager.py +0 -75
  241. lionagi/tests/test_core/test_prompts.py +0 -51
  242. lionagi/tests/test_core/test_session.py +0 -254
  243. lionagi/tests/test_core/test_session_base_util.py +0 -313
  244. lionagi/tests/test_core/test_tool_manager.py +0 -95
  245. lionagi-0.1.2.dist-info/LICENSE +0 -9
  246. lionagi-0.1.2.dist-info/METADATA +0 -174
  247. lionagi-0.1.2.dist-info/RECORD +0 -206
  248. /lionagi/core/{branch → _setting}/__init__.py +0 -0
  249. /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
  250. /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
  251. /lionagi/core/{form → agent/plan}/__init__.py +0 -0
  252. /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
  253. /lionagi/core/{graph → director}/__init__.py +0 -0
  254. /lionagi/core/{messages → engine}/__init__.py +0 -0
  255. /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
  256. /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
  257. /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
  258. /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
  259. /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
  260. /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
  261. /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
  262. /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
  263. /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
  264. /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
  265. /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
  266. /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
  267. {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
  268. {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,172 @@
1
+ # disallowed special tokens
2
+
3
+ disallowed_tokens = [
4
+ "▄",
5
+ "▅",
6
+ "▆",
7
+ "▇",
8
+ "█",
9
+ "▏",
10
+ "▎",
11
+ "▍",
12
+ "▌",
13
+ "▋",
14
+ "▊",
15
+ "▉",
16
+ "▔",
17
+ "▕",
18
+ "▁▁",
19
+ "▁▂",
20
+ "▁▃",
21
+ "▁▄",
22
+ "▁▅",
23
+ "▁▆",
24
+ "▁▇",
25
+ "▁█",
26
+ "▁▏",
27
+ "▁▎",
28
+ "▁▍",
29
+ "▁▌",
30
+ "▁▋",
31
+ "▁▊",
32
+ "▁▉",
33
+ "▁▔",
34
+ "▁▕",
35
+ "▄▄",
36
+ "▄▅",
37
+ "▄▆",
38
+ "▄▇",
39
+ "▄█",
40
+ "▄▏",
41
+ "▄▎",
42
+ "▄▍",
43
+ "▄▌",
44
+ "▄▋",
45
+ "▄▊",
46
+ "▄▉",
47
+ "▄▔",
48
+ "▄▕",
49
+ "▅▅",
50
+ "▅▆",
51
+ "▅▇",
52
+ "▅█",
53
+ "▅▏",
54
+ "▅▎",
55
+ "▅▍",
56
+ "▅▌",
57
+ "▅▋",
58
+ "▅▊",
59
+ "▅▉",
60
+ "▅▔",
61
+ "▅▕",
62
+ "▆▆",
63
+ "▆▇",
64
+ "▆█",
65
+ "▆▏",
66
+ "▆▎",
67
+ "▆▍",
68
+ "▆▌",
69
+ "▆▋",
70
+ "▆▊",
71
+ "▆▉",
72
+ "▆▔",
73
+ "▆▕",
74
+ "▇▇",
75
+ "▇█",
76
+ "▇▏",
77
+ "▇▎",
78
+ "▇▍",
79
+ "▇▌",
80
+ "▇▋",
81
+ "▇▊",
82
+ "▇▉",
83
+ "▇▔",
84
+ "▇▕",
85
+ "██",
86
+ "█▏",
87
+ "█▎",
88
+ "█▍",
89
+ "█▌",
90
+ "█▋",
91
+ "█▊",
92
+ "█▉",
93
+ "█",
94
+ "█▔",
95
+ "█▕",
96
+ "▏▏",
97
+ "▏▎",
98
+ "▏▍",
99
+ "▏▌",
100
+ "▏▋",
101
+ "▏▊",
102
+ "▏▉",
103
+ "▏",
104
+ "▏▔",
105
+ "▏▕",
106
+ "▎▎",
107
+ "▎▍",
108
+ "▎▌",
109
+ "▎▋",
110
+ "▎▊",
111
+ "▎▉",
112
+ "▎",
113
+ "▎▔",
114
+ "▎▕",
115
+ "▍▍",
116
+ "▍▌",
117
+ "▍▋",
118
+ "▍▊",
119
+ "▍▉",
120
+ "▍",
121
+ "▍▔",
122
+ "▍▕",
123
+ "▌▌",
124
+ "▌▋",
125
+ "▌▊",
126
+ "▌▉",
127
+ "▌",
128
+ "▌▔",
129
+ "▌▕",
130
+ "▋▋",
131
+ "▋▊",
132
+ "▋▉",
133
+ "▋",
134
+ "▋▔",
135
+ "▋▕",
136
+ "▊▊",
137
+ "▊▉",
138
+ "▊",
139
+ "▊▔",
140
+ "▊▕",
141
+ "▉▉",
142
+ "▉",
143
+ "▉▔",
144
+ "▉▕",
145
+ "▔▔",
146
+ "▔▕",
147
+ "▕▕",
148
+ "▁▁▁",
149
+ "▁▁▂",
150
+ "▁▁▃",
151
+ "▁▁▄",
152
+ "▁▁▅",
153
+ "▁▁▆",
154
+ "▁▁▇",
155
+ "▁▁█",
156
+ "▁▁▏",
157
+ "▁▁▎",
158
+ "▁▁▍",
159
+ "▁▁▌",
160
+ "▁▁▋",
161
+ "▁▁▊",
162
+ "▁▁▉",
163
+ "▁▁▔",
164
+ "▁▁▕",
165
+ "▁▂▂",
166
+ "▁▂▃",
167
+ "▁▂▄",
168
+ "▁▂▅",
169
+ "▁▂▆",
170
+ "▁▂▇",
171
+ "▁▂█",
172
+ ]
lionagi/libs/sys_util.py CHANGED
@@ -1,28 +1,17 @@
1
1
  """
2
- MIT License
3
-
4
- Copyright (c) 2023 HaiyangLi quantocean.li@gmail.com
5
-
6
- Permission is hereby granted, free of charge, to any person
7
- obtaining a copy of this software and associated documentation
8
- files (the "Software"), to deal in the Software without
9
- restriction, including without limitation the rights to use,
10
- copy, modify, merge, publish, distribute, sublicense, and/or
11
- sell copies of the Software, and to permit persons to whom
12
- the Software is furnished to do so, subject to the following
13
- conditions:
14
-
15
- The above copyright notice and this permission notice shall be
16
- included in all copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
- SOFTWARE.
2
+ Copyright 2024 HaiyangLi
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
26
15
  """
27
16
 
28
17
  import copy
@@ -430,6 +419,19 @@ class SysUtil:
430
419
 
431
420
  @staticmethod
432
421
  def list_files(dir_path: Path | str, extension: str = None) -> list[Path]:
422
+ """
423
+ Lists all files in a specified directory with an optional filter for file extensions.
424
+
425
+ Args:
426
+ dir_path (Path | str): The directory path where files are listed.
427
+ extension (str, optional): Filter files by extension. Default is None, which lists all files.
428
+
429
+ Returns:
430
+ list[Path]: A list of Path objects representing files in the directory.
431
+
432
+ Raises:
433
+ NotADirectoryError: If the provided dir_path is not a directory.
434
+ """
433
435
  dir_path = Path(dir_path)
434
436
  if not dir_path.is_dir():
435
437
  raise NotADirectoryError(f"{dir_path} is not a directory.")
@@ -440,6 +442,16 @@ class SysUtil:
440
442
 
441
443
  @staticmethod
442
444
  def copy_file(src: Path | str, dest: Path | str) -> None:
445
+ """
446
+ Copies a file from a source path to a destination path.
447
+
448
+ Args:
449
+ src (Path | str): The source file path.
450
+ dest (Path | str): The destination file path.
451
+
452
+ Raises:
453
+ FileNotFoundError: If the source file does not exist or is not a file.
454
+ """
443
455
  from shutil import copy2
444
456
 
445
457
  src, dest = Path(src), Path(dest)
@@ -450,6 +462,18 @@ class SysUtil:
450
462
 
451
463
  @staticmethod
452
464
  def get_size(path: Path | str) -> int:
465
+ """
466
+ Gets the size of a file or total size of files in a directory.
467
+
468
+ Args:
469
+ path (Path | str): The file or directory path.
470
+
471
+ Returns:
472
+ int: The size in bytes.
473
+
474
+ Raises:
475
+ FileNotFoundError: If the path does not exist.
476
+ """
453
477
  path = Path(path)
454
478
  if path.is_file():
455
479
  return path.stat().st_size
@@ -457,3 +481,50 @@ class SysUtil:
457
481
  return sum(f.stat().st_size for f in path.glob("**/*") if f.is_file())
458
482
  else:
459
483
  raise FileNotFoundError(f"{path} does not exist.")
484
+
485
+ @staticmethod
486
+ def save_to_file(
487
+ text,
488
+ directory: Path | str,
489
+ filename: str,
490
+ timestamp: bool = True,
491
+ dir_exist_ok: bool = True,
492
+ time_prefix: bool = False,
493
+ custom_timestamp_format: str | None = None,
494
+ random_hash_digits=0,
495
+ verbose=True,
496
+ ):
497
+ """
498
+ Saves text to a file within a specified directory, optionally adding a timestamp, hash, and verbose logging.
499
+
500
+ Args:
501
+ text (str): The text to save.
502
+ directory (Path | str): The directory path to save the file.
503
+ filename (str): The filename for the saved text.
504
+ timestamp (bool): If True, append a timestamp to the filename. Default is True.
505
+ dir_exist_ok (bool): If True, creates the directory if it does not exist. Default is True.
506
+ time_prefix (bool): If True, prepend the timestamp instead of appending. Default is False.
507
+ custom_timestamp_format (str | None): A custom format for the timestamp, if None uses default format. Default is None.
508
+ random_hash_digits (int): Number of random hash digits to append to filename. Default is 0.
509
+ verbose (bool): If True, prints the file path after saving. Default is True.
510
+
511
+ Returns:
512
+ bool: True if the text was successfully saved.
513
+ """
514
+ file_path = SysUtil.create_path(
515
+ directory=directory,
516
+ filename=filename,
517
+ timestamp=timestamp,
518
+ dir_exist_ok=dir_exist_ok,
519
+ time_prefix=time_prefix,
520
+ custom_timestamp_format=custom_timestamp_format,
521
+ random_hash_digits=random_hash_digits,
522
+ )
523
+
524
+ with open(file_path, "w") as file:
525
+ file.write(text)
526
+
527
+ if verbose:
528
+ print(f"Text saved to: {file_path}")
529
+
530
+ return True
@@ -0,0 +1,13 @@
1
+ from typing import Any
2
+ from pydantic import Field
3
+ from lionagi.libs import ParseUtil, SysUtil
4
+ from lionagi.core import Session
5
+ from lionagi.core.form.action_form import ActionForm
6
+
7
+
8
+ class CodeForm(ActionForm):
9
+ template_name: str = "code_form"
10
+ language: str = Field(
11
+ default="python",
12
+ description="The programming language of the code to be executed.",
13
+ )
@@ -1,18 +1,49 @@
1
1
  import asyncio
2
+ from pathlib import Path
3
+
4
+ from lionagi import logging as _logging
2
5
  from lionagi.core import Session
6
+ from lionagi.libs import ParseUtil
3
7
 
4
8
  from .base_prompts import CODER_PROMPTS
5
- from .util import extract_code_blocks, install_missing_dependencies, set_up_interpreter
9
+ from .util import install_missing_dependencies, set_up_interpreter, save_code_file
6
10
 
7
11
 
8
12
  class Coder:
13
+
9
14
  def __init__(
10
- self, prompts=None, session=None, session_kwargs=None, required_libraries=None
15
+ self,
16
+ prompts: dict = None,
17
+ session: Session = None,
18
+ session_kwargs: dict = None,
19
+ required_libraries: list = None,
20
+ work_dir: Path | str = None,
21
+ ) -> None:
22
+
23
+ self.prompts = prompts or CODER_PROMPTS
24
+ self.session = session or self._create_session(session_kwargs)
25
+ self.required_libraries = required_libraries or ["lionagi"]
26
+ self.work_dir = work_dir or Path.cwd() / "coder" / "code_files"
27
+
28
+ def _create_session(self, session_kwargs: dict = None) -> Session:
29
+ session_kwargs = session_kwargs or {}
30
+ return Session(system=self.prompts["system"], **session_kwargs)
31
+
32
+
33
+ class Coder:
34
+ def __init__(
35
+ self,
36
+ prompts=None,
37
+ session=None,
38
+ session_kwargs=None,
39
+ required_libraries=None,
40
+ work_dir=None,
11
41
  ):
12
42
  print("Initializing Coder...")
13
43
  self.prompts = prompts or CODER_PROMPTS
14
44
  self.session = session or self._create_session(session_kwargs)
15
45
  self.required_libraries = required_libraries or ["lionagi"]
46
+ self.work_dir = work_dir or Path.cwd() / "coder" / "code_files"
16
47
  print("Coder initialized.")
17
48
 
18
49
  def _create_session(self, session_kwargs=None):
@@ -32,7 +63,7 @@ class Coder:
32
63
  print("Writing code...")
33
64
  code = await self.session.chat(self.prompts["write_code"], context=context)
34
65
  print("Code writing completed.")
35
- return extract_code_blocks(code)
66
+ return ParseUtil.extract_code_blocks(code)
36
67
 
37
68
  async def _review_code(self, context=None):
38
69
  print("Reviewing code...")
@@ -78,6 +109,22 @@ class Coder:
78
109
  print("Code execution completed.")
79
110
  return execution
80
111
 
112
+ def _save_code_file(self, code, **kwargs):
113
+ print("Saving code...")
114
+ save_code_file(code, self.work_dir, **kwargs)
115
+ print("Code saved.")
116
+
117
+ @staticmethod
118
+ def _load_code_file(file_path):
119
+ print("Loading code...")
120
+ try:
121
+ with open(file_path, "r") as file:
122
+ print("Code loaded.")
123
+ return file.read()
124
+ except FileNotFoundError:
125
+ _logging.error(f"File not found: {file_path}")
126
+ return None
127
+
81
128
 
82
129
  async def main():
83
130
  print("Starting main function...")
@@ -1,3 +1,6 @@
1
+ from typing import Any
2
+ from pathlib import Path
3
+
1
4
  E2B_key_scheme = "E2B_API_KEY"
2
5
 
3
6
 
@@ -21,31 +24,6 @@ def set_up_interpreter(interpreter_provider="e2b", key_scheme=E2B_key_scheme):
21
24
  raise ValueError("Invalid interpreter provider")
22
25
 
23
26
 
24
- def extract_code_blocks(code):
25
- print("Extracting code blocks...")
26
- code_blocks = []
27
- lines = code.split("\n")
28
- inside_code_block = False
29
- current_block = []
30
-
31
- for line in lines:
32
- if line.startswith("```"):
33
- if inside_code_block:
34
- code_blocks.append("\n".join(current_block))
35
- current_block = []
36
- inside_code_block = False
37
- else:
38
- inside_code_block = True
39
- elif inside_code_block:
40
- current_block.append(line)
41
-
42
- if current_block:
43
- code_blocks.append("\n".join(current_block))
44
-
45
- print(f"Extracted {len(code_blocks)} code block(s).")
46
- return "\n\n".join(code_blocks)
47
-
48
-
49
27
  def install_missing_dependencies(required_libraries):
50
28
  print("Checking for missing dependencies...")
51
29
  missing_libraries = [
@@ -89,3 +67,30 @@ def install_library(library):
89
67
  print(
90
68
  "You may need to run the script with administrative privileges or use a virtual environment."
91
69
  )
70
+
71
+
72
+ def save_code_file(
73
+ code: Any,
74
+ directory: Path | str = None,
75
+ filename: str = "code.py",
76
+ timestamp: bool = True,
77
+ dir_exist_ok: bool = True,
78
+ time_prefix: bool = False,
79
+ custom_timestamp_format: str | None = None,
80
+ random_hash_digits: int = 3,
81
+ verbose: bool = True,
82
+ ):
83
+
84
+ from lionagi.libs import SysUtil
85
+
86
+ return SysUtil.save_to_file(
87
+ text=code,
88
+ directory=directory,
89
+ filename=filename,
90
+ timestamp=timestamp,
91
+ dir_exist_ok=dir_exist_ok,
92
+ time_prefix=time_prefix,
93
+ custom_timestamp_format=custom_timestamp_format,
94
+ random_hash_digits=random_hash_digits,
95
+ verbose=verbose,
96
+ )
@@ -296,8 +296,8 @@ class TestRCall(unittest.IsolatedAsyncioTestCase):
296
296
  await asyncio.sleep(2)
297
297
  return x
298
298
 
299
- with self.assertRaises(asyncio.TimeoutError):
300
- await rcall(async_func, 5, timeout=1)
299
+ with self.assertRaises(RuntimeError):
300
+ await rcall(async_func, 5, timeout=0.1)
301
301
 
302
302
  async def test_retry_mechanism(self):
303
303
  attempt_count = 0
@@ -307,22 +307,22 @@ class TestRCall(unittest.IsolatedAsyncioTestCase):
307
307
  attempt_count += 1
308
308
  raise ValueError("Test Error")
309
309
 
310
- with self.assertRaises(ValueError):
311
- await rcall(sync_func, 5, retries=3)
310
+ with self.assertRaises(RuntimeError):
311
+ await rcall(sync_func, 5, retries=3, delay=0.1, backoff_factor=1.1)
312
312
  self.assertEqual(attempt_count, 3) # Initial call + 3 retries
313
313
 
314
314
  async def test_default_value_on_exception(self):
315
315
  def sync_func(x):
316
316
  raise ValueError("Test Error")
317
317
 
318
- result = await rcall(sync_func, 5, default=10)
318
+ result = await rcall(sync_func, 5, default=10, delay=0)
319
319
  self.assertEqual(result, 10)
320
320
 
321
321
  async def test_exception_propagation(self):
322
322
  def sync_func(x):
323
323
  raise ValueError("Test Error")
324
324
 
325
- with self.assertRaises(ValueError):
325
+ with self.assertRaises(RuntimeError):
326
326
  await rcall(sync_func, 5)
327
327
 
328
328
 
@@ -581,22 +581,22 @@ class TestCallDecorator(unittest.IsolatedAsyncioTestCase):
581
581
  class TestThrottleClass(unittest.TestCase):
582
582
 
583
583
  def test_throttling_behavior_sync(self):
584
- throttle_decorator = Throttle(2) # 2 seconds throttle period
584
+ throttle_decorator = Throttle(0.1) # 2 seconds throttle period
585
585
 
586
586
  @throttle_decorator
587
587
  def test_func():
588
588
  return time.time()
589
589
 
590
590
  first_call_time = test_func()
591
- time.sleep(1) # Sleep less than the throttle period
591
+ time.sleep(0.1) # Sleep less than the throttle period
592
592
  second_call_time = test_func()
593
593
 
594
594
  self.assertGreaterEqual(
595
- second_call_time - first_call_time, 2
595
+ second_call_time - first_call_time, 0.1
596
596
  ) # Second call should be throttled
597
597
 
598
598
  def test_throttling_behavior_async(self):
599
- throttle_decorator = Throttle(2) # 2 seconds throttle period
599
+ throttle_decorator = Throttle(1) # 2 seconds throttle period
600
600
 
601
601
  @throttle_decorator
602
602
  async def test_func():
@@ -604,28 +604,28 @@ class TestThrottleClass(unittest.TestCase):
604
604
 
605
605
  async def async_test():
606
606
  first_call_time = await test_func()
607
- await asyncio.sleep(1) # Sleep less than the throttle period
607
+ await asyncio.sleep(0.1) # Sleep less than the throttle period
608
608
  second_call_time = await test_func()
609
609
 
610
610
  self.assertGreaterEqual(
611
- second_call_time - first_call_time, 2
611
+ second_call_time - first_call_time, 1
612
612
  ) # Second call should be throttled
613
613
 
614
614
  asyncio.run(async_test())
615
615
 
616
616
  def test_successive_calls_with_sufficient_delay(self):
617
- throttle_decorator = Throttle(1) # 1 second throttle period
617
+ throttle_decorator = Throttle(0.1) # 1 second throttle period
618
618
 
619
619
  @throttle_decorator
620
620
  def test_func():
621
621
  return time.time()
622
622
 
623
623
  first_call_time = test_func()
624
- time.sleep(1.1) # Sleep more than the throttle period
624
+ time.sleep(0.12) # Sleep more than the throttle period
625
625
  second_call_time = test_func()
626
626
 
627
627
  self.assertLess(
628
- second_call_time - first_call_time, 1.5
628
+ second_call_time - first_call_time, 0.2
629
629
  ) # Second call should not be throttled
630
630
 
631
631
 
@@ -633,7 +633,7 @@ class TestAsyncRetryDecorator(unittest.IsolatedAsyncioTestCase):
633
633
  async def test_successful_retry(self):
634
634
  attempt = 0
635
635
 
636
- @CallDecorator.retry(retries=3, delay=1, backoff_factor=2)
636
+ @CallDecorator.retry(retries=3, delay=0.1, backoff_factor=2)
637
637
  async def test_func():
638
638
  nonlocal attempt
639
639
  attempt += 1
@@ -648,20 +648,22 @@ class TestAsyncRetryDecorator(unittest.IsolatedAsyncioTestCase):
648
648
  async def test_retry_limit(self):
649
649
  attempt = 0
650
650
 
651
- @CallDecorator.retry(retries=2, delay=1, backoff_factor=2)
651
+ @CallDecorator.retry(retries=2, delay=0.1, backoff_factor=2)
652
652
  async def test_func():
653
653
  nonlocal attempt
654
654
  attempt += 1
655
655
  raise ValueError("Test failure")
656
656
 
657
- with self.assertRaises(ValueError):
657
+ try:
658
658
  await test_func()
659
+ except:
660
+ pass
659
661
  self.assertEqual(attempt, 2)
660
662
 
661
663
  async def test_immediate_success(self):
662
664
  attempt = 0
663
665
 
664
- @CallDecorator.retry(retries=3, delay=1, backoff_factor=2)
666
+ @CallDecorator.retry(retries=3, delay=0.1, backoff_factor=2)
665
667
  async def test_func():
666
668
  nonlocal attempt
667
669
  attempt += 1
@@ -675,7 +677,7 @@ class TestAsyncRetryDecorator(unittest.IsolatedAsyncioTestCase):
675
677
  attempt = 0
676
678
  start_time = time.time()
677
679
 
678
- @CallDecorator.retry(retries=3, delay=1, backoff_factor=2)
680
+ @CallDecorator.retry(retries=3, delay=0.1, backoff_factor=2)
679
681
  async def test_func():
680
682
  nonlocal attempt
681
683
  attempt += 1
@@ -690,7 +692,7 @@ class TestAsyncRetryDecorator(unittest.IsolatedAsyncioTestCase):
690
692
  self.assertEqual(result, "Success")
691
693
  # Note: The actual delay might be slightly longer than expected due to asyncio's event loop scheduling.
692
694
  self.assertTrue(
693
- elapsed_time >= 3, f"Elapsed time was {elapsed_time}, expected >= 3"
695
+ elapsed_time >= 0.3, f"Elapsed time was {elapsed_time}, expected >= 3"
694
696
  )
695
697
  self.assertEqual(attempt, 3)
696
698