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
lionagi/__init__.py CHANGED
@@ -1,15 +1,70 @@
1
1
  """
2
- lionagi is an intelligent automation framework.
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.
3
15
  """
4
16
 
5
17
  import logging
6
18
  from .version import __version__
7
19
  from dotenv import load_dotenv
8
20
 
9
- from .core import direct, Branch, Session, func_to_tool
10
- from .integrations.provider.services import Services
11
- from .integrations.chunker.chunk import chunk
12
- from .integrations.loader.load import load
21
+ from lionagi.libs.ln_convert import to_list, to_dict, to_df, to_readable_dict
22
+ from lionagi.libs.ln_func_call import alcall, bcall, lcall, CallDecorator as cd, tcall
23
+ from lionagi.core.collections.abc import Field
24
+ from lionagi.core.collections import progression, flow, pile, iModel
25
+ from lionagi.core.generic import Node, Graph, Tree, Edge
26
+ from lionagi.core.action import func_to_tool
27
+ from lionagi.core.report import Form, Report
28
+ from lionagi.core.session.branch import Branch
29
+ from lionagi.core.session.session import Session
30
+ from lionagi.core.work.worker import work, Worker
31
+ from lionagi.integrations.provider.services import Services
32
+ from lionagi.integrations.chunker.chunk import chunk
33
+ from lionagi.integrations.loader.load import load
34
+ import lionagi.core.director.direct as direct
35
+
36
+
37
+ __all__ = [
38
+ "Field",
39
+ "progression",
40
+ "flow",
41
+ "pile",
42
+ "iModel",
43
+ "work",
44
+ "Worker",
45
+ "Branch",
46
+ "Session",
47
+ "Form",
48
+ "Report",
49
+ "Services",
50
+ "direct",
51
+ "Node",
52
+ "Graph",
53
+ "Tree",
54
+ "Edge",
55
+ "chunk",
56
+ "load",
57
+ "func_to_tool",
58
+ "cd",
59
+ "alcall",
60
+ "bcall",
61
+ "to_list",
62
+ "to_dict",
63
+ "lcall",
64
+ "to_df",
65
+ "tcall",
66
+ "to_readable_dict",
67
+ ]
13
68
 
14
69
 
15
70
  logger = logging.getLogger(__name__)
lionagi/core/__init__.py CHANGED
@@ -1,26 +1 @@
1
1
  from . import *
2
-
3
- from .branch.branch import Branch
4
- from .session.session import Session
5
- from .generic import (
6
- ActionNode,
7
- ActionSelection,
8
- Condition,
9
- )
10
- from .agent.base_agent import BaseAgent
11
- from .messages.schema import Instruction, System, Response
12
- from .tool import func_to_tool
13
-
14
-
15
- __all__ = [
16
- "ActionNode",
17
- "ActionSelection",
18
- "Branch",
19
- "Condition",
20
- "Session",
21
- "System",
22
- "Instruction",
23
- "Response",
24
- "BaseAgent",
25
- "func_to_tool",
26
- ]
@@ -0,0 +1,59 @@
1
+ # TODO
2
+
3
+ # import csv
4
+ # import json
5
+ # import threading
6
+ # from contextlib import contextmanager
7
+
8
+
9
+ # class Settings:
10
+ # def __init__(self):
11
+ # self._lock = threading.Lock()
12
+ # self._config = {}
13
+ # self._default_service = None
14
+
15
+ # def load_from_json(self, file_path):
16
+ # with self._lock:
17
+ # with open(file_path, "r") as file:
18
+ # self._config = json.load(file)
19
+
20
+ # def save_to_json(self, file_path):
21
+ # with self._lock:
22
+ # with open(file_path, "w") as file:
23
+ # json.dump(self._config, file, indent=4)
24
+
25
+ # def load_default_service(self, file_path):
26
+ # with self._lock:
27
+ # with open(file_path, "r") as file:
28
+ # reader = csv.DictReader(file)
29
+ # self._default_service = next(reader)
30
+
31
+ # def save_default_service(self, file_path):
32
+ # with self._lock:
33
+ # fieldnames = ["provider", "api_key", "rate_limit"]
34
+ # with open(file_path, "w", newline="") as file:
35
+ # writer = csv.DictWriter(file, fieldnames=fieldnames)
36
+ # writer.writeheader()
37
+ # writer.writerow(self._default_service)
38
+
39
+ # @contextmanager
40
+ # def service_context(self, provider=None, api_key=None, rate_limit=None):
41
+ # with self._lock:
42
+ # service_config = {
43
+ # "provider": provider or self._default_service["provider"],
44
+ # "api_key": api_key or self._default_service["api_key"],
45
+ # "rate_limit": rate_limit or self._default_service["rate_limit"],
46
+ # }
47
+ # yield service_config
48
+
49
+ # def get_config(self, key):
50
+ # with self._lock:
51
+ # return self._config.get(key)
52
+
53
+ # def set_config(self, key, value):
54
+ # with self._lock:
55
+ # self._config[key] = value
56
+
57
+
58
+ # # Singleton instance
59
+ # lionagi_settings = Settings()
@@ -0,0 +1,14 @@
1
+ from .function_calling import FunctionCalling
2
+ from .tool import Tool
3
+ from .tool_manager import ToolManager, func_to_tool
4
+ from .node import ActionNode, DirectiveSelection
5
+
6
+
7
+ __all__ = [
8
+ "FunctionCalling",
9
+ "Tool",
10
+ "ToolManager",
11
+ "func_to_tool",
12
+ "ActionNode",
13
+ "DirectiveSelection",
14
+ ]
@@ -0,0 +1,136 @@
1
+ """
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.
15
+ """
16
+
17
+ """
18
+ This module defines the FunctionCalling class, which facilitates dynamic
19
+ invocation of functions based on various input types. It supports initializing
20
+ function calls from tuples, dictionaries, ActionRequest objects, or JSON strings.
21
+
22
+ Note:
23
+ Function Calling object is the only way for AI system to call functions.
24
+ """
25
+
26
+ from functools import singledispatchmethod
27
+ from typing import Any, Callable, Dict
28
+
29
+ from lionagi.libs import ParseUtil
30
+ from lionagi.libs.ln_func_call import call_handler
31
+ from lionagi.core.collections.abc import Actionable
32
+ from lionagi.core.message.action_request import ActionRequest
33
+
34
+
35
+ class FunctionCalling(Actionable):
36
+ """
37
+ A class for dynamically invoking functions based on various input types,
38
+ allowing for specification of the function and arguments through multiple
39
+ formats including tuples, dictionaries, ActionRequests, or JSON strings.
40
+ """
41
+
42
+ def __init__(self, function: Callable, arguments: Dict[str, Any] = None):
43
+ """
44
+ Initializes a new instance of FunctionCalling with the given function
45
+ and optional arguments.
46
+
47
+ Args:
48
+ function (Callable): The function to be called.
49
+ arguments (Dict[str, Any]): Arguments to pass to the function.
50
+ Defaults to an empty dictionary.
51
+ """
52
+ self.function = function
53
+ self.arguments = arguments or {}
54
+
55
+ @property
56
+ def func_name(self) -> str:
57
+ """
58
+ Returns the name of the function.
59
+
60
+ Returns:
61
+ str: The function's name.
62
+ """
63
+ return self.function.__name__
64
+
65
+ @singledispatchmethod
66
+ @classmethod
67
+ def create(cls, func_call: Any) -> "FunctionCalling":
68
+ """
69
+ Creates an instance of FunctionCalling based on the type of input.
70
+
71
+ Args:
72
+ func_call (Any): The function call description, which can be a tuple, dict,
73
+ ActionRequest, or JSON string.
74
+
75
+ Returns:
76
+ FunctionCalling: An instance of FunctionCalling prepared to invoke
77
+ the specified function.
78
+
79
+ Raises:
80
+ TypeError: If the input type is not supported.
81
+ """
82
+ raise TypeError(f"Unsupported type {type(func_call)}")
83
+
84
+ @create.register(tuple)
85
+ def _(cls, function_calling: tuple) -> "FunctionCalling":
86
+ if len(function_calling) == 2:
87
+ return cls(function=function_calling[0], arguments=function_calling[1])
88
+ else:
89
+ raise ValueError(f"Invalid function call {function_calling}")
90
+
91
+ @create.register(dict)
92
+ def _(cls, function_calling: Dict[str, Any]) -> "FunctionCalling":
93
+ if len(function_calling) == 2 and (
94
+ {"function", "arguments"} <= function_calling.keys()
95
+ ):
96
+ return cls.create(
97
+ (function_calling["function"], function_calling["arguments"])
98
+ )
99
+ raise ValueError(f"Invalid function call {function_calling}")
100
+
101
+ @create.register(ActionRequest)
102
+ def _(cls, function_calling: ActionRequest) -> "FunctionCalling":
103
+ return cls.create((function_calling.function, function_calling.arguments))
104
+
105
+ @create.register(str)
106
+ def _(cls, function_calling: str) -> "FunctionCalling":
107
+ _call = None
108
+ try:
109
+ _call = ParseUtil.fuzzy_parse_json(function_calling)
110
+ except Exception as e:
111
+ raise ValueError(f"Invalid function call {function_calling}") from e
112
+
113
+ if isinstance(_call, dict):
114
+ return cls.create(_call)
115
+ raise ValueError(f"Invalid function call {function_calling}")
116
+
117
+ async def invoke(self) -> Any:
118
+ """
119
+ Asynchronously invokes the stored function with the provided arguments.
120
+
121
+ Returns:
122
+ Any: The result of the function call.
123
+ """
124
+ return await call_handler(self.function, **self.arguments)
125
+
126
+ def __str__(self) -> str:
127
+ """
128
+ Returns a string representation of the function call.
129
+
130
+ Returns:
131
+ str: String representation of the function call.
132
+ """
133
+ return f"{self.func_name}({self.arguments})"
134
+
135
+ def __repr__(self) -> str:
136
+ return self.__str__()
@@ -0,0 +1 @@
1
+ # TODO
@@ -0,0 +1,109 @@
1
+ """
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.
15
+ """
16
+
17
+ from pydantic import Field
18
+
19
+ from lionagi.core.collections.abc import Actionable
20
+ from lionagi.core.generic.node import Node
21
+ from .tool import Tool
22
+
23
+
24
+ class DirectiveSelection(Node, Actionable):
25
+ """
26
+ Represents a directive selection node which can be invoked to perform an action.
27
+
28
+ Attributes:
29
+ directive (str): The action to be performed, with a default value of "chat".
30
+ directive_kwargs (dict): The arguments for the action.
31
+
32
+ Methods:
33
+ invoke(): An asynchronous method to perform the action defined by the directive.
34
+ """
35
+
36
+ directive: str = Field(
37
+ "chat", description="The action to be performed", alias="action_type"
38
+ )
39
+ directive_kwargs: dict = Field(
40
+ default_factory=dict,
41
+ description="The arguments for the action",
42
+ alias="action_arguments",
43
+ )
44
+
45
+ async def invoke(self):
46
+ """
47
+ Perform the action defined by the directive.
48
+
49
+ This method is intended to be overridden by subclasses to provide specific
50
+ implementation details for the action.
51
+ """
52
+ pass
53
+
54
+
55
+ class ActionNode(DirectiveSelection):
56
+ """
57
+ Represents an action node that can invoke actions within a branch using tools and instructions.
58
+
59
+ Attributes:
60
+ tools (list[Tool] | Tool | None): The tools to be used in the action.
61
+ instruction (Node): The instruction for the action.
62
+
63
+ Methods:
64
+ invoke(branch, context=None): An asynchronous method to invoke the action
65
+ within the given branch.
66
+ """
67
+
68
+ tools: list[Tool] | Tool | None = Field(
69
+ default_factory=list,
70
+ description="The tools to be used in the action",
71
+ alias="tool",
72
+ )
73
+ instruction: Node = Field(
74
+ ..., description="The instruction for the action", alias="instruct"
75
+ )
76
+
77
+ async def invoke(self, branch, context=None):
78
+ """
79
+ Invoke the action within the given branch.
80
+
81
+ Args:
82
+ branch: The branch in which to perform the action.
83
+ context: Optional; Additional context for the action.
84
+
85
+ Returns:
86
+ The result of the action, depending on the directive.
87
+
88
+ Raises:
89
+ ValueError: If the directive is not "chat" or "direct".
90
+ """
91
+ if self.directive == "chat":
92
+ return await branch.chat(
93
+ instruction=self.instruction.instruct,
94
+ tools=self.tools,
95
+ **self.directive_kwargs,
96
+ )
97
+ elif self.directive == "direct":
98
+ if self.tools:
99
+ self.directive_kwargs["allow_action"] = True
100
+ return await branch.direct(
101
+ instruction=self.instruction.instruct,
102
+ context=context,
103
+ tools=self.tools,
104
+ **self.directive_kwargs,
105
+ )
106
+ else:
107
+ raise ValueError(
108
+ 'Invalid directive, valid directives are: "chat", "direct"'
109
+ )
@@ -0,0 +1,114 @@
1
+ """
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.
15
+ """
16
+
17
+ from typing import Callable, Union, List, Dict, Any
18
+ from pydantic import Field, field_serializer
19
+ from lionagi.libs.ln_func_call import call_handler
20
+ from lionagi.core.collections.abc import Actionable
21
+ from lionagi.core.generic.node import Node
22
+ from .function_calling import FunctionCalling
23
+
24
+
25
+ class Tool(Node, Actionable):
26
+ """
27
+ Class representing a Tool with capabilities for pre-processing, post-processing,
28
+ and parsing function results.
29
+
30
+ Attributes:
31
+ function (Callable): The callable function or capability of the tool.
32
+ schema_ (Union[Dict, None]): Schema in OpenAI format.
33
+ pre_processor (Union[Callable, None]): Function to preprocess input arguments.
34
+ pre_processor_kwargs (Union[Dict, None]): Keyword arguments for the pre-processor.
35
+ post_processor (Union[Callable, None]): Function to post-process the result.
36
+ post_processor_kwargs (Union[Dict, None]): Keyword arguments for the post-processor.
37
+ parser (Union[Callable, None]): Function to parse the result to a JSON serializable format.
38
+ """
39
+
40
+ function: Callable = Field(
41
+ ...,
42
+ description="The callable function or capability of the tool.",
43
+ )
44
+
45
+ schema_: Union[Dict, None] = Field(
46
+ None,
47
+ description="Schema in OpenAI format.",
48
+ )
49
+
50
+ pre_processor: Union[Callable, None] = None
51
+ pre_processor_kwargs: Union[Dict, None] = None
52
+
53
+ post_processor: Union[Callable, None] = None
54
+ post_processor_kwargs: Union[Dict, None] = None
55
+
56
+ parser: Union[Callable, None] = None # Parse result to JSON serializable format
57
+
58
+ @field_serializer("function", check_fields=False)
59
+ def serialize_func(self, func: Callable) -> str:
60
+ """
61
+ Serialize the function for storage or transmission.
62
+
63
+ Args:
64
+ func (Callable): The function to serialize.
65
+
66
+ Returns:
67
+ str: The name of the function.
68
+ """
69
+ return func.__name__
70
+
71
+ @property
72
+ def name(self) -> str:
73
+ """
74
+ Get the name of the function from the schema.
75
+
76
+ Returns:
77
+ str: The name of the function.
78
+ """
79
+ return self.schema_["function"]["name"]
80
+
81
+ async def invoke(self, kwargs: Dict = {}) -> Any:
82
+ """
83
+ Invoke the tool's function with optional pre-processing and post-processing.
84
+
85
+ Args:
86
+ kwargs (Dict): The arguments to pass to the function.
87
+
88
+ Returns:
89
+ Any: The result of the function call.
90
+ """
91
+ if self.pre_processor:
92
+ pre_process_kwargs = self.pre_processor_kwargs or {}
93
+ kwargs = await call_handler(
94
+ self.pre_processor(kwargs, **pre_process_kwargs)
95
+ )
96
+ if not isinstance(kwargs, dict):
97
+ raise ValueError("Pre-processor must return a dictionary.")
98
+
99
+ func_call_ = FunctionCalling(function=self.function, arguments=kwargs)
100
+ try:
101
+ result = await func_call_.invoke()
102
+ except Exception:
103
+ return None
104
+
105
+ if self.post_processor:
106
+ post_process_kwargs = self.post_processor_kwargs or {}
107
+ result = await call_handler(
108
+ self.post_processor(result, **post_process_kwargs)
109
+ )
110
+
111
+ return result if not self.parser else self.parser(result)
112
+
113
+
114
+ TOOL_TYPE = Union[bool, Tool, str, List[Union[Tool, str, Dict]], Dict]