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.
- lionagi/__init__.py +60 -5
- lionagi/core/__init__.py +0 -25
- lionagi/core/_setting/_setting.py +59 -0
- lionagi/core/action/__init__.py +14 -0
- lionagi/core/action/function_calling.py +136 -0
- lionagi/core/action/manual.py +1 -0
- lionagi/core/action/node.py +109 -0
- lionagi/core/action/tool.py +114 -0
- lionagi/core/action/tool_manager.py +356 -0
- lionagi/core/agent/base_agent.py +27 -13
- lionagi/core/agent/eval/evaluator.py +1 -0
- lionagi/core/agent/eval/vote.py +40 -0
- lionagi/core/agent/learn/learner.py +59 -0
- lionagi/core/agent/plan/unit_template.py +1 -0
- lionagi/core/collections/__init__.py +17 -0
- lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
- lionagi/core/collections/abc/__init__.py +53 -0
- lionagi/core/collections/abc/component.py +615 -0
- lionagi/core/collections/abc/concepts.py +297 -0
- lionagi/core/collections/abc/exceptions.py +150 -0
- lionagi/core/collections/abc/util.py +45 -0
- lionagi/core/collections/exchange.py +161 -0
- lionagi/core/collections/flow.py +426 -0
- lionagi/core/collections/model.py +419 -0
- lionagi/core/collections/pile.py +913 -0
- lionagi/core/collections/progression.py +236 -0
- lionagi/core/collections/util.py +64 -0
- lionagi/core/director/direct.py +314 -0
- lionagi/core/director/director.py +2 -0
- lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
- lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
- lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
- lionagi/core/executor/base_executor.py +90 -0
- lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
- lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
- lionagi/core/generic/__init__.py +3 -33
- lionagi/core/generic/edge.py +29 -79
- lionagi/core/generic/edge_condition.py +16 -0
- lionagi/core/generic/graph.py +236 -0
- lionagi/core/generic/hyperedge.py +1 -0
- lionagi/core/generic/node.py +156 -221
- lionagi/core/generic/tree.py +48 -0
- lionagi/core/generic/tree_node.py +79 -0
- lionagi/core/mail/__init__.py +12 -0
- lionagi/core/mail/mail.py +25 -0
- lionagi/core/mail/mail_manager.py +139 -58
- lionagi/core/mail/package.py +45 -0
- lionagi/core/mail/start_mail.py +36 -0
- lionagi/core/message/__init__.py +19 -0
- lionagi/core/message/action_request.py +133 -0
- lionagi/core/message/action_response.py +135 -0
- lionagi/core/message/assistant_response.py +95 -0
- lionagi/core/message/instruction.py +234 -0
- lionagi/core/message/message.py +101 -0
- lionagi/core/message/system.py +86 -0
- lionagi/core/message/util.py +283 -0
- lionagi/core/report/__init__.py +4 -0
- lionagi/core/report/base.py +217 -0
- lionagi/core/report/form.py +231 -0
- lionagi/core/report/report.py +166 -0
- lionagi/core/report/util.py +28 -0
- lionagi/core/rule/_default.py +16 -0
- lionagi/core/rule/action.py +99 -0
- lionagi/core/rule/base.py +238 -0
- lionagi/core/rule/boolean.py +56 -0
- lionagi/core/rule/choice.py +47 -0
- lionagi/core/rule/mapping.py +96 -0
- lionagi/core/rule/number.py +71 -0
- lionagi/core/rule/rulebook.py +109 -0
- lionagi/core/rule/string.py +52 -0
- lionagi/core/rule/util.py +35 -0
- lionagi/core/session/branch.py +431 -0
- lionagi/core/session/directive_mixin.py +287 -0
- lionagi/core/session/session.py +229 -903
- lionagi/core/structure/__init__.py +1 -0
- lionagi/core/structure/chain.py +1 -0
- lionagi/core/structure/forest.py +1 -0
- lionagi/core/structure/graph.py +1 -0
- lionagi/core/structure/tree.py +1 -0
- lionagi/core/unit/__init__.py +5 -0
- lionagi/core/unit/parallel_unit.py +245 -0
- lionagi/core/unit/template/action.py +81 -0
- lionagi/core/unit/template/base.py +51 -0
- lionagi/core/unit/template/plan.py +84 -0
- lionagi/core/unit/template/predict.py +109 -0
- lionagi/core/unit/template/score.py +124 -0
- lionagi/core/unit/template/select.py +104 -0
- lionagi/core/unit/unit.py +362 -0
- lionagi/core/unit/unit_form.py +305 -0
- lionagi/core/unit/unit_mixin.py +1168 -0
- lionagi/core/unit/util.py +71 -0
- lionagi/core/validator/validator.py +364 -0
- lionagi/core/work/work.py +74 -0
- lionagi/core/work/work_function.py +92 -0
- lionagi/core/work/work_queue.py +81 -0
- lionagi/core/work/worker.py +195 -0
- lionagi/core/work/worklog.py +124 -0
- lionagi/experimental/compressor/base.py +46 -0
- lionagi/experimental/compressor/llm_compressor.py +247 -0
- lionagi/experimental/compressor/llm_summarizer.py +61 -0
- lionagi/experimental/compressor/util.py +70 -0
- lionagi/experimental/directive/__init__.py +19 -0
- lionagi/experimental/directive/parser/base_parser.py +69 -2
- lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
- lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
- lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
- lionagi/experimental/knowledge/base.py +10 -0
- lionagi/experimental/memory/__init__.py +0 -0
- lionagi/experimental/strategies/__init__.py +0 -0
- lionagi/experimental/strategies/base.py +1 -0
- lionagi/integrations/bridge/langchain_/documents.py +4 -0
- lionagi/integrations/bridge/llamaindex_/index.py +30 -0
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
- lionagi/integrations/chunker/chunk.py +161 -24
- lionagi/integrations/config/oai_configs.py +34 -3
- lionagi/integrations/config/openrouter_configs.py +14 -2
- lionagi/integrations/loader/load.py +122 -21
- lionagi/integrations/loader/load_util.py +6 -77
- lionagi/integrations/provider/_mapping.py +46 -0
- lionagi/integrations/provider/litellm.py +2 -1
- lionagi/integrations/provider/mlx_service.py +16 -9
- lionagi/integrations/provider/oai.py +91 -4
- lionagi/integrations/provider/ollama.py +6 -5
- lionagi/integrations/provider/openrouter.py +115 -8
- lionagi/integrations/provider/services.py +2 -2
- lionagi/integrations/provider/transformers.py +18 -22
- lionagi/integrations/storage/__init__.py +3 -3
- lionagi/integrations/storage/neo4j.py +52 -60
- lionagi/integrations/storage/storage_util.py +44 -46
- lionagi/integrations/storage/structure_excel.py +43 -26
- lionagi/integrations/storage/to_excel.py +11 -4
- lionagi/libs/__init__.py +22 -1
- lionagi/libs/ln_api.py +75 -20
- lionagi/libs/ln_context.py +37 -0
- lionagi/libs/ln_convert.py +21 -9
- lionagi/libs/ln_func_call.py +69 -28
- lionagi/libs/ln_image.py +107 -0
- lionagi/libs/ln_nested.py +26 -11
- lionagi/libs/ln_parse.py +82 -23
- lionagi/libs/ln_queue.py +16 -0
- lionagi/libs/ln_tokenize.py +164 -0
- lionagi/libs/ln_validate.py +16 -0
- lionagi/libs/special_tokens.py +172 -0
- lionagi/libs/sys_util.py +95 -24
- lionagi/lions/coder/code_form.py +13 -0
- lionagi/lions/coder/coder.py +50 -3
- lionagi/lions/coder/util.py +30 -25
- lionagi/tests/libs/test_func_call.py +23 -21
- lionagi/tests/libs/test_nested.py +36 -21
- lionagi/tests/libs/test_parse.py +1 -1
- lionagi/tests/test_core/collections/__init__.py +0 -0
- lionagi/tests/test_core/collections/test_component.py +206 -0
- lionagi/tests/test_core/collections/test_exchange.py +138 -0
- lionagi/tests/test_core/collections/test_flow.py +145 -0
- lionagi/tests/test_core/collections/test_pile.py +171 -0
- lionagi/tests/test_core/collections/test_progression.py +129 -0
- lionagi/tests/test_core/generic/test_edge.py +67 -0
- lionagi/tests/test_core/generic/test_graph.py +96 -0
- lionagi/tests/test_core/generic/test_node.py +106 -0
- lionagi/tests/test_core/generic/test_tree_node.py +73 -0
- lionagi/tests/test_core/test_branch.py +115 -294
- lionagi/tests/test_core/test_form.py +46 -0
- lionagi/tests/test_core/test_report.py +105 -0
- lionagi/tests/test_core/test_validator.py +111 -0
- lionagi/version.py +1 -1
- lionagi-0.2.0.dist-info/LICENSE +202 -0
- lionagi-0.2.0.dist-info/METADATA +272 -0
- lionagi-0.2.0.dist-info/RECORD +240 -0
- lionagi/core/branch/base.py +0 -653
- lionagi/core/branch/branch.py +0 -474
- lionagi/core/branch/flow_mixin.py +0 -96
- lionagi/core/branch/util.py +0 -323
- lionagi/core/direct/__init__.py +0 -19
- lionagi/core/direct/cot.py +0 -123
- lionagi/core/direct/plan.py +0 -164
- lionagi/core/direct/predict.py +0 -166
- lionagi/core/direct/react.py +0 -171
- lionagi/core/direct/score.py +0 -279
- lionagi/core/direct/select.py +0 -170
- lionagi/core/direct/sentiment.py +0 -1
- lionagi/core/direct/utils.py +0 -110
- lionagi/core/direct/vote.py +0 -64
- lionagi/core/execute/base_executor.py +0 -47
- lionagi/core/flow/baseflow.py +0 -23
- lionagi/core/flow/monoflow/ReAct.py +0 -240
- lionagi/core/flow/monoflow/__init__.py +0 -9
- lionagi/core/flow/monoflow/chat.py +0 -95
- lionagi/core/flow/monoflow/chat_mixin.py +0 -253
- lionagi/core/flow/monoflow/followup.py +0 -215
- lionagi/core/flow/polyflow/__init__.py +0 -1
- lionagi/core/flow/polyflow/chat.py +0 -251
- lionagi/core/form/action_form.py +0 -26
- lionagi/core/form/field_validator.py +0 -287
- lionagi/core/form/form.py +0 -302
- lionagi/core/form/mixin.py +0 -214
- lionagi/core/form/scored_form.py +0 -13
- lionagi/core/generic/action.py +0 -26
- lionagi/core/generic/component.py +0 -532
- lionagi/core/generic/condition.py +0 -46
- lionagi/core/generic/mail.py +0 -90
- lionagi/core/generic/mailbox.py +0 -36
- lionagi/core/generic/relation.py +0 -70
- lionagi/core/generic/signal.py +0 -22
- lionagi/core/generic/structure.py +0 -362
- lionagi/core/generic/transfer.py +0 -20
- lionagi/core/generic/work.py +0 -40
- lionagi/core/graph/graph.py +0 -126
- lionagi/core/graph/tree.py +0 -190
- lionagi/core/mail/schema.py +0 -63
- lionagi/core/messages/schema.py +0 -325
- lionagi/core/tool/__init__.py +0 -5
- lionagi/core/tool/tool.py +0 -28
- lionagi/core/tool/tool_manager.py +0 -283
- lionagi/experimental/report/form.py +0 -64
- lionagi/experimental/report/report.py +0 -138
- lionagi/experimental/report/util.py +0 -47
- lionagi/experimental/tool/function_calling.py +0 -43
- lionagi/experimental/tool/manual.py +0 -66
- lionagi/experimental/tool/schema.py +0 -59
- lionagi/experimental/tool/tool_manager.py +0 -138
- lionagi/experimental/tool/util.py +0 -16
- lionagi/experimental/validator/rule.py +0 -139
- lionagi/experimental/validator/validator.py +0 -56
- lionagi/experimental/work/__init__.py +0 -10
- lionagi/experimental/work/async_queue.py +0 -54
- lionagi/experimental/work/schema.py +0 -73
- lionagi/experimental/work/work_function.py +0 -67
- lionagi/experimental/work/worker.py +0 -56
- lionagi/experimental/work2/form.py +0 -371
- lionagi/experimental/work2/report.py +0 -289
- lionagi/experimental/work2/schema.py +0 -30
- lionagi/experimental/work2/tests.py +0 -72
- lionagi/experimental/work2/work_function.py +0 -89
- lionagi/experimental/work2/worker.py +0 -12
- lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
- lionagi/tests/test_core/generic/test_component.py +0 -89
- lionagi/tests/test_core/test_base_branch.py +0 -426
- lionagi/tests/test_core/test_chat_flow.py +0 -63
- lionagi/tests/test_core/test_mail_manager.py +0 -75
- lionagi/tests/test_core/test_prompts.py +0 -51
- lionagi/tests/test_core/test_session.py +0 -254
- lionagi/tests/test_core/test_session_base_util.py +0 -313
- lionagi/tests/test_core/test_tool_manager.py +0 -95
- lionagi-0.1.2.dist-info/LICENSE +0 -9
- lionagi-0.1.2.dist-info/METADATA +0 -174
- lionagi-0.1.2.dist-info/RECORD +0 -206
- /lionagi/core/{branch → _setting}/__init__.py +0 -0
- /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
- /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
- /lionagi/core/{form → agent/plan}/__init__.py +0 -0
- /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
- /lionagi/core/{graph → director}/__init__.py +0 -0
- /lionagi/core/{messages → engine}/__init__.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
- /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
- /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
- /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
- /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
- /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
- /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
- /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
- /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
- /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
- /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
- /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/WHEEL +0 -0
- {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
lionagi/core/generic/node.py
CHANGED
@@ -1,285 +1,220 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
"""
|
2
|
+
This module defines the Node class, representing a node in a graph-like
|
3
|
+
structure within LionAGI. Nodes can form relationships with other nodes
|
4
|
+
through directed edges, enabling construction and manipulation of complex
|
5
|
+
relational networks.
|
6
|
+
|
7
|
+
Includes functionality for managing relationships, such as adding,
|
8
|
+
modifying, and removing edges, and querying related nodes and connections.
|
9
|
+
"""
|
4
10
|
|
5
|
-
from
|
6
|
-
from
|
11
|
+
from pydantic import Field
|
12
|
+
from pandas import Series
|
13
|
+
|
14
|
+
from lionagi.libs.ln_convert import to_list
|
15
|
+
|
16
|
+
from lionagi.core.collections.abc import (
|
17
|
+
Component,
|
18
|
+
Condition,
|
19
|
+
Relatable,
|
20
|
+
RelationError,
|
21
|
+
get_lion_id,
|
22
|
+
)
|
23
|
+
from lionagi.core.collections import pile, Pile
|
7
24
|
from lionagi.core.generic.edge import Edge
|
8
|
-
from lionagi.core.generic.relation import Relations
|
9
|
-
from lionagi.core.generic.mailbox import MailBox
|
10
25
|
|
11
26
|
|
12
|
-
class Node(
|
27
|
+
class Node(Component, Relatable):
|
13
28
|
"""
|
14
|
-
|
29
|
+
Node in a graph structure, can connect to other nodes via edges.
|
30
|
+
|
31
|
+
Extends `Component` by incorporating relational capabilities, allowing
|
32
|
+
nodes to connect through 'in' and 'out' directed edges, representing
|
33
|
+
incoming and outgoing relationships.
|
15
34
|
|
16
35
|
Attributes:
|
17
|
-
relations (
|
18
|
-
|
19
|
-
|
20
|
-
Properties:
|
21
|
-
related_nodes: A set of IDs representing nodes related to this node.
|
22
|
-
edges: A dictionary of all edges connected to this node.
|
23
|
-
node_relations: A dictionary categorizing preceding and succeeding
|
24
|
-
relations to this node.
|
25
|
-
precedessors: A list of node IDs that precede this node.
|
26
|
-
successors: A list of node IDs that succeed this node.
|
27
|
-
|
28
|
-
Methods:
|
29
|
-
relate(node, self_as, condition, **kwargs): Relates this node to
|
30
|
-
another node with an edge.
|
31
|
-
unrelate(node, edge): Removes one or all relations between this node
|
32
|
-
and another.
|
33
|
-
to_llama_index(node_type, **kwargs): Serializes this node for
|
34
|
-
LlamaIndex.
|
35
|
-
to_langchain(**kwargs): Serializes this node for Langchain.
|
36
|
-
from_llama_index(llama_node, **kwargs): Deserializes a node from
|
37
|
-
LlamaIndex data.
|
38
|
-
from_langchain(lc_doc): Deserializes a node from Langchain data.
|
39
|
-
__str__(): String representation of the node.
|
40
|
-
|
41
|
-
Raises:
|
42
|
-
ValueError: When invalid parameters are provided to methods.
|
36
|
+
relations (dict[str, Pile]): Dictionary holding 'Pile' instances
|
37
|
+
for incoming ('in') and outgoing ('out') edges.
|
43
38
|
"""
|
44
39
|
|
45
|
-
relations:
|
46
|
-
default_factory=
|
40
|
+
relations: dict[str, Pile] = Field(
|
41
|
+
default_factory=lambda: {"in": pile(), "out": pile()},
|
47
42
|
description="The relations of the node.",
|
48
|
-
alias="node_relations",
|
49
43
|
)
|
50
44
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
@property
|
46
|
+
def edges(self) -> Pile[Edge]:
|
47
|
+
"""
|
48
|
+
Get unified view of all incoming and outgoing edges.
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
Combined pile of all edges connected to this node.
|
52
|
+
"""
|
53
|
+
return self.relations["in"] + self.relations["out"]
|
55
54
|
|
56
55
|
@property
|
57
56
|
def related_nodes(self) -> list[str]:
|
58
|
-
"""
|
59
|
-
|
60
|
-
nodes.discard(self.id_)
|
61
|
-
return list(nodes)
|
57
|
+
"""
|
58
|
+
Get list of all unique node IDs directly related to this node.
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
"""
|
66
|
-
|
60
|
+
Returns:
|
61
|
+
List of node IDs related to this node.
|
62
|
+
"""
|
63
|
+
all_nodes = set(
|
64
|
+
to_list([[i.head, i.tail] for i in self.edges], flatten=True, dropna=True)
|
65
|
+
)
|
66
|
+
all_nodes.discard(self.ln_id)
|
67
|
+
return list(all_nodes)
|
67
68
|
|
68
69
|
@property
|
69
70
|
def node_relations(self) -> dict:
|
70
|
-
"""
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
71
|
+
"""
|
72
|
+
Get categorized view of direct relationships into groups.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
Dict with keys 'in' and 'out', each containing a mapping of
|
76
|
+
related node IDs to lists of edges representing relationships.
|
77
|
+
"""
|
78
|
+
out_node_edges = {}
|
79
|
+
if not self.relations["out"].is_empty():
|
80
|
+
for edge in self.relations["out"]:
|
81
|
+
for node_id in self.related_nodes:
|
82
|
+
if edge.tail == node_id:
|
83
|
+
out_node_edges.setdefault(node_id, []).append(edge)
|
84
|
+
|
85
|
+
in_node_edges = {}
|
86
|
+
if not self.relations["in"].is_empty():
|
87
|
+
for edge in self.relations["in"]:
|
88
|
+
for node_id in self.related_nodes:
|
89
|
+
if edge.head == node_id:
|
90
|
+
in_node_edges.setdefault(node_id, []).append(edge)
|
91
|
+
|
92
|
+
return {"out": out_node_edges, "in": in_node_edges}
|
91
93
|
|
92
94
|
@property
|
93
|
-
def
|
94
|
-
"""
|
95
|
-
|
95
|
+
def predecessors(self) -> list[str]:
|
96
|
+
"""
|
97
|
+
Get list of IDs of nodes with direct incoming relation to this.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
List of node IDs that precede this node.
|
101
|
+
"""
|
102
|
+
return [
|
103
|
+
node_id for node_id, edges in self.node_relations["in"].items() if edges
|
104
|
+
]
|
96
105
|
|
97
106
|
@property
|
98
107
|
def successors(self) -> list[str]:
|
99
|
-
"""
|
100
|
-
|
108
|
+
"""
|
109
|
+
Get list of IDs of nodes with direct outgoing relation from this.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
List of node IDs that succeed this node.
|
113
|
+
"""
|
114
|
+
return [
|
115
|
+
node_id for node_id, edges in self.node_relations["out"].items() if edges
|
116
|
+
]
|
101
117
|
|
102
118
|
def relate(
|
103
119
|
self,
|
104
120
|
node: "Node",
|
105
|
-
|
121
|
+
direction: str = "out",
|
106
122
|
condition: Condition | None = None,
|
107
123
|
label: str | None = None,
|
108
|
-
bundle=False,
|
124
|
+
bundle: bool = False,
|
109
125
|
) -> None:
|
110
|
-
"""
|
126
|
+
"""
|
127
|
+
Establish directed relationship from this node to another.
|
111
128
|
|
112
129
|
Args:
|
113
|
-
node
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
**kwargs: Additional keyword arguments for edge creation.
|
130
|
+
node: Target node to relate to.
|
131
|
+
direction: Direction of edge ('in' or 'out'). Default 'out'.
|
132
|
+
condition: Optional condition to associate with edge.
|
133
|
+
label: Optional label for edge.
|
134
|
+
bundle: Whether to bundle edge with others. Default False.
|
119
135
|
|
120
136
|
Raises:
|
121
|
-
ValueError: If
|
137
|
+
ValueError: If direction is neither 'in' nor 'out'.
|
122
138
|
"""
|
123
|
-
if
|
124
|
-
|
125
|
-
|
139
|
+
if direction not in ["in", "out"]:
|
140
|
+
raise ValueError(
|
141
|
+
f"Invalid value for direction: {direction}, " "must be 'in' or 'out'"
|
126
142
|
)
|
127
|
-
self.relations.points_to[edge.id_] = edge
|
128
|
-
node.relations.pointed_by[edge.id_] = edge
|
129
143
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
144
|
+
edge = Edge(
|
145
|
+
head=self if direction == "out" else node,
|
146
|
+
tail=node if direction == "out" else self,
|
147
|
+
condition=condition,
|
148
|
+
bundle=bundle,
|
149
|
+
label=label,
|
150
|
+
)
|
136
151
|
|
137
|
-
|
138
|
-
|
139
|
-
f"Invalid value for self_as: {node_as}, must be 'head' or 'tail'"
|
140
|
-
)
|
152
|
+
self.relations[direction].include(edge)
|
153
|
+
node.relations["in" if direction == "out" else "out"].include(edge)
|
141
154
|
|
142
155
|
def remove_edge(self, node: "Node", edge: Edge | str) -> bool:
|
143
|
-
|
144
|
-
|
156
|
+
"""
|
157
|
+
Remove specified edge or all edges between this and another node.
|
145
158
|
|
146
|
-
|
159
|
+
Args:
|
160
|
+
node: Other node involved in edge.
|
161
|
+
edge: Specific edge to remove or 'all' to remove all edges.
|
147
162
|
|
148
|
-
|
149
|
-
|
150
|
-
or edge_id not in node.relations.all_edges
|
151
|
-
):
|
152
|
-
raise ValueError(
|
153
|
-
f"Edge {edge_id} does not exist between nodes {self.id_} and "
|
154
|
-
f"{node.id_}."
|
155
|
-
)
|
163
|
+
Returns:
|
164
|
+
True if edge(s) successfully removed, False otherwise.
|
156
165
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
166
|
+
Raises:
|
167
|
+
RelationError: If removal fails or edge does not exist.
|
168
|
+
"""
|
169
|
+
edge_piles = [
|
170
|
+
self.relations["in"],
|
171
|
+
self.relations["out"],
|
172
|
+
node.relations["in"],
|
173
|
+
node.relations["out"],
|
162
174
|
]
|
163
|
-
try:
|
164
|
-
for _dict in all_dicts:
|
165
|
-
edge_id = edge.id_ if isinstance(edge, Edge) else edge
|
166
|
-
_dict.pop(edge_id, None)
|
167
|
-
return True
|
168
175
|
|
169
|
-
|
170
|
-
raise
|
171
|
-
|
172
|
-
) from e
|
176
|
+
if not all(pile.exclude(edge) for pile in edge_piles):
|
177
|
+
raise RelationError(f"Failed to remove edge between nodes.")
|
178
|
+
return True
|
173
179
|
|
174
180
|
def unrelate(self, node: "Node", edge: Edge | str = "all") -> bool:
|
175
181
|
"""
|
176
|
-
|
182
|
+
Remove all or specific relationships between this and another node.
|
177
183
|
|
178
184
|
Args:
|
179
|
-
node
|
180
|
-
edge
|
181
|
-
Defaults to "all".
|
185
|
+
node: Other node to unrelate from.
|
186
|
+
edge: Specific edge to remove or 'all' for all. Default 'all'.
|
182
187
|
|
183
188
|
Returns:
|
184
|
-
|
189
|
+
True if relationships successfully removed, False otherwise.
|
185
190
|
|
186
191
|
Raises:
|
187
|
-
|
192
|
+
RelationError: If operation fails to unrelate nodes.
|
188
193
|
"""
|
189
194
|
if edge == "all":
|
190
|
-
|
191
|
-
node.
|
192
|
-
) + self.node_relations["
|
195
|
+
edges = self.node_relations["out"].get(
|
196
|
+
node.ln_id, []
|
197
|
+
) + self.node_relations["in"].get(node.ln_id, [])
|
193
198
|
else:
|
194
|
-
|
199
|
+
edges = [get_lion_id(edge)]
|
195
200
|
|
196
|
-
if
|
197
|
-
raise
|
201
|
+
if not edges:
|
202
|
+
raise RelationError(f"Node is not related to {node.ln_id}.")
|
198
203
|
|
199
204
|
try:
|
200
|
-
for edge_id in
|
205
|
+
for edge_id in edges:
|
201
206
|
self.remove_edge(node, edge_id)
|
202
207
|
return True
|
203
|
-
except
|
204
|
-
raise
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
node_type (Type | str | Any): The type of node in LlamaIndex.
|
214
|
-
Defaults to None.
|
215
|
-
**kwargs: Additional keyword arguments for serialization.
|
216
|
-
|
217
|
-
Returns:
|
218
|
-
Any: The serialized node for LlamaIndex.
|
219
|
-
"""
|
220
|
-
return LlamaIndexBridge.to_llama_index_node(self, node_type=node_type, **kwargs)
|
221
|
-
|
222
|
-
def to_langchain(self, **kwargs) -> Any:
|
223
|
-
"""
|
224
|
-
Serializes this node for Langchain.
|
225
|
-
|
226
|
-
Args:
|
227
|
-
**kwargs: Additional keyword arguments for serialization.
|
228
|
-
|
229
|
-
Returns:
|
230
|
-
Any: The serialized node for Langchain.
|
231
|
-
"""
|
232
|
-
return LangchainBridge.to_langchain_document(self, **kwargs)
|
233
|
-
|
234
|
-
@classmethod
|
235
|
-
def from_llama_index(cls, llama_node: Any, **kwargs) -> "Node":
|
236
|
-
"""
|
237
|
-
Deserializes a node from LlamaIndex data.
|
238
|
-
|
239
|
-
Args:
|
240
|
-
llama_node (Any): The LlamaIndex node data.
|
241
|
-
**kwargs: Additional keyword arguments for deserialization.
|
242
|
-
|
243
|
-
Returns:
|
244
|
-
Node: The deserialized node.
|
245
|
-
"""
|
246
|
-
llama_dict = llama_node.to_dict(**kwargs)
|
247
|
-
return cls.from_obj(llama_dict)
|
248
|
-
|
249
|
-
@classmethod
|
250
|
-
def from_langchain(cls, lc_doc: Any) -> "Node":
|
251
|
-
"""Deserializes a node from Langchain data.
|
252
|
-
|
253
|
-
Args:
|
254
|
-
lc_doc (Any): The Langchain document data.
|
255
|
-
|
256
|
-
Returns:
|
257
|
-
Node: The deserialized node.
|
258
|
-
"""
|
259
|
-
langchain_json = lc_doc.to_json()
|
260
|
-
langchain_dict = {"lc_id": langchain_json["id"], **langchain_json["kwargs"]}
|
261
|
-
return cls.from_obj(langchain_dict)
|
262
|
-
|
263
|
-
def __str__(self) -> str:
|
264
|
-
"""
|
265
|
-
Provides a string representation of the node.
|
208
|
+
except RelationError as e:
|
209
|
+
raise e
|
210
|
+
|
211
|
+
def __str__(self):
|
212
|
+
_dict = self.to_dict()
|
213
|
+
_dict["relations"] = [
|
214
|
+
len(self.relations["in"]),
|
215
|
+
len(self.relations["out"]),
|
216
|
+
]
|
217
|
+
return Series(_dict).__str__()
|
266
218
|
|
267
|
-
|
268
|
-
|
269
|
-
"""
|
270
|
-
timestamp = f" ({self.timestamp})" if self.timestamp else ""
|
271
|
-
if self.content:
|
272
|
-
content_preview = (
|
273
|
-
f"{self.content[:50]}..." if len(self.content) > 50 else self.content
|
274
|
-
)
|
275
|
-
else:
|
276
|
-
content_preview = ""
|
277
|
-
meta_preview = (
|
278
|
-
f"{str(self.metadata)[:50]}..."
|
279
|
-
if len(str(self.metadata)) > 50
|
280
|
-
else str(self.metadata)
|
281
|
-
)
|
282
|
-
return (
|
283
|
-
f"{self.class_name()}({self.id_}, {content_preview}, {meta_preview},"
|
284
|
-
f"{timestamp})"
|
285
|
-
)
|
219
|
+
def __repr__(self):
|
220
|
+
return self.__str__()
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"""This module provides tree structure."""
|
2
|
+
|
3
|
+
from pydantic import Field
|
4
|
+
from lionagi.core.collections.abc import Condition
|
5
|
+
from lionagi.core.collections.util import to_list_type
|
6
|
+
from lionagi.core.generic.tree_node import TreeNode
|
7
|
+
from lionagi.core.generic.graph import Graph
|
8
|
+
|
9
|
+
|
10
|
+
class Tree(Graph):
|
11
|
+
"""
|
12
|
+
Represents a tree structure, extending the graph with tree-specific functionalities.
|
13
|
+
|
14
|
+
Manages parent-child relationships within the tree.
|
15
|
+
|
16
|
+
Attributes:
|
17
|
+
root (TreeNode | None): The root node of the tree. Defaults to None.
|
18
|
+
"""
|
19
|
+
|
20
|
+
root: TreeNode | None = Field(
|
21
|
+
default=None, description="The root node of the tree graph."
|
22
|
+
)
|
23
|
+
|
24
|
+
def relate_parent_child(
|
25
|
+
self,
|
26
|
+
parent: TreeNode,
|
27
|
+
children,
|
28
|
+
condition: Condition | None = None,
|
29
|
+
bundle: bool = False,
|
30
|
+
) -> None:
|
31
|
+
"""
|
32
|
+
Establishes parent-child relationships between the given parent and child node(s).
|
33
|
+
|
34
|
+
Args:
|
35
|
+
parent (TreeNode): The parent node.
|
36
|
+
children (list[TreeNode]): A list of child nodes.
|
37
|
+
condition (Condition | None): The condition associated with the relationships, if any.
|
38
|
+
bundle (bool): Indicates whether to bundle the relations into a single
|
39
|
+
transaction. Defaults to False.
|
40
|
+
"""
|
41
|
+
|
42
|
+
for i in to_list_type(children):
|
43
|
+
i.relate_parent(parent, condition=condition, bundle=bundle)
|
44
|
+
|
45
|
+
if self.root is None:
|
46
|
+
self.root = parent
|
47
|
+
|
48
|
+
self.add_node([parent, *children])
|
@@ -0,0 +1,79 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from pydantic import Field
|
3
|
+
from lionagi.core.collections.abc import Condition
|
4
|
+
from lionagi.core.collections.util import to_list_type
|
5
|
+
from lionagi.core.generic.node import Node
|
6
|
+
|
7
|
+
|
8
|
+
class TreeLabel(str, Enum):
|
9
|
+
"""Enumeration representing tree relationships."""
|
10
|
+
|
11
|
+
PARENT = "parent"
|
12
|
+
CHILD = "child"
|
13
|
+
|
14
|
+
|
15
|
+
class TreeNode(Node):
|
16
|
+
"""Represents a node in a tree structure."""
|
17
|
+
|
18
|
+
parent: Node | None = Field(
|
19
|
+
default=None,
|
20
|
+
description="The parent node, as an instance of Node.",
|
21
|
+
)
|
22
|
+
|
23
|
+
@property
|
24
|
+
def children(self) -> list[str]:
|
25
|
+
"""Return a list of child node ids."""
|
26
|
+
if not self.parent:
|
27
|
+
return list(self.related_nodes)
|
28
|
+
else:
|
29
|
+
return [node for node in self.related_nodes if node != self.parent.ln_id]
|
30
|
+
|
31
|
+
def relate_child(
|
32
|
+
self,
|
33
|
+
node: Node | list[Node],
|
34
|
+
condition: Condition | None = None,
|
35
|
+
bundle: bool = False,
|
36
|
+
) -> None:
|
37
|
+
"""Establish a parent-child relationship with the given node(s)."""
|
38
|
+
children = to_list_type(node)
|
39
|
+
for _child in children:
|
40
|
+
self.relate(
|
41
|
+
_child,
|
42
|
+
direction="out",
|
43
|
+
# label=TreeLabel.PARENT,
|
44
|
+
condition=condition,
|
45
|
+
bundle=bundle,
|
46
|
+
)
|
47
|
+
if isinstance(_child, TreeNode):
|
48
|
+
_child.parent = self
|
49
|
+
|
50
|
+
def relate_parent(
|
51
|
+
self,
|
52
|
+
node: Node,
|
53
|
+
condition: Condition | None = None,
|
54
|
+
bundle: bool = False,
|
55
|
+
) -> None:
|
56
|
+
"""Establish a parent-child relationship with the given parent node."""
|
57
|
+
if self.parent:
|
58
|
+
self.unrelate(self.parent)
|
59
|
+
self.relate(
|
60
|
+
node,
|
61
|
+
direction="in",
|
62
|
+
# label=TreeLabel.PARENT,
|
63
|
+
condition=condition,
|
64
|
+
bundle=bundle,
|
65
|
+
)
|
66
|
+
self.parent = node
|
67
|
+
|
68
|
+
def unrelate_parent(self):
|
69
|
+
"""Remove the parent-child relationship with the parent node."""
|
70
|
+
self.unrelate(self.parent)
|
71
|
+
self.parent = None
|
72
|
+
|
73
|
+
def unrelate_child(self, child: Node | list[Node]):
|
74
|
+
"""Remove the parent-child relationship with the given child node(s)."""
|
75
|
+
children: list[Node] = [child] if isinstance(child, Node) else child
|
76
|
+
for _child in children:
|
77
|
+
self.unrelate(_child)
|
78
|
+
if isinstance(_child, TreeNode):
|
79
|
+
_child.parent = None
|
lionagi/core/mail/__init__.py
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
from lionagi.core.collections.abc import Element, Field, Sendable
|
2
|
+
from .package import PackageCategory, Package
|
3
|
+
|
4
|
+
|
5
|
+
class Mail(Element, Sendable):
|
6
|
+
"""Represents a mail component with sender and recipient information."""
|
7
|
+
|
8
|
+
package: Package | None = Field(
|
9
|
+
None,
|
10
|
+
title="Package",
|
11
|
+
description="The package to be delivered.",
|
12
|
+
)
|
13
|
+
|
14
|
+
@property
|
15
|
+
def category(self) -> PackageCategory:
|
16
|
+
"""Return the category of the package."""
|
17
|
+
return self.package.category
|
18
|
+
|
19
|
+
def to_dict(self):
|
20
|
+
return {
|
21
|
+
"ln_id": self.ln_id,
|
22
|
+
"created": self.timestamp,
|
23
|
+
"package_category": self.package.category,
|
24
|
+
"package_id": self.package.ln_id,
|
25
|
+
}
|