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,10 +1,14 @@
|
|
1
1
|
from collections import deque
|
2
|
+
from pydantic import Field
|
2
3
|
from lionagi.libs import AsyncUtil
|
3
|
-
from
|
4
|
-
from .
|
4
|
+
from lionagi.core.collections.abc import Executable, Element
|
5
|
+
from lionagi.core.collections import Exchange
|
6
|
+
from lionagi.core.collections.util import to_list_type, get_lion_id
|
7
|
+
from .mail import Mail, Package
|
8
|
+
from lionagi.core.collections import Pile, pile
|
5
9
|
|
6
10
|
|
7
|
-
class MailManager:
|
11
|
+
class MailManager(Element, Executable):
|
8
12
|
"""
|
9
13
|
Manages the sending, receiving, and storage of mail items between various sources.
|
10
14
|
|
@@ -15,82 +19,162 @@ class MailManager:
|
|
15
19
|
sources (Dict[str, Any]): A dictionary mapping source identifiers to their attributes.
|
16
20
|
mails (Dict[str, Dict[str, deque]]): A nested dictionary storing queued mail items, organized by recipient
|
17
21
|
and sender.
|
22
|
+
execute_stop (bool): A flag indicating whether to stop execution.
|
18
23
|
"""
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
sources: Pile[Element] = Field(
|
26
|
+
default_factory=lambda: pile(),
|
27
|
+
description="The pile of managed sources",
|
28
|
+
)
|
29
|
+
|
30
|
+
mails: dict[str, dict[str, deque]] = Field(
|
31
|
+
default_factory=dict,
|
32
|
+
description="The mails waiting to be sent",
|
33
|
+
examples=["{'recipient_id': {'sender_id': deque()}}"],
|
34
|
+
)
|
35
|
+
|
36
|
+
execute_stop: bool = Field(
|
37
|
+
False, description="A flag indicating whether to stop execution."
|
38
|
+
)
|
39
|
+
|
40
|
+
def __init__(self, sources=None):
|
41
|
+
"""
|
42
|
+
Initializes the MailManager with optional sources.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
sources (Optional[list]): A list of sources to be managed by the MailManager.
|
46
|
+
"""
|
47
|
+
super().__init__()
|
48
|
+
if sources:
|
49
|
+
self.add_sources(sources)
|
25
50
|
|
26
51
|
def add_sources(self, sources):
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
52
|
+
"""
|
53
|
+
Adds new sources to the MailManager.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
sources (list): A list of sources to be added.
|
57
|
+
|
58
|
+
Raises:
|
59
|
+
ValueError: If failed to add sources.
|
60
|
+
"""
|
61
|
+
try:
|
62
|
+
sources = to_list_type(sources)
|
63
|
+
self.sources.include(sources)
|
64
|
+
for item in sources:
|
65
|
+
self.mails[item.ln_id] = {}
|
66
|
+
except Exception as e:
|
67
|
+
raise ValueError(f"Failed to add source. Error {e}")
|
37
68
|
|
38
69
|
@staticmethod
|
39
|
-
def create_mail(
|
40
|
-
|
70
|
+
def create_mail(sender, recipient, category, package):
|
71
|
+
"""
|
72
|
+
Creates a mail item.
|
41
73
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
74
|
+
Args:
|
75
|
+
sender (str): The sender of the mail.
|
76
|
+
recipient (str): The recipient of the mail.
|
77
|
+
category (str): The category of the mail.
|
78
|
+
package (Any): The content of the package.
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
Mail: The created mail object.
|
82
|
+
"""
|
83
|
+
pack = Package(category=category, package=package)
|
84
|
+
mail = Mail(
|
85
|
+
sender=sender,
|
86
|
+
recipient=recipient,
|
87
|
+
package=pack,
|
88
|
+
)
|
89
|
+
return mail
|
49
90
|
|
50
91
|
def delete_source(self, source_id):
|
92
|
+
"""
|
93
|
+
Deletes a source from the MailManager.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
source_id (str): The ID of the source to be deleted.
|
97
|
+
|
98
|
+
Raises:
|
99
|
+
ValueError: If the source does not exist.
|
100
|
+
"""
|
51
101
|
if source_id not in self.sources:
|
52
102
|
raise ValueError(f"Source {source_id} does not exist.")
|
53
|
-
# if self.mails[source_id]:
|
54
|
-
# raise ValueError(f"None empty pending mails in source {source_id}")
|
55
103
|
self.sources.pop(source_id)
|
56
104
|
self.mails.pop(source_id)
|
57
105
|
|
58
|
-
def collect(self,
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
106
|
+
def collect(self, sender):
|
107
|
+
"""
|
108
|
+
Collects mails from a sender's outbox and queues them for the recipient.
|
109
|
+
|
110
|
+
Args:
|
111
|
+
sender (str): The ID of the sender.
|
112
|
+
|
113
|
+
Raises:
|
114
|
+
ValueError: If the sender or recipient source does not exist.
|
115
|
+
"""
|
116
|
+
if sender not in self.sources:
|
117
|
+
raise ValueError(f"Sender source {sender} does not exist.")
|
118
|
+
mailbox = (
|
119
|
+
self.sources[sender]
|
120
|
+
if isinstance(self.sources[sender], Exchange)
|
121
|
+
else self.sources[sender].mailbox
|
122
|
+
)
|
123
|
+
while mailbox.pending_outs.size() > 0:
|
124
|
+
mail_id = mailbox.pending_outs.popleft()
|
125
|
+
mail = mailbox.pile.pop(mail_id)
|
126
|
+
if mail.recipient not in self.sources:
|
127
|
+
raise ValueError(f"Recipient source {mail.recipient} does not exist")
|
128
|
+
if mail.sender not in self.mails[mail.recipient]:
|
129
|
+
self.mails[mail.recipient].update({mail.sender: deque()})
|
130
|
+
self.mails[mail.recipient][mail.sender].append(mail)
|
131
|
+
|
132
|
+
def send(self, recipient):
|
133
|
+
"""
|
134
|
+
Sends mails to a recipient's inbox.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
recipient (str): The ID of the recipient.
|
138
|
+
|
139
|
+
Raises:
|
140
|
+
ValueError: If the recipient source does not exist.
|
141
|
+
"""
|
142
|
+
if recipient not in self.sources:
|
143
|
+
raise ValueError(f"Recipient source {recipient} does not exist.")
|
144
|
+
if not self.mails[recipient]:
|
75
145
|
return
|
76
|
-
for key in list(self.mails[
|
77
|
-
|
78
|
-
|
79
|
-
self.sources[
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
146
|
+
for key in list(self.mails[recipient].keys()):
|
147
|
+
pending_mails = self.mails[recipient].pop(key)
|
148
|
+
mailbox = (
|
149
|
+
self.sources[recipient]
|
150
|
+
if isinstance(self.sources[recipient], Exchange)
|
151
|
+
else self.sources[recipient].mailbox
|
152
|
+
)
|
153
|
+
while pending_mails:
|
154
|
+
mail = pending_mails.popleft()
|
155
|
+
mailbox.include(mail, "in")
|
84
156
|
|
85
157
|
def collect_all(self):
|
86
|
-
|
87
|
-
|
158
|
+
"""
|
159
|
+
Collects mails from all sources.
|
160
|
+
"""
|
161
|
+
for source in self.sources:
|
162
|
+
self.collect(get_lion_id(source))
|
88
163
|
|
89
164
|
def send_all(self):
|
90
|
-
|
91
|
-
|
165
|
+
"""
|
166
|
+
Sends mails to all sources.
|
167
|
+
"""
|
168
|
+
for source in self.sources:
|
169
|
+
self.send(get_lion_id(source))
|
92
170
|
|
93
171
|
async def execute(self, refresh_time=1):
|
172
|
+
"""
|
173
|
+
Continuously collects and sends mails until execution is stopped.
|
174
|
+
|
175
|
+
Args:
|
176
|
+
refresh_time (int): The time in seconds to wait between each cycle. Defaults to 1.
|
177
|
+
"""
|
94
178
|
while not self.execute_stop:
|
95
179
|
self.collect_all()
|
96
180
|
self.send_all()
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import Any
|
3
|
+
from pydantic import field_validator
|
4
|
+
from lionagi.core.collections.abc import Element, Field
|
5
|
+
|
6
|
+
|
7
|
+
class PackageCategory(str, Enum):
|
8
|
+
MESSAGE = "message"
|
9
|
+
TOOL = "tool"
|
10
|
+
IMODEL = "imodel"
|
11
|
+
NODE = "node"
|
12
|
+
NODE_LIST = "node_list"
|
13
|
+
NODE_ID = "node_id"
|
14
|
+
START = "start"
|
15
|
+
END = "end"
|
16
|
+
CONDITION = "condition"
|
17
|
+
|
18
|
+
|
19
|
+
class Package(Element):
|
20
|
+
|
21
|
+
request_source: str | None = None
|
22
|
+
|
23
|
+
category: PackageCategory = Field(
|
24
|
+
None,
|
25
|
+
title="Category",
|
26
|
+
description="The category of the package.",
|
27
|
+
)
|
28
|
+
|
29
|
+
package: Any = Field(
|
30
|
+
None,
|
31
|
+
title="Package",
|
32
|
+
description="The package to be delivered.",
|
33
|
+
)
|
34
|
+
|
35
|
+
@field_validator("category", mode="before")
|
36
|
+
def validate_category(cls, value: Any):
|
37
|
+
if value is None:
|
38
|
+
raise ValueError("Package category cannot be None.")
|
39
|
+
if isinstance(value, PackageCategory):
|
40
|
+
return value
|
41
|
+
else:
|
42
|
+
try:
|
43
|
+
return PackageCategory(value)
|
44
|
+
except Exception as e:
|
45
|
+
raise ValueError(f"Invalid value for category: {value}.") from e
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from collections import deque
|
2
|
+
from pydantic import Field
|
3
|
+
from lionagi.core.generic.node import Node
|
4
|
+
from lionagi.core.mail.mail import Mail, Package
|
5
|
+
from lionagi.core.collections import Exchange
|
6
|
+
|
7
|
+
|
8
|
+
class StartMail(Node):
|
9
|
+
"""
|
10
|
+
Represents a start mail node that triggers the initiation of a process.
|
11
|
+
|
12
|
+
Attributes:
|
13
|
+
mailbox (Exchange): The exchange object that holds pending start mails.
|
14
|
+
"""
|
15
|
+
|
16
|
+
mailbox: Exchange = Field(
|
17
|
+
default_factory=Exchange[Mail], description="The pending start mail"
|
18
|
+
)
|
19
|
+
|
20
|
+
def trigger(self, context, structure_id, executable_id):
|
21
|
+
"""
|
22
|
+
Triggers the start mail by including it in the mailbox.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
context (Any): The context to be included in the start mail.
|
26
|
+
structure_id (str): The ID of the structure to be initiated.
|
27
|
+
executable_id (str): The ID of the executable to receive the start mail.
|
28
|
+
"""
|
29
|
+
start_mail_content = {"context": context, "structure_id": structure_id}
|
30
|
+
pack = Package(category="start", package=start_mail_content)
|
31
|
+
start_mail = Mail(
|
32
|
+
sender=self.ln_id,
|
33
|
+
recipient=executable_id,
|
34
|
+
package=pack,
|
35
|
+
)
|
36
|
+
self.mailbox.include(start_mail, "out")
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from .message import RoledMessage, MessageRole
|
2
|
+
from .system import System
|
3
|
+
from .instruction import Instruction
|
4
|
+
from .assistant_response import AssistantResponse
|
5
|
+
from .action_request import ActionRequest
|
6
|
+
from .action_response import ActionResponse
|
7
|
+
from .util import create_message
|
8
|
+
|
9
|
+
|
10
|
+
__all__ = [
|
11
|
+
"RoledMessage",
|
12
|
+
"MessageRole",
|
13
|
+
"System",
|
14
|
+
"Instruction",
|
15
|
+
"AssistantResponse",
|
16
|
+
"ActionRequest",
|
17
|
+
"ActionResponse",
|
18
|
+
"create_message",
|
19
|
+
]
|
@@ -0,0 +1,133 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import inspect
|
18
|
+
from pydantic import Field
|
19
|
+
from lionagi.libs import convert, ParseUtil
|
20
|
+
from .message import RoledMessage, MessageRole
|
21
|
+
|
22
|
+
|
23
|
+
class ActionRequest(RoledMessage):
|
24
|
+
"""
|
25
|
+
Represents a request for an action with function and arguments.
|
26
|
+
|
27
|
+
Inherits from `RoledMessage` and provides attributes specific to action requests.
|
28
|
+
|
29
|
+
Attributes:
|
30
|
+
function (str): The name of the function to be called.
|
31
|
+
arguments (dict): The keyword arguments to be passed to the function.
|
32
|
+
action_response (str): The ID of the action response that this request corresponds to.
|
33
|
+
"""
|
34
|
+
|
35
|
+
function: str | None = Field(
|
36
|
+
None, description="The name of the function to be called"
|
37
|
+
)
|
38
|
+
|
39
|
+
arguments: dict | None = Field(
|
40
|
+
None, description="The keyword arguments to be passed to the function"
|
41
|
+
)
|
42
|
+
|
43
|
+
action_response: str | None = Field(
|
44
|
+
None,
|
45
|
+
description="The id of the action response that this request corresponds to",
|
46
|
+
)
|
47
|
+
|
48
|
+
def __init__(
|
49
|
+
self,
|
50
|
+
function=None,
|
51
|
+
arguments=None,
|
52
|
+
sender=None, # sender is the assistant who made the request
|
53
|
+
recipient=None, # recipient is the actionable component
|
54
|
+
**kwargs,
|
55
|
+
):
|
56
|
+
"""
|
57
|
+
Initializes the ActionRequest.
|
58
|
+
|
59
|
+
Args:
|
60
|
+
function (str or function, optional): The function to be called.
|
61
|
+
arguments (dict, optional): The keyword arguments for the function.
|
62
|
+
sender (str, optional): The sender of the request.
|
63
|
+
recipient (str, optional): The recipient of the request.
|
64
|
+
"""
|
65
|
+
function = function.__name__ if inspect.isfunction(function) else function
|
66
|
+
arguments = _prepare_arguments(arguments)
|
67
|
+
|
68
|
+
super().__init__(
|
69
|
+
role=MessageRole.ASSISTANT,
|
70
|
+
sender=sender,
|
71
|
+
recipient=recipient,
|
72
|
+
content={"action_request": {"function": function, "arguments": arguments}},
|
73
|
+
**kwargs,
|
74
|
+
)
|
75
|
+
self.function = function
|
76
|
+
self.arguments = arguments
|
77
|
+
|
78
|
+
def is_responded(self):
|
79
|
+
"""
|
80
|
+
Checks if the action request has been responded to.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
bool: True if the action request has a response, otherwise False.
|
84
|
+
"""
|
85
|
+
return self.action_response is not None
|
86
|
+
|
87
|
+
def clone(self, **kwargs):
|
88
|
+
"""
|
89
|
+
Creates a copy of the current ActionRequest object with optional additional arguments.
|
90
|
+
|
91
|
+
This method clones the current object, preserving its function and arguments.
|
92
|
+
It also retains the original `action_response` and metadata, while allowing
|
93
|
+
for the addition of new attributes through keyword arguments.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
**kwargs: Optional keyword arguments to be included in the cloned object.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
ActionRequest: A new instance of the object with the same function, arguments,
|
100
|
+
and additional keyword arguments.
|
101
|
+
"""
|
102
|
+
import json
|
103
|
+
|
104
|
+
arguments = json.dumps(self.arguments)
|
105
|
+
request_copy = ActionRequest(
|
106
|
+
function=self.function, arguments=json.loads(arguments), **kwargs
|
107
|
+
)
|
108
|
+
request_copy.action_response = self.action_response
|
109
|
+
request_copy.metadata["origin_ln_id"] = self.ln_id
|
110
|
+
return request_copy
|
111
|
+
|
112
|
+
|
113
|
+
def _prepare_arguments(arguments):
|
114
|
+
"""
|
115
|
+
Prepares the arguments for the action request.
|
116
|
+
|
117
|
+
Args:
|
118
|
+
arguments (Any): The arguments to be prepared.
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
dict: The prepared arguments.
|
122
|
+
|
123
|
+
Raises:
|
124
|
+
ValueError: If the arguments are invalid.
|
125
|
+
"""
|
126
|
+
if not isinstance(arguments, dict):
|
127
|
+
try:
|
128
|
+
arguments = ParseUtil.fuzzy_parse_json(convert.to_str(arguments))
|
129
|
+
except Exception as e:
|
130
|
+
raise ValueError(f"Invalid arguments: {e}") from e
|
131
|
+
if isinstance(arguments, dict):
|
132
|
+
return arguments
|
133
|
+
raise ValueError(f"Invalid arguments: {arguments}")
|
@@ -0,0 +1,135 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
from typing import Any
|
18
|
+
from pydantic import Field
|
19
|
+
from .message import RoledMessage, MessageRole
|
20
|
+
from .action_request import ActionRequest
|
21
|
+
|
22
|
+
|
23
|
+
# action response must correlates to a specific action request
|
24
|
+
class ActionResponse(RoledMessage):
|
25
|
+
"""
|
26
|
+
Represents a response to a specific action request.
|
27
|
+
|
28
|
+
Inherits from `RoledMessage` and provides attributes specific to action responses.
|
29
|
+
|
30
|
+
Attributes:
|
31
|
+
action_request (str): The ID of the action request that this response corresponds to.
|
32
|
+
function (str): The name of the function called.
|
33
|
+
arguments (dict): The keyword arguments provided.
|
34
|
+
func_outputs (Any): The output of the function call.
|
35
|
+
"""
|
36
|
+
|
37
|
+
action_request: str | None = Field(
|
38
|
+
None,
|
39
|
+
description="The id of the action request that this response corresponds to",
|
40
|
+
)
|
41
|
+
|
42
|
+
function: str | None = Field(None, description="The name of the function called")
|
43
|
+
arguments: dict | None = Field(None, description="The keyword arguments provided")
|
44
|
+
func_outputs: Any | None = Field(
|
45
|
+
None, description="The output of the function call"
|
46
|
+
)
|
47
|
+
|
48
|
+
def __init__(
|
49
|
+
self,
|
50
|
+
action_request: ActionRequest,
|
51
|
+
sender: str | None = None, # the sender of action request
|
52
|
+
func_outputs=None,
|
53
|
+
**kwargs,
|
54
|
+
):
|
55
|
+
"""
|
56
|
+
Initializes the ActionResponse.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
action_request (ActionRequest): The action request that this response corresponds to.
|
60
|
+
sender (str, optional): The sender of the action request.
|
61
|
+
func_outputs (Any, optional): The output of the function call.
|
62
|
+
|
63
|
+
Raises:
|
64
|
+
ValueError: If the action request has already been responded to.
|
65
|
+
"""
|
66
|
+
if action_request.is_responded():
|
67
|
+
raise ValueError("Action request has already been responded to")
|
68
|
+
|
69
|
+
super().__init__(
|
70
|
+
role=MessageRole.ASSISTANT,
|
71
|
+
sender=sender or "N/A", # sender is the actionable component
|
72
|
+
recipient=action_request.sender, # recipient is the assistant who made the request
|
73
|
+
content={
|
74
|
+
"action_response": {
|
75
|
+
"function": action_request.function,
|
76
|
+
"arguments": action_request.arguments,
|
77
|
+
"output": func_outputs,
|
78
|
+
}
|
79
|
+
},
|
80
|
+
**kwargs,
|
81
|
+
)
|
82
|
+
self.update_request(action_request)
|
83
|
+
self.func_outputs = func_outputs
|
84
|
+
|
85
|
+
def update_request(self, action_request: ActionRequest):
|
86
|
+
"""
|
87
|
+
Updates the action request details in the action response.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
action_request (ActionRequest): The action request to update from.
|
91
|
+
"""
|
92
|
+
self.function = action_request.function
|
93
|
+
self.arguments = action_request.arguments
|
94
|
+
self.action_request = action_request.ln_id
|
95
|
+
action_request.action_response = self.ln_id
|
96
|
+
|
97
|
+
def _to_dict(self):
|
98
|
+
"""
|
99
|
+
Converts the action response to a dictionary.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
dict: A dictionary representation of the action response.
|
103
|
+
"""
|
104
|
+
return {
|
105
|
+
"function": self.function,
|
106
|
+
"arguments": self.arguments,
|
107
|
+
"output": self.func_outputs,
|
108
|
+
}
|
109
|
+
|
110
|
+
def clone(self, **kwargs):
|
111
|
+
"""
|
112
|
+
Creates a copy of the current object with optional additional arguments.
|
113
|
+
|
114
|
+
This method clones the current object, preserving its function and arguments.
|
115
|
+
It also retains the original `action_request`, `func_outputs`, and metadata,
|
116
|
+
while allowing for the addition of new attributes through keyword arguments.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
**kwargs: Optional keyword arguments to be included in the cloned object.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
ActionResponse: A new instance of the object with the same function, arguments,
|
123
|
+
and additional keyword arguments.
|
124
|
+
"""
|
125
|
+
import json
|
126
|
+
|
127
|
+
arguments = json.dumps(self.arguments)
|
128
|
+
action_request = ActionRequest(
|
129
|
+
function=self.function, arguments=json.loads(arguments)
|
130
|
+
)
|
131
|
+
action_response_copy = ActionResponse(action_request=action_request, **kwargs)
|
132
|
+
action_response_copy.action_request = self.action_request
|
133
|
+
action_response_copy.func_outputs = self.func_outputs
|
134
|
+
action_response_copy.metadata["origin_ln_id"] = self.ln_id
|
135
|
+
return action_response_copy
|