lionagi 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) 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} +83 -67
  35. lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
  36. lionagi/core/generic/__init__.py +3 -33
  37. lionagi/core/generic/edge.py +42 -92
  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/__init__.py +0 -0
  109. lionagi/experimental/knowledge/base.py +10 -0
  110. lionagi/experimental/knowledge/graph.py +0 -0
  111. lionagi/experimental/memory/__init__.py +0 -0
  112. lionagi/experimental/strategies/__init__.py +0 -0
  113. lionagi/experimental/strategies/base.py +1 -0
  114. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  115. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  116. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  117. lionagi/integrations/chunker/chunk.py +161 -24
  118. lionagi/integrations/config/oai_configs.py +34 -3
  119. lionagi/integrations/config/openrouter_configs.py +14 -2
  120. lionagi/integrations/loader/load.py +122 -21
  121. lionagi/integrations/loader/load_util.py +6 -77
  122. lionagi/integrations/provider/_mapping.py +46 -0
  123. lionagi/integrations/provider/litellm.py +2 -1
  124. lionagi/integrations/provider/mlx_service.py +16 -9
  125. lionagi/integrations/provider/oai.py +91 -4
  126. lionagi/integrations/provider/ollama.py +6 -5
  127. lionagi/integrations/provider/openrouter.py +115 -8
  128. lionagi/integrations/provider/services.py +2 -2
  129. lionagi/integrations/provider/transformers.py +18 -22
  130. lionagi/integrations/storage/__init__.py +3 -3
  131. lionagi/integrations/storage/neo4j.py +52 -60
  132. lionagi/integrations/storage/storage_util.py +45 -47
  133. lionagi/integrations/storage/structure_excel.py +285 -0
  134. lionagi/integrations/storage/to_excel.py +23 -7
  135. lionagi/libs/__init__.py +26 -1
  136. lionagi/libs/ln_api.py +75 -20
  137. lionagi/libs/ln_context.py +37 -0
  138. lionagi/libs/ln_convert.py +21 -9
  139. lionagi/libs/ln_func_call.py +69 -28
  140. lionagi/libs/ln_image.py +107 -0
  141. lionagi/libs/ln_nested.py +26 -11
  142. lionagi/libs/ln_parse.py +82 -23
  143. lionagi/libs/ln_queue.py +16 -0
  144. lionagi/libs/ln_tokenize.py +164 -0
  145. lionagi/libs/ln_validate.py +16 -0
  146. lionagi/libs/special_tokens.py +172 -0
  147. lionagi/libs/sys_util.py +95 -24
  148. lionagi/lions/coder/code_form.py +13 -0
  149. lionagi/lions/coder/coder.py +50 -3
  150. lionagi/lions/coder/util.py +30 -25
  151. lionagi/tests/libs/test_func_call.py +23 -21
  152. lionagi/tests/libs/test_nested.py +36 -21
  153. lionagi/tests/libs/test_parse.py +1 -1
  154. lionagi/tests/test_core/collections/__init__.py +0 -0
  155. lionagi/tests/test_core/collections/test_component.py +206 -0
  156. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  157. lionagi/tests/test_core/collections/test_flow.py +145 -0
  158. lionagi/tests/test_core/collections/test_pile.py +171 -0
  159. lionagi/tests/test_core/collections/test_progression.py +129 -0
  160. lionagi/tests/test_core/generic/__init__.py +0 -0
  161. lionagi/tests/test_core/generic/test_edge.py +67 -0
  162. lionagi/tests/test_core/generic/test_graph.py +96 -0
  163. lionagi/tests/test_core/generic/test_node.py +106 -0
  164. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  165. lionagi/tests/test_core/test_branch.py +115 -294
  166. lionagi/tests/test_core/test_form.py +46 -0
  167. lionagi/tests/test_core/test_report.py +105 -0
  168. lionagi/tests/test_core/test_validator.py +111 -0
  169. lionagi/version.py +1 -1
  170. lionagi-0.2.0.dist-info/LICENSE +202 -0
  171. lionagi-0.2.0.dist-info/METADATA +272 -0
  172. lionagi-0.2.0.dist-info/RECORD +240 -0
  173. lionagi/core/branch/base.py +0 -653
  174. lionagi/core/branch/branch.py +0 -474
  175. lionagi/core/branch/flow_mixin.py +0 -96
  176. lionagi/core/branch/util.py +0 -323
  177. lionagi/core/direct/__init__.py +0 -19
  178. lionagi/core/direct/cot.py +0 -123
  179. lionagi/core/direct/plan.py +0 -164
  180. lionagi/core/direct/predict.py +0 -166
  181. lionagi/core/direct/react.py +0 -171
  182. lionagi/core/direct/score.py +0 -279
  183. lionagi/core/direct/select.py +0 -170
  184. lionagi/core/direct/sentiment.py +0 -1
  185. lionagi/core/direct/utils.py +0 -110
  186. lionagi/core/direct/vote.py +0 -64
  187. lionagi/core/execute/base_executor.py +0 -47
  188. lionagi/core/flow/baseflow.py +0 -23
  189. lionagi/core/flow/monoflow/ReAct.py +0 -238
  190. lionagi/core/flow/monoflow/__init__.py +0 -9
  191. lionagi/core/flow/monoflow/chat.py +0 -95
  192. lionagi/core/flow/monoflow/chat_mixin.py +0 -253
  193. lionagi/core/flow/monoflow/followup.py +0 -213
  194. lionagi/core/flow/polyflow/__init__.py +0 -1
  195. lionagi/core/flow/polyflow/chat.py +0 -251
  196. lionagi/core/form/action_form.py +0 -26
  197. lionagi/core/form/field_validator.py +0 -287
  198. lionagi/core/form/form.py +0 -302
  199. lionagi/core/form/mixin.py +0 -214
  200. lionagi/core/form/scored_form.py +0 -13
  201. lionagi/core/generic/action.py +0 -26
  202. lionagi/core/generic/component.py +0 -455
  203. lionagi/core/generic/condition.py +0 -44
  204. lionagi/core/generic/mail.py +0 -90
  205. lionagi/core/generic/mailbox.py +0 -36
  206. lionagi/core/generic/relation.py +0 -70
  207. lionagi/core/generic/signal.py +0 -22
  208. lionagi/core/generic/structure.py +0 -362
  209. lionagi/core/generic/transfer.py +0 -20
  210. lionagi/core/generic/work.py +0 -40
  211. lionagi/core/graph/graph.py +0 -126
  212. lionagi/core/graph/tree.py +0 -190
  213. lionagi/core/mail/schema.py +0 -63
  214. lionagi/core/messages/schema.py +0 -325
  215. lionagi/core/tool/__init__.py +0 -5
  216. lionagi/core/tool/tool.py +0 -28
  217. lionagi/core/tool/tool_manager.py +0 -282
  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/work/_logger.py +0 -25
  224. lionagi/experimental/work/schema.py +0 -30
  225. lionagi/experimental/work/tests.py +0 -72
  226. lionagi/experimental/work/work_function.py +0 -89
  227. lionagi/experimental/work/worker.py +0 -12
  228. lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
  229. lionagi/tests/test_core/test_base_branch.py +0 -426
  230. lionagi/tests/test_core/test_chat_flow.py +0 -63
  231. lionagi/tests/test_core/test_mail_manager.py +0 -75
  232. lionagi/tests/test_core/test_prompts.py +0 -51
  233. lionagi/tests/test_core/test_session.py +0 -254
  234. lionagi/tests/test_core/test_session_base_util.py +0 -313
  235. lionagi/tests/test_core/test_tool_manager.py +0 -95
  236. lionagi-0.1.1.dist-info/LICENSE +0 -9
  237. lionagi-0.1.1.dist-info/METADATA +0 -174
  238. lionagi-0.1.1.dist-info/RECORD +0 -190
  239. /lionagi/core/{branch → _setting}/__init__.py +0 -0
  240. /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
  241. /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
  242. /lionagi/core/{form → agent/plan}/__init__.py +0 -0
  243. /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
  244. /lionagi/core/{graph → director}/__init__.py +0 -0
  245. /lionagi/core/{messages → engine}/__init__.py +0 -0
  246. /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
  247. /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
  248. /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
  249. /lionagi/{experimental/tool → core/unit/template}/__init__.py +0 -0
  250. /lionagi/{experimental/work → core/validator}/__init__.py +0 -0
  251. /lionagi/core/{flow/mono_chat_mixin.py → work/__init__.py} +0 -0
  252. /lionagi/experimental/{work/exchange.py → compressor/__init__.py} +0 -0
  253. /lionagi/experimental/{work/util.py → directive/template/__init__.py} +0 -0
  254. /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
  255. /lionagi/{tests/libs/test_async.py → experimental/evaluator/__init__.py} +0 -0
  256. {lionagi-0.1.1.dist-info → lionagi-0.2.0.dist-info}/WHEEL +0 -0
  257. {lionagi-0.1.1.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
@@ -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)