lionagi 0.1.2__py3-none-any.whl → 0.2.0__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 +74 -0
  94. lionagi/core/work/work_function.py +92 -0
  95. lionagi/core/work/work_queue.py +81 -0
  96. lionagi/core/work/worker.py +195 -0
  97. lionagi/core/work/worklog.py +124 -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.0.dist-info/LICENSE +202 -0
  168. lionagi-0.2.0.dist-info/METADATA +272 -0
  169. lionagi-0.2.0.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.0.dist-info}/WHEEL +0 -0
  268. {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
@@ -1,70 +0,0 @@
1
- """
2
- A module for representing relationships between nodes in a graph structure,
3
- encapsulating incoming and outgoing edges.
4
- """
5
-
6
- from pydantic import Field
7
- from pydantic.dataclasses import dataclass
8
- from lionagi.libs import convert
9
- from lionagi.core.generic.edge import Edge
10
-
11
-
12
- @dataclass
13
- class Relations:
14
- """
15
- Represents the relationships of a node via its incoming and outgoing edges.
16
-
17
- This class stores edges in two dictionaries: `preceding` for outgoing edges
18
- and `succeeding` for incoming edges. It provides properties to access all
19
- edges together and to get a unique set of all connected node IDs.
20
-
21
- Attributes:
22
- preceding (dict[str, Edge]): A dictionary of outgoing edges from the
23
- node, with the edge ID as the key and the `Edge` object as the
24
- value. Represents edges leading from this node to other nodes.
25
- succeeding (dict[str, Edge]): A dictionary of incoming edges to the
26
- node, with the edge ID as the key and the `Edge` object as the
27
- value. Represents edges from other nodes leading to this node.
28
- """
29
-
30
- points_to: dict[str, Edge] = Field(
31
- title="Outgoing edges",
32
- default_factory=dict,
33
- description="The Outgoing edges of the node, reads self precedes other, \
34
- {edge_id: Edge}",
35
- )
36
-
37
- pointed_by: dict[str, Edge] = Field(
38
- title="Incoming edges",
39
- default_factory=dict,
40
- description="The Incoming edges of the node, reads self succeeds other, \
41
- {edge_id: Edge}",
42
- )
43
-
44
- @property
45
- def all_edges(self) -> dict[str, Edge]:
46
- """
47
- Combines and returns all incoming and outgoing edges of the node.
48
-
49
- Returns:
50
- dict[str, Edge]: A dictionary of all edges connected to the node,
51
- including both preceding (outgoing) and succeeding (incoming)
52
- edges, indexed by edge IDs.
53
- """
54
- return {**self.points_to, **self.pointed_by}
55
-
56
- @property
57
- def all_nodes(self) -> set[str]:
58
- """
59
- Extracts and returns a unique set of all node IDs connected to this
60
- node through its edges.
61
-
62
- It processes both heads and tails of each edge in `all_edges`, flattens
63
- the list to a one-dimensional list, and then converts it to a set to
64
- ensure uniqueness.
65
-
66
- Returns:
67
- set[str]: A set of unique node IDs connected to this node, derived
68
- from both incoming and outgoing edges.
69
- """
70
- return set(convert.to_list([[i.head, i.tail] for i in self.all_edges.values()]))
@@ -1,22 +0,0 @@
1
- from abc import ABC
2
- from collections import deque
3
- from lionagi.core.generic import BaseNode
4
- from lionagi.core.generic.mail import Mail
5
- from typing import Any
6
-
7
-
8
- class Signal(BaseNode, ABC): ...
9
-
10
-
11
- class Start(Signal):
12
- pending_outs: deque = deque()
13
-
14
- def trigger(self, context: Any, structure_id: str, executable_id: str):
15
- start_mail_content = {"context": context, "structure_id": structure_id}
16
- start_mail = Mail(
17
- sender=self.id_,
18
- recipient=executable_id,
19
- category="start",
20
- package=start_mail_content,
21
- )
22
- self.pending_outs.append(start_mail)
@@ -1,362 +0,0 @@
1
- """
2
- This module provides the BaseStructure class, which represents a node with
3
- internal edges and nodes, including methods for managing them.
4
-
5
- The BaseStructure class inherits from the Node class and provides functionality
6
- for adding, removing, and querying nodes and edges within the structure, as
7
- well as checking if the structure is empty.
8
- """
9
-
10
- from functools import singledispatchmethod
11
- from typing import Any
12
- from pydantic import Field
13
-
14
- from lionagi.libs import convert, func_call
15
- from .condition import Condition
16
- from .edge import Edge
17
- from .node import Node
18
- from .action import ActionSelection
19
- from lionagi.core.tool import Tool
20
-
21
-
22
- class BaseStructure(Node):
23
- """
24
- Represents a node with internal edges and nodes, including methods for
25
- managing them.
26
-
27
- Provides functionality for adding, removing, and querying nodes and edges
28
- within the structure, as well as checking if the structure is empty.
29
- """
30
-
31
- internal_nodes: dict[str, Node] = Field(
32
- default_factory=dict,
33
- description="A dictionary of all nodes within the structure, keyed by \
34
- node ID.",
35
- )
36
-
37
- @property
38
- def internal_edges(self) -> dict[str, Edge]:
39
- """
40
- Gets all internal edges indexed by their ID.
41
-
42
- Returns:
43
- dict[str, Edge]: A dictionary of all internal edges within the
44
- structure.
45
- """
46
- edges = {}
47
- for i in self.internal_nodes.values():
48
- for _, edge in i.edges.items():
49
- if edge.id_ not in edges:
50
- edges[edge.id_] = edge
51
- return edges
52
-
53
- @property
54
- def is_empty(self) -> bool:
55
- """
56
- Checks if the structure is empty (contains no nodes).
57
-
58
- Returns:
59
- bool: True if the structure has no nodes, False otherwise.
60
- """
61
- return len(self.internal_nodes) == 0
62
-
63
- def clear(self):
64
- """Clears all nodes and edges from the structure."""
65
- self.internal_nodes.clear()
66
-
67
- def get_node_edges(
68
- self,
69
- node: Node | str,
70
- node_as: str = "both",
71
- label: list | str = None,
72
- ) -> dict[str, list[Edge]]:
73
- """
74
- Retrieves edges associated with a specific node.
75
-
76
- Args:
77
- node (Node | str): The node or its ID to query for edges.
78
- node_as (str, optional): The role of the node in the edges.
79
- Defaults to "both".
80
- - "both" or "all": Retrieve edges where the node is either the
81
- head or tail.
82
- - "head", "predecessor", "outgoing", "out", or "predecessors":
83
- Retrieve edges where the node is the head.
84
- - "tail", "successor", "incoming", "in", or "successors":
85
- Retrieve edges where the node is the tail.
86
- label (list | str, optional): Filter edges by label(s). Defaults to
87
- None.
88
-
89
- Returns:
90
- dict[str, list[Edge]]: A dictionary mapping related node IDs to
91
- lists of associated edges based on the specified criteria.
92
-
93
- Raises:
94
- ValueError: If an invalid role is specified for the node.
95
- """
96
-
97
- node = self.get_node(node)
98
-
99
- if node_as in ["all", "both"]:
100
- all_node_edges = {i: [] for i in node.related_nodes}
101
-
102
- for k, v in node.node_relations["points_to"].items():
103
- all_node_edges[k].append(v)
104
-
105
- for k, v in node.node_relations["pointed_by"].items():
106
- all_node_edges[k].append(v)
107
-
108
- for k, v in all_node_edges.items():
109
- all_node_edges[k] = convert.to_list(v, dropna=True, flatten=True)
110
-
111
- if label:
112
- for k, v in all_node_edges.items():
113
- all_node_edges[k] = (
114
- v
115
- if v.label in convert.to_list(label, dropna=True, flatten=True)
116
- else []
117
- )
118
-
119
- return {k: v for k, v in all_node_edges.items() if len(v) > 0}
120
-
121
- elif node_as in ["head", "predecessor", "outgoing", "out", "predecessors"]:
122
- return node.node_relations["points_to"]
123
-
124
- elif node_as in ["tail", "successor", "incoming", "in", "successors"]:
125
- return node.node_relations["pointed_by"]
126
-
127
- else:
128
- raise ValueError(
129
- f"Invalid value for self_as: {node_as}, must be 'head' or 'tail'"
130
- )
131
-
132
- def relate_nodes(
133
- self,
134
- head: Node,
135
- tail: Node,
136
- condition: Condition | None = None,
137
- bundle=False,
138
- label=None,
139
- **kwargs,
140
- ):
141
- """
142
- Relates two nodes within the structure with an edge.
143
-
144
- Args:
145
- head (Node): The head node of the edge.
146
- tail (Node): The tail node of the edge.
147
- condition (Condition | None, optional): The condition associated
148
- with the edge. Defaults to None.
149
- label (optional): The label for the edge.
150
- **kwargs: Additional keyword arguments for the edge creation.
151
-
152
- Raises:
153
- ValueError: If there is an error adding the edge.
154
- """
155
- try:
156
- if isinstance(head, Tool) or isinstance(head, ActionSelection):
157
- raise ValueError(
158
- f"type {type(tail)} should not be the head of the relationship, "
159
- f"please switch position and attach it to the tail of the relationship"
160
- )
161
-
162
- if isinstance(tail, Tool) or isinstance(tail, ActionSelection):
163
- bundle = True
164
-
165
- if head.id_ not in self.internal_nodes:
166
- self.add_node(head)
167
-
168
- if tail.id_ not in self.internal_nodes:
169
- self.add_node(tail)
170
-
171
- head.relate(
172
- tail,
173
- node_as="head",
174
- condition=condition,
175
- label=label,
176
- bundle=bundle,
177
- **kwargs,
178
- )
179
- except Exception as e:
180
- raise ValueError(f"Error adding edge: {e}") from e
181
-
182
- def remove_edge(
183
- self, edge: Edge | str | list[str | Edge] | dict[str, Edge]
184
- ) -> bool:
185
- """
186
- Removes one or more edges from the structure.
187
-
188
- Args:
189
- edge: The edge(s) to be removed, specified as single edge, its ID,
190
- a list, or a dictionary of edges.
191
-
192
- Returns:
193
- bool: True if all specified edges were successfully removed, False
194
- otherwise.
195
- """
196
- if isinstance(edge, list):
197
- for i in edge:
198
- self._remove_edge(i)
199
-
200
- elif isinstance(edge, dict):
201
- for i in edge.values():
202
- self._remove_edge(i)
203
-
204
- elif isinstance(edge, (Edge, str)):
205
- self._remove_edge(edge)
206
-
207
- @singledispatchmethod
208
- def add_node(self, node: Any) -> None:
209
- """
210
- Method placeholder for adding a node. Will be implemented by register
211
- decorators.
212
-
213
- Args:
214
- node (Any): The node to be added.
215
-
216
- Raises:
217
- NotImplementedError: If the method is not implemented for the type
218
- of node.
219
- """
220
- raise NotImplementedError
221
-
222
- @add_node.register(Node)
223
- def _(self, node) -> None:
224
- if node.id_ not in self.internal_nodes:
225
- self.internal_nodes[node.id_] = node
226
- else:
227
- raise ValueError(f"Node {node.id_} already exists in structure.")
228
-
229
- @add_node.register(list)
230
- def _(self, node) -> None:
231
- for _node in node:
232
- self.add_node(_node)
233
-
234
- @add_node.register(dict)
235
- def _(self, node) -> None:
236
- self.add_node(list(node.values()))
237
-
238
- def get_node(self, node, default="undefined"):
239
- """
240
- Retrieves one or more nodes by ID, node instance, or a collection of
241
- IDs/nodes.
242
-
243
- Args:
244
- node: A single node, node ID, or a collection of nodes/IDs to
245
- retrieve.
246
- default: The default value to return if a node is not found.
247
-
248
- Returns:
249
- The node(s) corresponding to the input, or the default value for
250
- any not found.
251
- """
252
- if not isinstance(node, (list, dict, set)):
253
- return self._get_node(node, default=default)
254
- else:
255
- node = list(node) if isinstance(node, set) else node
256
- node = list(node.values()) if isinstance(node, dict) else node
257
-
258
- return func_call.lcall(node, self._get_node, default=default)
259
-
260
- @singledispatchmethod
261
- def remove_node(self, node: Any) -> bool:
262
- """
263
- Method placeholder for removing a node. Will be implemented by register
264
- decorators.
265
-
266
- Args:
267
- node (Any): The node to be removed.
268
-
269
- Returns:
270
- bool: True if the node was successfully removed, False otherwise.
271
-
272
- Raises:
273
- NotImplementedError: If the method is not implemented for the type
274
- of node.
275
- """
276
- return NotImplementedError
277
-
278
- @remove_node.register(Node)
279
- def _(self, node: Node) -> bool:
280
- return self._remove_node(node)
281
-
282
- @remove_node.register(str)
283
- def _(self, node: str) -> bool:
284
- return self._remove_node(node)
285
-
286
- @remove_node.register(list)
287
- def _(self, node: list[str | Node]) -> bool:
288
- for i in node:
289
- self.remove_node(i)
290
-
291
- @remove_node.register(dict)
292
- def _(self, node: dict[str, Node]) -> bool:
293
- self.remove_node(list(node.values()))
294
-
295
- def _pop_node(self, node: Node | str, default="undefined"):
296
- node = self.get_node(node, default=default)
297
- self.remove_node(node)
298
- return node
299
-
300
- @singledispatchmethod
301
- def pop_node(self, node: Any, default="undefined") -> Node:
302
- return NotImplementedError
303
-
304
- @pop_node.register(Node)
305
- def _(self, node: Node, default="undefined") -> Node:
306
- return self._pop_node(node, default=default)
307
-
308
- @pop_node.register(str)
309
- def _(self, node: str, default="undefined") -> Node:
310
- return self._pop_node(node, default=default)
311
-
312
- @pop_node.register(list)
313
- def _(self, node: list[str | Node], default="undefined") -> list[Node]:
314
- nodes = []
315
- for i in node:
316
- nodes.append(self.pop_node(i, default=default))
317
- return nodes
318
-
319
- @pop_node.register(dict)
320
- def _(self, node: dict[str, Node], default="undefined") -> list[Node]:
321
- return self.pop_node(list(node.values()), default=default)
322
-
323
- def _remove_edge(self, edge: Edge | str) -> bool:
324
- """Helper method to remove an edge by ID or edge instance.
325
-
326
- Args:
327
- edge (Edge | str): The edge or its ID to remove.
328
-
329
- Returns:
330
- bool: True if the edge was successfully removed, False otherwise.
331
-
332
- Raises:
333
- ValueError: If the edge is not found within the structure.
334
- """
335
- edge_id = edge.id_ if isinstance(edge, Edge) else edge
336
- if not edge_id in self.internal_edges:
337
- raise ValueError(f"Edge {edge_id} not found in structure.")
338
-
339
- edge = self.internal_edges[edge_id]
340
-
341
- head: Node = self.get_node(edge.head)
342
- tail: Node = self.get_node(edge.tail)
343
-
344
- head.unrelate(tail, edge=edge)
345
-
346
- def _get_node(self, node: Node | str, default="undefined") -> Node:
347
- node_id_ = node.id_ if isinstance(node, Node) else node
348
- if not node_id_ in self.internal_nodes:
349
- if default == "undefined":
350
- raise KeyError(f"Node {node_id_} not found in structure.")
351
- return default
352
- return self.internal_nodes[node_id_]
353
-
354
- def _remove_node(self, node: Node | str) -> bool:
355
- try:
356
- node = self.get_node(node)
357
- related_nodes = self.get_node(node.related_nodes)
358
- func_call.lcall(related_nodes, node.unrelate)
359
- self.internal_nodes.pop(node.id_)
360
- return True
361
- except Exception as e:
362
- raise ValueError(f"Error removing node: {e}") from e
@@ -1,20 +0,0 @@
1
- from collections import deque
2
- from pydantic import Field
3
- from pydantic.dataclasses import dataclass
4
-
5
- from lionagi.core.generic.mail import Mail
6
- from lionagi.core.generic.signal import Signal
7
-
8
-
9
- @dataclass
10
- class Transfer:
11
-
12
- schedule: dict[str, deque[Mail | Signal]] = Field(
13
- default_factory=dict,
14
- description="The sequence of all pending mails - {direction: deque[mail_id]}",
15
- )
16
-
17
- @property
18
- def is_empty(self) -> bool:
19
- """Returns a flag indicating whether the transfer is empty."""
20
- return not any(self.schedule.values())
@@ -1,40 +0,0 @@
1
- from pydantic.dataclasses import dataclass
2
- from typing import Any
3
- from abc import ABC, abstractmethod
4
- from pydantic import Field
5
-
6
- from .node import Node
7
-
8
-
9
- @dataclass
10
- class Work:
11
-
12
- work_completed: bool = Field(
13
- default=False,
14
- description="A flag indicating whether the work is already completed.",
15
- )
16
-
17
- work_result: Any | None = Field(
18
- default=None,
19
- description="The result of the work.",
20
- )
21
-
22
- context: dict | str | None = Field(
23
- None, description="The context buffer for the next instruction."
24
- )
25
-
26
-
27
- class Worker(Node, ABC):
28
- stopped: bool = False
29
-
30
- @abstractmethod
31
- def perform(self, *args, **kwargs):
32
- pass
33
-
34
- @abstractmethod
35
- def forward(self, *args, **kwargs):
36
- pass
37
-
38
- def stop(self):
39
- self.stopped = True
40
- return True
@@ -1,126 +0,0 @@
1
- """
2
- This module provides the Graph class, which represents a graph structure
3
- extending the capabilities of BaseStructure to include graph-specific
4
- properties and methods, such as detecting heads, acyclicity, and conversion to
5
- NetworkX for visualization.
6
- """
7
-
8
- from collections import deque
9
- from typing import Any
10
-
11
- from lionagi.core.generic import Node
12
- from lionagi.core.generic import BaseStructure
13
-
14
-
15
- class Graph(BaseStructure):
16
- """
17
- Represents a graph structure extending the capabilities of BaseStructure.
18
-
19
- Includes graph-specific properties and methods, such as detecting heads,
20
- acyclicity, and conversion to NetworkX for visualization.
21
- """
22
-
23
- def get_heads(self):
24
- return [
25
- node
26
- for node in self.internal_nodes.values()
27
- if not node.relations.pointed_by
28
- ]
29
-
30
- @property
31
- def acyclic(self) -> bool:
32
- """
33
- Checks if the graph is acyclic.
34
-
35
- An acyclic graph contains no cycles and can be represented as a directed
36
- acyclic graph (DAG).
37
-
38
- Returns:
39
- bool: True if the graph is acyclic, False otherwise.
40
- """
41
- node_ids = list(self.internal_nodes.keys())
42
- check_deque = deque(node_ids)
43
- check_dict = {key: 0 for key in node_ids} # 0: not visited, 1: temp, 2: perm
44
-
45
- def visit(key):
46
- if check_dict[key] == 2:
47
- return True
48
- elif check_dict[key] == 1:
49
- return False
50
-
51
- check_dict[key] = 1
52
-
53
- points_to_edges = self.internal_nodes[key].relations.points_to
54
-
55
- for _, edge in points_to_edges.items():
56
- check = visit(edge.tail)
57
- if not check:
58
- return False
59
-
60
- check_dict[key] = 2
61
- return True
62
-
63
- while check_deque:
64
- key = check_deque.pop()
65
- check = visit(key)
66
- if not check:
67
- return False
68
- return True
69
-
70
- def to_networkx(self, **kwargs) -> Any:
71
- """
72
- Converts the graph into a NetworkX graph object.
73
-
74
- The NetworkX graph object can be used for further analysis or
75
- visualization.
76
-
77
- Args:
78
- **kwargs: Additional keyword arguments to pass to the NetworkX graph
79
- constructor.
80
-
81
- Returns:
82
- Any: A NetworkX graph object representing the current graph
83
- structure.
84
- """
85
- from lionagi.libs import SysUtil
86
-
87
- SysUtil.check_import("networkx")
88
-
89
- from networkx import DiGraph
90
-
91
- g = DiGraph(**kwargs)
92
- for node_id, node in self.internal_nodes.items():
93
- node_info = node.to_dict()
94
- node_info.pop("id_")
95
- node_info.update({"class_name": node.class_name})
96
- g.add_node(node_id, **node_info)
97
-
98
- for _edge in list(self.internal_edges.values()):
99
- edge_info = _edge.to_dict()
100
- edge_info.pop("id_")
101
- edge_info.update({"class_name": _edge.__class__.__name__})
102
- source_node_id = edge_info.pop("head")
103
- target_node_id = edge_info.pop("tail")
104
- g.add_edge(source_node_id, target_node_id, **edge_info)
105
-
106
- return g
107
-
108
- def display(self, **kwargs):
109
- """
110
- Displays the graph using NetworkX's drawing capabilities.
111
-
112
- This method requires NetworkX and a compatible plotting library (like
113
- matplotlib) to be installed.
114
-
115
- Args:
116
- **kwargs: Additional keyword arguments to pass to the NetworkX graph
117
- constructor.
118
- """
119
- from lionagi.libs import SysUtil
120
-
121
- SysUtil.check_import("networkx")
122
-
123
- from networkx import draw
124
-
125
- g = self.to_networkx(**kwargs)
126
- draw(g)