lionagi 0.0.312__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lionagi/__init__.py +61 -3
- lionagi/core/__init__.py +0 -14
- 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/__init__.py +0 -3
- lionagi/core/agent/base_agent.py +45 -36
- 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/collections/_logger.py +319 -0
- 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/engine/branch_engine.py +333 -0
- lionagi/core/engine/instruction_map_engine.py +204 -0
- lionagi/core/engine/sandbox_.py +14 -0
- lionagi/core/engine/script_engine.py +99 -0
- lionagi/core/executor/base_executor.py +90 -0
- lionagi/core/executor/graph_executor.py +330 -0
- lionagi/core/executor/neo4j_executor.py +384 -0
- lionagi/core/generic/__init__.py +7 -0
- lionagi/core/generic/edge.py +112 -0
- 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 +220 -0
- lionagi/core/generic/tree.py +48 -0
- lionagi/core/generic/tree_node.py +79 -0
- lionagi/core/mail/__init__.py +7 -3
- lionagi/core/mail/mail.py +25 -0
- lionagi/core/mail/mail_manager.py +142 -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/__init__.py +0 -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/__init__.py +0 -3
- lionagi/core/session/branch.py +431 -0
- lionagi/core/session/directive_mixin.py +287 -0
- lionagi/core/session/session.py +230 -902
- 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/__init__.py +0 -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/__init__.py +0 -0
- lionagi/core/validator/validator.py +364 -0
- lionagi/core/work/__init__.py +0 -0
- lionagi/core/work/work.py +76 -0
- lionagi/core/work/work_function.py +101 -0
- lionagi/core/work/work_queue.py +103 -0
- lionagi/core/work/worker.py +258 -0
- lionagi/core/work/worklog.py +120 -0
- lionagi/experimental/__init__.py +0 -0
- lionagi/experimental/compressor/__init__.py +0 -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/__init__.py +0 -0
- lionagi/experimental/directive/parser/base_parser.py +282 -0
- lionagi/experimental/directive/template/__init__.py +0 -0
- lionagi/experimental/directive/template/base_template.py +79 -0
- lionagi/experimental/directive/template/schema.py +36 -0
- lionagi/experimental/directive/tokenizer.py +73 -0
- lionagi/experimental/evaluator/__init__.py +0 -0
- lionagi/experimental/evaluator/ast_evaluator.py +131 -0
- lionagi/experimental/evaluator/base_evaluator.py +218 -0
- lionagi/experimental/knowledge/__init__.py +0 -0
- lionagi/experimental/knowledge/base.py +10 -0
- lionagi/experimental/knowledge/graph.py +0 -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/autogen_/__init__.py +0 -0
- lionagi/integrations/bridge/autogen_/autogen_.py +124 -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/bridge/llamaindex_/llama_pack.py +227 -0
- lionagi/integrations/bridge/llamaindex_/node_parser.py +6 -9
- lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +1 -0
- lionagi/integrations/bridge/transformers_/__init__.py +0 -0
- lionagi/integrations/bridge/transformers_/install_.py +36 -0
- lionagi/integrations/chunker/__init__.py +0 -0
- lionagi/integrations/chunker/chunk.py +312 -0
- lionagi/integrations/config/oai_configs.py +38 -7
- lionagi/integrations/config/ollama_configs.py +1 -1
- lionagi/integrations/config/openrouter_configs.py +14 -2
- lionagi/integrations/loader/__init__.py +0 -0
- lionagi/integrations/loader/load.py +253 -0
- lionagi/integrations/loader/load_util.py +195 -0
- 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 +7 -6
- 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 -0
- lionagi/integrations/storage/neo4j.py +665 -0
- lionagi/integrations/storage/storage_util.py +287 -0
- lionagi/integrations/storage/structure_excel.py +285 -0
- lionagi/integrations/storage/to_csv.py +63 -0
- lionagi/integrations/storage/to_excel.py +83 -0
- lionagi/libs/__init__.py +26 -1
- lionagi/libs/ln_api.py +78 -23
- 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_knowledge_graph.py +405 -0
- lionagi/libs/ln_nested.py +26 -11
- lionagi/libs/ln_parse.py +110 -14
- lionagi/libs/ln_queue.py +117 -0
- lionagi/libs/ln_tokenize.py +164 -0
- lionagi/{core/prompt/field_validator.py → libs/ln_validate.py} +79 -14
- lionagi/libs/special_tokens.py +172 -0
- lionagi/libs/sys_util.py +107 -2
- lionagi/lions/__init__.py +0 -0
- lionagi/lions/coder/__init__.py +0 -0
- lionagi/lions/coder/add_feature.py +20 -0
- lionagi/lions/coder/base_prompts.py +22 -0
- lionagi/lions/coder/code_form.py +13 -0
- lionagi/lions/coder/coder.py +168 -0
- lionagi/lions/coder/util.py +96 -0
- lionagi/lions/researcher/__init__.py +0 -0
- lionagi/lions/researcher/data_source/__init__.py +0 -0
- lionagi/lions/researcher/data_source/finhub_.py +191 -0
- lionagi/lions/researcher/data_source/google_.py +199 -0
- lionagi/lions/researcher/data_source/wiki_.py +96 -0
- lionagi/lions/researcher/data_source/yfinance_.py +21 -0
- lionagi/tests/integrations/__init__.py +0 -0
- lionagi/tests/libs/__init__.py +0 -0
- lionagi/tests/libs/test_field_validators.py +353 -0
- lionagi/tests/{test_libs → libs}/test_func_call.py +23 -21
- lionagi/tests/{test_libs → libs}/test_nested.py +36 -21
- lionagi/tests/{test_libs → libs}/test_parse.py +1 -1
- lionagi/tests/libs/test_queue.py +67 -0
- 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/__init__.py +0 -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 -292
- 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.0.312.dist-info → lionagi-0.2.1.dist-info}/LICENSE +12 -11
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/METADATA +19 -118
- lionagi-0.2.1.dist-info/RECORD +240 -0
- lionagi/core/branch/__init__.py +0 -4
- lionagi/core/branch/base_branch.py +0 -654
- lionagi/core/branch/branch.py +0 -471
- lionagi/core/branch/branch_flow_mixin.py +0 -96
- lionagi/core/branch/executable_branch.py +0 -347
- lionagi/core/branch/util.py +0 -323
- lionagi/core/direct/__init__.py +0 -6
- lionagi/core/direct/predict.py +0 -161
- lionagi/core/direct/score.py +0 -278
- lionagi/core/direct/select.py +0 -169
- lionagi/core/direct/utils.py +0 -87
- lionagi/core/direct/vote.py +0 -64
- lionagi/core/flow/base/baseflow.py +0 -23
- lionagi/core/flow/monoflow/ReAct.py +0 -238
- lionagi/core/flow/monoflow/__init__.py +0 -9
- lionagi/core/flow/monoflow/chat.py +0 -95
- lionagi/core/flow/monoflow/chat_mixin.py +0 -263
- lionagi/core/flow/monoflow/followup.py +0 -214
- lionagi/core/flow/polyflow/__init__.py +0 -1
- lionagi/core/flow/polyflow/chat.py +0 -248
- lionagi/core/mail/schema.py +0 -56
- lionagi/core/messages/__init__.py +0 -3
- lionagi/core/messages/schema.py +0 -533
- lionagi/core/prompt/prompt_template.py +0 -316
- lionagi/core/schema/__init__.py +0 -22
- lionagi/core/schema/action_node.py +0 -29
- lionagi/core/schema/base_mixin.py +0 -296
- lionagi/core/schema/base_node.py +0 -199
- lionagi/core/schema/condition.py +0 -24
- lionagi/core/schema/data_logger.py +0 -354
- lionagi/core/schema/data_node.py +0 -93
- lionagi/core/schema/prompt_template.py +0 -67
- lionagi/core/schema/structure.py +0 -910
- lionagi/core/tool/__init__.py +0 -3
- lionagi/core/tool/tool_manager.py +0 -280
- lionagi/integrations/bridge/pydantic_/base_model.py +0 -7
- lionagi/tests/test_core/test_base_branch.py +0 -427
- 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 -312
- lionagi/tests/test_core/test_tool_manager.py +0 -95
- lionagi-0.0.312.dist-info/RECORD +0 -111
- /lionagi/core/{branch/base → _setting}/__init__.py +0 -0
- /lionagi/core/{flow → agent/eval}/__init__.py +0 -0
- /lionagi/core/{flow/base → agent/learn}/__init__.py +0 -0
- /lionagi/core/{prompt → agent/plan}/__init__.py +0 -0
- /lionagi/core/{tool/manual.py → agent/plan/plan.py} +0 -0
- /lionagi/{tests/test_integrations → core/director}/__init__.py +0 -0
- /lionagi/{tests/test_libs → core/engine}/__init__.py +0 -0
- /lionagi/{tests/test_libs/test_async.py → core/executor/__init__.py} +0 -0
- /lionagi/tests/{test_libs → libs}/test_api.py +0 -0
- /lionagi/tests/{test_libs → libs}/test_convert.py +0 -0
- /lionagi/tests/{test_libs → libs}/test_sys_util.py +0 -0
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,347 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This module contains the ExecutableBranch class, which represents an executable branch in a conversation tree.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import contextlib
|
6
|
-
from collections import deque
|
7
|
-
from typing import Any
|
8
|
-
|
9
|
-
from lionagi.libs import convert, AsyncUtil, ParseUtil
|
10
|
-
|
11
|
-
from ..schema import BaseRelatableNode, ActionNode
|
12
|
-
from ..mail import BaseMail
|
13
|
-
from ..messages import System, Instruction
|
14
|
-
from ..agent import BaseAgent
|
15
|
-
|
16
|
-
from .branch import Branch
|
17
|
-
|
18
|
-
|
19
|
-
class ExecutableBranch(BaseRelatableNode):
|
20
|
-
"""
|
21
|
-
Represents an executable branch in a conversation tree.
|
22
|
-
|
23
|
-
Attributes:
|
24
|
-
branch (Branch): The branch associated with the executable branch.
|
25
|
-
pending_ins (dict): The pending incoming mails for the executable branch.
|
26
|
-
pending_outs (deque): The pending outgoing mails for the executable branch.
|
27
|
-
responses (list): The responses generated by the executable branch.
|
28
|
-
execute_stop (bool): A flag indicating whether the execution should stop.
|
29
|
-
context (Any): The context of the executable branch.
|
30
|
-
context_log (list): The log of contexts for the executable branch.
|
31
|
-
verbose (bool): A flag indicating whether to provide verbose output.
|
32
|
-
|
33
|
-
Methods:
|
34
|
-
__init__(self, verbose=True, **kwargs) -> None:
|
35
|
-
Initializes the ExecutableBranch instance.
|
36
|
-
|
37
|
-
send(self, recipient_id: str, category: str, package: Any) -> None:
|
38
|
-
Sends a mail to a recipient.
|
39
|
-
|
40
|
-
async forward(self) -> None:
|
41
|
-
Forwards the pending incoming mails to the appropriate processing methods.
|
42
|
-
|
43
|
-
async execute(self, refresh_time=1) -> None:
|
44
|
-
Executes the executable branch.
|
45
|
-
|
46
|
-
async _process_node(self, mail: BaseMail) -> None:
|
47
|
-
Processes a node mail.
|
48
|
-
|
49
|
-
_process_node_list(self, mail: BaseMail) -> None:
|
50
|
-
Processes a node list mail.
|
51
|
-
|
52
|
-
_process_condition(self, mail: BaseMail) -> None:
|
53
|
-
Processes a condition mail.
|
54
|
-
|
55
|
-
_system_process(self, system: System, verbose=True, context_verbose=False) -> None:
|
56
|
-
Processes a system message.
|
57
|
-
|
58
|
-
async _instruction_process(self, instruction: Instruction, verbose=True, **kwargs) -> None:
|
59
|
-
Processes an instruction message.
|
60
|
-
|
61
|
-
async _action_process(self, action: ActionNode, verbose=True) -> None:
|
62
|
-
Processes an action node.
|
63
|
-
|
64
|
-
async _agent_process(self, agent, verbose=True) -> None:
|
65
|
-
Processes an agent.
|
66
|
-
|
67
|
-
_process_start(self, mail: BaseMail) -> None:
|
68
|
-
Processes a start mail.
|
69
|
-
|
70
|
-
_process_end(self, mail: BaseMail) -> None:
|
71
|
-
Processes an end mail.
|
72
|
-
"""
|
73
|
-
|
74
|
-
def __init__(self, verbose=True, **kwargs):
|
75
|
-
"""
|
76
|
-
Initializes the ExecutableBranch instance.
|
77
|
-
|
78
|
-
Args:
|
79
|
-
verbose (bool): A flag indicating whether to provide verbose output (default: True).
|
80
|
-
**kwargs: Additional keyword arguments for initializing the branch.
|
81
|
-
"""
|
82
|
-
super().__init__()
|
83
|
-
self.branch: Branch = Branch(**kwargs)
|
84
|
-
self.pending_ins = {} # needed
|
85
|
-
self.pending_outs = deque() # needed
|
86
|
-
self.responses = []
|
87
|
-
self.execute_stop = False # needed
|
88
|
-
self.context = None # needed
|
89
|
-
self.context_log = []
|
90
|
-
self.verbose = verbose
|
91
|
-
|
92
|
-
def send(self, recipient_id: str, category: str, package: Any) -> None:
|
93
|
-
"""
|
94
|
-
Sends a mail to a recipient.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
recipient_id (str): The ID of the recipient.
|
98
|
-
category (str): The category of the mail.
|
99
|
-
package (Any): The package to send in the mail.
|
100
|
-
"""
|
101
|
-
mail = BaseMail(
|
102
|
-
sender_id=self.id_,
|
103
|
-
recipient_id=recipient_id,
|
104
|
-
category=category,
|
105
|
-
package=package,
|
106
|
-
)
|
107
|
-
self.pending_outs.append(mail)
|
108
|
-
|
109
|
-
async def forward(self) -> None:
|
110
|
-
"""
|
111
|
-
Forwards the pending incoming mails to the appropriate processing methods.
|
112
|
-
"""
|
113
|
-
for key in list(self.pending_ins.keys()):
|
114
|
-
while self.pending_ins[key]:
|
115
|
-
mail = self.pending_ins[key].popleft()
|
116
|
-
if mail.category == "start":
|
117
|
-
self._process_start(mail)
|
118
|
-
elif mail.category == "node":
|
119
|
-
await self._process_node(mail)
|
120
|
-
elif mail.category == "node_list":
|
121
|
-
self._process_node_list(mail)
|
122
|
-
elif mail.category == "condition":
|
123
|
-
self._process_condition(mail)
|
124
|
-
elif mail.category == "end":
|
125
|
-
self._process_end(mail)
|
126
|
-
|
127
|
-
async def execute(self, refresh_time=1) -> None:
|
128
|
-
"""
|
129
|
-
Executes the executable branch.
|
130
|
-
|
131
|
-
Args:
|
132
|
-
refresh_time (int): The refresh time for execution (default: 1).
|
133
|
-
"""
|
134
|
-
while not self.execute_stop:
|
135
|
-
await self.forward()
|
136
|
-
await AsyncUtil.sleep(refresh_time)
|
137
|
-
|
138
|
-
async def _process_node(self, mail: BaseMail):
|
139
|
-
"""
|
140
|
-
Processes a node mail.
|
141
|
-
|
142
|
-
Args:
|
143
|
-
mail (BaseMail): The node mail to process.
|
144
|
-
|
145
|
-
Raises:
|
146
|
-
ValueError: If the mail package is invalid.
|
147
|
-
"""
|
148
|
-
if isinstance(mail.package, System):
|
149
|
-
self._system_process(mail.package, verbose=self.verbose)
|
150
|
-
self.send(mail.sender_id, "node_id", mail.package.id_)
|
151
|
-
|
152
|
-
elif isinstance(mail.package, Instruction):
|
153
|
-
await self._instruction_process(mail.package, verbose=self.verbose)
|
154
|
-
self.send(mail.sender_id, "node_id", mail.package.id_)
|
155
|
-
|
156
|
-
elif isinstance(mail.package, ActionNode):
|
157
|
-
await self._action_process(mail.package, verbose=self.verbose)
|
158
|
-
self.send(mail.sender_id, "node_id", mail.package.instruction.id_)
|
159
|
-
else:
|
160
|
-
try:
|
161
|
-
await self._agent_process(mail.package, verbose=self.verbose)
|
162
|
-
self.send(mail.sender_id, "node_id", mail.package.id_)
|
163
|
-
except:
|
164
|
-
raise ValueError(f"Invalid mail to process. Mail:{mail}")
|
165
|
-
|
166
|
-
def _process_node_list(self, mail: BaseMail):
|
167
|
-
"""
|
168
|
-
Processes a node list mail.
|
169
|
-
|
170
|
-
Args:
|
171
|
-
mail (BaseMail): The node list mail to process.
|
172
|
-
|
173
|
-
Raises:
|
174
|
-
ValueError: If multiple path selection is not supported.
|
175
|
-
"""
|
176
|
-
self.send(mail.sender_id, "end", "end")
|
177
|
-
self.execute_stop = True
|
178
|
-
raise ValueError("Multiple path selection is currently not supported")
|
179
|
-
|
180
|
-
def _process_condition(self, mail: BaseMail):
|
181
|
-
"""
|
182
|
-
Processes a condition mail.
|
183
|
-
|
184
|
-
Args:
|
185
|
-
mail (BaseMail): The condition mail to process.
|
186
|
-
"""
|
187
|
-
relationship = mail.package
|
188
|
-
check_result = relationship.condition(self)
|
189
|
-
back_mail = {"relationship_id": mail.package.id_, "check_result": check_result}
|
190
|
-
self.send(mail.sender_id, "condition", back_mail)
|
191
|
-
|
192
|
-
def _system_process(self, system: System, verbose=True, context_verbose=False):
|
193
|
-
"""
|
194
|
-
Processes a system message.
|
195
|
-
|
196
|
-
Args:
|
197
|
-
system (System): The system message to process.
|
198
|
-
verbose (bool): A flag indicating whether to provide verbose output (default: True).
|
199
|
-
context_verbose (bool): A flag indicating whether to display the context (default: False).
|
200
|
-
"""
|
201
|
-
from lionagi.libs import SysUtil
|
202
|
-
|
203
|
-
SysUtil.check_import("IPython")
|
204
|
-
from IPython.display import Markdown, display
|
205
|
-
|
206
|
-
if verbose:
|
207
|
-
print(f"------------------Welcome: {system.sender}--------------------")
|
208
|
-
display(Markdown(f"system: {convert.to_str(system.system_info)}"))
|
209
|
-
if self.context and context_verbose:
|
210
|
-
display(Markdown(f"context: {convert.to_str(self.context)}"))
|
211
|
-
|
212
|
-
self.branch.add_message(system=system)
|
213
|
-
|
214
|
-
async def _instruction_process(
|
215
|
-
self, instruction: Instruction, verbose=True, **kwargs
|
216
|
-
):
|
217
|
-
"""
|
218
|
-
Processes an instruction message.
|
219
|
-
|
220
|
-
Args:
|
221
|
-
instruction (Instruction): The instruction message to process.
|
222
|
-
verbose (bool): A flag indicating whether to provide verbose output (default: True).
|
223
|
-
**kwargs: Additional keyword arguments for processing the instruction.
|
224
|
-
"""
|
225
|
-
from lionagi.libs import SysUtil
|
226
|
-
|
227
|
-
SysUtil.check_import("IPython")
|
228
|
-
from IPython.display import Markdown, display
|
229
|
-
|
230
|
-
if verbose:
|
231
|
-
display(
|
232
|
-
Markdown(
|
233
|
-
f"{instruction.sender}: {convert.to_str(instruction.instruct)}"
|
234
|
-
)
|
235
|
-
)
|
236
|
-
|
237
|
-
if self.context:
|
238
|
-
instruction.content.update({"context": self.context})
|
239
|
-
self.context = None
|
240
|
-
|
241
|
-
result = await self.branch.chat(instruction, **kwargs)
|
242
|
-
with contextlib.suppress(Exception):
|
243
|
-
result = ParseUtil.fuzzy_parse_json(result)
|
244
|
-
if "response" in result.keys():
|
245
|
-
result = result["response"]
|
246
|
-
if verbose and len(self.branch.assistant_responses) != 0:
|
247
|
-
display(
|
248
|
-
Markdown(
|
249
|
-
f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
|
250
|
-
)
|
251
|
-
)
|
252
|
-
print("-----------------------------------------------------")
|
253
|
-
|
254
|
-
self.responses.append(result)
|
255
|
-
|
256
|
-
async def _action_process(self, action: ActionNode, verbose=True):
|
257
|
-
"""
|
258
|
-
Processes an action node.
|
259
|
-
|
260
|
-
Args:
|
261
|
-
action (ActionNode): The action node to process.
|
262
|
-
verbose (bool): A flag indicating whether to provide verbose output (default: True).
|
263
|
-
|
264
|
-
Raises:
|
265
|
-
ValueError: If the action is not valid.
|
266
|
-
"""
|
267
|
-
from lionagi.libs import SysUtil
|
268
|
-
|
269
|
-
SysUtil.check_import("IPython")
|
270
|
-
from IPython.display import Markdown, display
|
271
|
-
|
272
|
-
try:
|
273
|
-
func = getattr(self.branch, action.action)
|
274
|
-
except:
|
275
|
-
raise ValueError(f"{action.action} is not a valid action")
|
276
|
-
|
277
|
-
if verbose:
|
278
|
-
display(
|
279
|
-
Markdown(
|
280
|
-
f"{action.instruction.sender}: {convert.to_str(action.instruction.instruct)}"
|
281
|
-
)
|
282
|
-
)
|
283
|
-
|
284
|
-
if action.tools:
|
285
|
-
self.branch.register_tools(action.tools)
|
286
|
-
if self.context:
|
287
|
-
result = await func(
|
288
|
-
action.instruction.content["instruction"],
|
289
|
-
context=self.context,
|
290
|
-
tools=action.tools,
|
291
|
-
**action.action_kwargs,
|
292
|
-
)
|
293
|
-
self.context = None
|
294
|
-
else:
|
295
|
-
result = await func(
|
296
|
-
action.instruction.content, tools=action.tools, **action.action_kwargs
|
297
|
-
)
|
298
|
-
|
299
|
-
if verbose and len(self.branch.assistant_responses) != 0:
|
300
|
-
display(
|
301
|
-
Markdown(
|
302
|
-
f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
|
303
|
-
)
|
304
|
-
)
|
305
|
-
print("-----------------------------------------------------")
|
306
|
-
|
307
|
-
self.responses.append(result)
|
308
|
-
|
309
|
-
async def _agent_process(self, agent, verbose=True):
|
310
|
-
"""
|
311
|
-
Processes an agent.
|
312
|
-
|
313
|
-
Args:
|
314
|
-
agent: The agent to process.
|
315
|
-
verbose (bool): A flag indicating whether to provide verbose output (default: True).
|
316
|
-
"""
|
317
|
-
context = self.responses
|
318
|
-
if verbose:
|
319
|
-
print("*****************************************************")
|
320
|
-
result = await agent.execute(context)
|
321
|
-
|
322
|
-
if verbose:
|
323
|
-
print("*****************************************************")
|
324
|
-
|
325
|
-
self.context = result
|
326
|
-
self.responses.append(result)
|
327
|
-
|
328
|
-
def _process_start(self, mail):
|
329
|
-
"""
|
330
|
-
Processes a start mail.
|
331
|
-
|
332
|
-
Args:
|
333
|
-
mail (BaseMail): The start mail to process.
|
334
|
-
"""
|
335
|
-
start_mail_content = mail.package
|
336
|
-
self.context = start_mail_content["context"]
|
337
|
-
self.send(start_mail_content["structure_id"], "start", "start")
|
338
|
-
|
339
|
-
def _process_end(self, mail):
|
340
|
-
"""
|
341
|
-
Processes an end mail.
|
342
|
-
|
343
|
-
Args:
|
344
|
-
mail (BaseMail): The end mail to process.
|
345
|
-
"""
|
346
|
-
self.execute_stop = True
|
347
|
-
self.send(mail.sender_id, "end", "end")
|
lionagi/core/branch/util.py
DELETED
@@ -1,323 +0,0 @@
|
|
1
|
-
import contextlib
|
2
|
-
from datetime import datetime
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
from lionagi.libs import convert, nested, func_call, dataframe
|
6
|
-
|
7
|
-
from lionagi.core.messages.schema import (
|
8
|
-
System,
|
9
|
-
Instruction,
|
10
|
-
Response,
|
11
|
-
BaseMessage,
|
12
|
-
BranchColumns,
|
13
|
-
)
|
14
|
-
|
15
|
-
CUSTOM_TYPE = dict[str, Any] | str | list[Any] | None
|
16
|
-
|
17
|
-
|
18
|
-
class MessageUtil:
|
19
|
-
|
20
|
-
@staticmethod
|
21
|
-
def create_message(
|
22
|
-
system: System | CUSTOM_TYPE = None,
|
23
|
-
instruction: Instruction | CUSTOM_TYPE = None,
|
24
|
-
context: str | dict[str, Any] | None = None,
|
25
|
-
response: Response | CUSTOM_TYPE = None,
|
26
|
-
output_fields=None,
|
27
|
-
**kwargs,
|
28
|
-
) -> BaseMessage:
|
29
|
-
"""
|
30
|
-
Creates a message object based on the input parameters, ensuring only one message role is present.
|
31
|
-
|
32
|
-
Args:
|
33
|
-
system: Information for creating a System message.
|
34
|
-
instruction: Information for creating an Instruction message.
|
35
|
-
context: Context information for the message.
|
36
|
-
response: Response data for creating a message.
|
37
|
-
**kwargs: Additional keyword arguments for message creation.
|
38
|
-
|
39
|
-
Returns:
|
40
|
-
A message object of the appropriate type based on provided inputs.
|
41
|
-
|
42
|
-
Raises:
|
43
|
-
ValueError: If more than one of the role-specific parameters are provided.
|
44
|
-
"""
|
45
|
-
if sum(func_call.lcall([system, instruction, response], bool)) != 1:
|
46
|
-
raise ValueError("Error: Message must have one and only one role.")
|
47
|
-
|
48
|
-
if isinstance(system, System):
|
49
|
-
return system
|
50
|
-
elif isinstance(instruction, Instruction):
|
51
|
-
return instruction
|
52
|
-
elif isinstance(response, Response):
|
53
|
-
return response
|
54
|
-
|
55
|
-
msg = 0
|
56
|
-
if response:
|
57
|
-
msg = Response(response=response, **kwargs)
|
58
|
-
elif instruction:
|
59
|
-
msg = Instruction(
|
60
|
-
instruction=instruction,
|
61
|
-
context=context,
|
62
|
-
output_fields=output_fields,
|
63
|
-
**kwargs,
|
64
|
-
)
|
65
|
-
elif system:
|
66
|
-
msg = System(system=system, **kwargs)
|
67
|
-
return msg
|
68
|
-
|
69
|
-
@staticmethod
|
70
|
-
def validate_messages(messages: dataframe.ln_DataFrame) -> bool:
|
71
|
-
"""
|
72
|
-
Validates the format and content of a DataFrame containing messages.
|
73
|
-
|
74
|
-
Args:
|
75
|
-
messages: A DataFrame with message information.
|
76
|
-
|
77
|
-
Returns:
|
78
|
-
True if the messages DataFrame is correctly formatted, False otherwise.
|
79
|
-
|
80
|
-
Raises:
|
81
|
-
ValueError: If the DataFrame does not match expected schema or content requirements.
|
82
|
-
"""
|
83
|
-
|
84
|
-
if list(messages.columns) != BranchColumns.COLUMNS.value:
|
85
|
-
raise ValueError("Invalid messages dataframe. Unmatched columns.")
|
86
|
-
if messages.isnull().values.any():
|
87
|
-
raise ValueError("Invalid messages dataframe. Cannot have null.")
|
88
|
-
if any(
|
89
|
-
role not in ["system", "user", "assistant"]
|
90
|
-
for role in messages["role"].unique()
|
91
|
-
):
|
92
|
-
raise ValueError(
|
93
|
-
'Invalid messages dataframe. Cannot have role other than ["system", "user", "assistant"].'
|
94
|
-
)
|
95
|
-
for cont in messages["content"]:
|
96
|
-
if cont.startswith("Sender"):
|
97
|
-
cont = cont.split(":", 1)[1]
|
98
|
-
try:
|
99
|
-
convert.to_dict(cont)
|
100
|
-
except:
|
101
|
-
raise ValueError(
|
102
|
-
"Invalid messages dataframe. Content expect json string."
|
103
|
-
)
|
104
|
-
return True
|
105
|
-
|
106
|
-
@staticmethod
|
107
|
-
def sign_message(
|
108
|
-
messages: dataframe.ln_DataFrame, sender: str
|
109
|
-
) -> dataframe.ln_DataFrame:
|
110
|
-
"""
|
111
|
-
Appends a sender prefix to the 'content' field of each message in a DataFrame.
|
112
|
-
|
113
|
-
Args:
|
114
|
-
messages: A DataFrame containing message data.
|
115
|
-
sender: The identifier of the sender to prefix to message contents.
|
116
|
-
|
117
|
-
Returns:
|
118
|
-
A DataFrame with sender-prefixed message contents.
|
119
|
-
|
120
|
-
Raises:
|
121
|
-
ValueError: If the sender is None or the value is 'none'.
|
122
|
-
"""
|
123
|
-
|
124
|
-
if sender is None or convert.strip_lower(sender) == "none":
|
125
|
-
raise ValueError("sender cannot be None")
|
126
|
-
df = convert.to_df(messages)
|
127
|
-
|
128
|
-
for i in df.index:
|
129
|
-
if not df.loc[i, "content"].startswith("Sender"):
|
130
|
-
df.loc[i, "content"] = f"Sender {sender}: {df.loc[i, 'content']}"
|
131
|
-
else:
|
132
|
-
content = df.loc[i, "content"].split(":", 1)[1]
|
133
|
-
df.loc[i, "content"] = f"Sender {sender}: {content}"
|
134
|
-
|
135
|
-
return convert.to_df(df)
|
136
|
-
|
137
|
-
@staticmethod
|
138
|
-
def filter_messages_by(
|
139
|
-
messages: dataframe.ln_DataFrame,
|
140
|
-
role: str | None = None,
|
141
|
-
sender: str | None = None,
|
142
|
-
start_time: datetime | None = None,
|
143
|
-
end_time: datetime | None = None,
|
144
|
-
content_keywords: str | list[str] | None = None,
|
145
|
-
case_sensitive: bool = False,
|
146
|
-
) -> dataframe.ln_DataFrame:
|
147
|
-
"""
|
148
|
-
Filters messages in a DataFrame based on specified criteria.
|
149
|
-
|
150
|
-
Args:
|
151
|
-
messages: The DataFrame to filter.
|
152
|
-
role: The role to filter by.
|
153
|
-
sender: The sender to filter by.
|
154
|
-
start_time: The minimum timestamp for messages.
|
155
|
-
end_time: The maximum timestamp for messages.
|
156
|
-
content_keywords: Keywords to look for in message content.
|
157
|
-
case_sensitive: Whether the keyword search should be case-sensitive.
|
158
|
-
|
159
|
-
Returns:
|
160
|
-
A filtered DataFrame based on the specified criteria.
|
161
|
-
"""
|
162
|
-
|
163
|
-
try:
|
164
|
-
outs = messages.copy()
|
165
|
-
|
166
|
-
if content_keywords:
|
167
|
-
outs = MessageUtil.search_keywords(
|
168
|
-
outs, keywords=content_keywords, case_sensitive=case_sensitive
|
169
|
-
)
|
170
|
-
|
171
|
-
outs = outs[outs["role"] == role] if role else outs
|
172
|
-
outs = outs[outs["sender"] == sender] if sender else outs
|
173
|
-
outs = outs[outs["timestamp"] > start_time] if start_time else outs
|
174
|
-
outs = outs[outs["timestamp"] < end_time] if end_time else outs
|
175
|
-
|
176
|
-
return convert.to_df(outs)
|
177
|
-
|
178
|
-
except Exception as e:
|
179
|
-
raise ValueError(f"Error in filtering messages: {e}") from e
|
180
|
-
|
181
|
-
@staticmethod
|
182
|
-
def remove_message(messages: dataframe.ln_DataFrame, node_id: str) -> bool:
|
183
|
-
"""
|
184
|
-
Removes a message from the DataFrame based on its node ID.
|
185
|
-
|
186
|
-
Args:
|
187
|
-
messages: The DataFrame containing messages.
|
188
|
-
node_id: The unique identifier of the message to be removed.
|
189
|
-
|
190
|
-
Returns:
|
191
|
-
If any messages are removed.
|
192
|
-
|
193
|
-
Examples:
|
194
|
-
>>> messages = dataframe.ln_DataFrame([...])
|
195
|
-
>>> updated_messages = MessageUtil.remove_message(messages, "node_id_123")
|
196
|
-
"""
|
197
|
-
|
198
|
-
initial_length = len(messages)
|
199
|
-
messages.drop(messages[messages["node_id"] == node_id].index, inplace=True)
|
200
|
-
messages.reset_index(drop=True, inplace=True)
|
201
|
-
|
202
|
-
return len(messages) < initial_length
|
203
|
-
|
204
|
-
@staticmethod
|
205
|
-
def get_message_rows(
|
206
|
-
messages: dataframe.ln_DataFrame,
|
207
|
-
sender: str | None = None,
|
208
|
-
role: str | None = None,
|
209
|
-
n: int = 1,
|
210
|
-
sign_: bool = False,
|
211
|
-
from_: str = "front",
|
212
|
-
) -> dataframe.ln_DataFrame:
|
213
|
-
"""
|
214
|
-
Retrieves a specified number of message rows based on sender and role.
|
215
|
-
|
216
|
-
Args:
|
217
|
-
messages: The DataFrame containing messages.
|
218
|
-
sender: Filter messages by the sender.
|
219
|
-
role: Filter messages by the role.
|
220
|
-
n: The number of messages to retrieve.
|
221
|
-
sign_: If True, sign the message with the sender.
|
222
|
-
from_: Specify retrieval from the 'front' or 'last' of the DataFrame.
|
223
|
-
|
224
|
-
Returns:
|
225
|
-
A DataFrame containing the filtered messages.
|
226
|
-
"""
|
227
|
-
|
228
|
-
outs = ""
|
229
|
-
|
230
|
-
if from_ == "last":
|
231
|
-
if sender is None and role is None:
|
232
|
-
outs = messages.iloc[-n:]
|
233
|
-
elif sender and role:
|
234
|
-
outs = messages[
|
235
|
-
(messages["sender"] == sender) & (messages["role"] == role)
|
236
|
-
].iloc[-n:]
|
237
|
-
|
238
|
-
elif sender:
|
239
|
-
outs = messages[messages["sender"] == sender].iloc[-n:]
|
240
|
-
else:
|
241
|
-
outs = messages[messages["role"] == role].iloc[-n:]
|
242
|
-
|
243
|
-
elif from_ == "front":
|
244
|
-
if sender is None and role is None:
|
245
|
-
outs = messages.iloc[:n]
|
246
|
-
elif sender and role:
|
247
|
-
outs = messages[
|
248
|
-
(messages["sender"] == sender) & (messages["role"] == role)
|
249
|
-
].iloc[:n]
|
250
|
-
elif sender:
|
251
|
-
outs = messages[messages["sender"] == sender].iloc[:n]
|
252
|
-
else:
|
253
|
-
outs = messages[messages["role"] == role].iloc[:n]
|
254
|
-
|
255
|
-
return MessageUtil.sign_message(outs, sender) if sign_ else outs
|
256
|
-
|
257
|
-
@staticmethod
|
258
|
-
def extend(
|
259
|
-
df1: dataframe.ln_DataFrame, df2: dataframe.ln_DataFrame, **kwargs
|
260
|
-
) -> dataframe.ln_DataFrame:
|
261
|
-
"""
|
262
|
-
Extends a DataFrame with another DataFrame's rows, ensuring no duplicate 'node_id'.
|
263
|
-
|
264
|
-
Args:
|
265
|
-
df1: The primary DataFrame.
|
266
|
-
df2: The DataFrame to merge with the primary DataFrame.
|
267
|
-
**kwargs: Additional keyword arguments for `drop_duplicates`.
|
268
|
-
|
269
|
-
Returns:
|
270
|
-
A DataFrame combined from df1 and df2 with duplicates removed based on 'node_id'.
|
271
|
-
|
272
|
-
Examples:
|
273
|
-
>>> df_main = dataframe.ln_DataFrame([...])
|
274
|
-
>>> df_additional = dataframe.ln_DataFrame([...])
|
275
|
-
>>> combined_df = MessageUtil.extend(df_main, df_additional, keep='first')
|
276
|
-
"""
|
277
|
-
|
278
|
-
MessageUtil.validate_messages(df2)
|
279
|
-
try:
|
280
|
-
if len(df2.dropna(how="all")) > 0 and len(df1.dropna(how="all")) > 0:
|
281
|
-
df = convert.to_df([df1, df2])
|
282
|
-
df.drop_duplicates(
|
283
|
-
inplace=True, subset=["node_id"], keep="first", **kwargs
|
284
|
-
)
|
285
|
-
return convert.to_df(df)
|
286
|
-
except Exception as e:
|
287
|
-
raise ValueError(f"Error in extending messages: {e}") from e
|
288
|
-
|
289
|
-
@staticmethod
|
290
|
-
def to_markdown_string(messages: dataframe.ln_DataFrame) -> str:
|
291
|
-
"""
|
292
|
-
Converts messages in a DataFrame to a Markdown-formatted string for easy reading.
|
293
|
-
|
294
|
-
Args:
|
295
|
-
messages: A DataFrame containing messages with columns for 'role' and 'content'.
|
296
|
-
|
297
|
-
Returns:
|
298
|
-
A string formatted in Markdown, where each message's content is presented
|
299
|
-
according to its role in a readable format.
|
300
|
-
"""
|
301
|
-
|
302
|
-
answers = []
|
303
|
-
for _, i in messages.iterrows():
|
304
|
-
content = convert.to_dict(i.content)
|
305
|
-
|
306
|
-
if i.role == "assistant":
|
307
|
-
with contextlib.suppress(Exception):
|
308
|
-
a = nested.nget(content, ["action_response", "func"])
|
309
|
-
b = nested.nget(content, ["action_response", "arguments"])
|
310
|
-
c = nested.nget(content, ["action_response", "output"])
|
311
|
-
if a is not None:
|
312
|
-
answers.extend(
|
313
|
-
(f"Function: {a}", f"Arguments: {b}", f"Output: {c}")
|
314
|
-
)
|
315
|
-
else:
|
316
|
-
answers.append(nested.nget(content, ["assistant_response"]))
|
317
|
-
elif i.role == "user":
|
318
|
-
with contextlib.suppress(Exception):
|
319
|
-
answers.append(nested.nget(content, ["instruction"]))
|
320
|
-
else:
|
321
|
-
with contextlib.suppress(Exception):
|
322
|
-
answers.append(nested.nget(content, ["system_info"]))
|
323
|
-
return "\n".join(answers)
|