lionagi 0.0.306__py3-none-any.whl → 0.0.307__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 +2 -5
- lionagi/core/__init__.py +7 -5
- lionagi/core/agent/__init__.py +3 -0
- lionagi/core/agent/base_agent.py +10 -12
- lionagi/core/branch/__init__.py +4 -0
- lionagi/core/branch/base_branch.py +81 -81
- lionagi/core/branch/branch.py +16 -28
- lionagi/core/branch/branch_flow_mixin.py +3 -7
- lionagi/core/branch/executable_branch.py +86 -56
- lionagi/core/branch/util.py +77 -162
- lionagi/core/{flow/direct → direct}/__init__.py +1 -1
- lionagi/core/{flow/direct/predict.py → direct/parallel_predict.py} +39 -17
- lionagi/core/direct/parallel_react.py +0 -0
- lionagi/core/direct/parallel_score.py +0 -0
- lionagi/core/direct/parallel_select.py +0 -0
- lionagi/core/direct/parallel_sentiment.py +0 -0
- lionagi/core/direct/predict.py +174 -0
- lionagi/core/{flow/direct → direct}/react.py +2 -2
- lionagi/core/{flow/direct → direct}/score.py +28 -23
- lionagi/core/{flow/direct → direct}/select.py +48 -45
- lionagi/core/direct/utils.py +83 -0
- lionagi/core/flow/monoflow/ReAct.py +6 -5
- lionagi/core/flow/monoflow/__init__.py +9 -0
- lionagi/core/flow/monoflow/chat.py +10 -10
- lionagi/core/flow/monoflow/chat_mixin.py +11 -10
- lionagi/core/flow/monoflow/followup.py +6 -5
- lionagi/core/flow/polyflow/__init__.py +1 -0
- lionagi/core/flow/polyflow/chat.py +15 -3
- lionagi/core/mail/mail_manager.py +18 -19
- lionagi/core/mail/schema.py +5 -4
- lionagi/core/messages/schema.py +18 -20
- lionagi/core/prompt/__init__.py +0 -0
- lionagi/core/prompt/prompt_template.py +0 -0
- lionagi/core/schema/__init__.py +2 -2
- lionagi/core/schema/action_node.py +11 -3
- lionagi/core/schema/base_mixin.py +56 -59
- lionagi/core/schema/base_node.py +35 -38
- lionagi/core/schema/condition.py +24 -0
- lionagi/core/schema/data_logger.py +96 -99
- lionagi/core/schema/data_node.py +19 -19
- lionagi/core/schema/prompt_template.py +0 -0
- lionagi/core/schema/structure.py +171 -169
- lionagi/core/session/__init__.py +1 -3
- lionagi/core/session/session.py +196 -214
- lionagi/core/tool/tool_manager.py +95 -103
- lionagi/integrations/__init__.py +1 -3
- lionagi/integrations/bridge/langchain_/documents.py +17 -18
- lionagi/integrations/bridge/langchain_/langchain_bridge.py +14 -14
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +22 -22
- lionagi/integrations/bridge/llamaindex_/node_parser.py +12 -12
- lionagi/integrations/bridge/llamaindex_/reader.py +11 -11
- lionagi/integrations/bridge/llamaindex_/textnode.py +7 -7
- lionagi/integrations/config/openrouter_configs.py +0 -1
- lionagi/integrations/provider/oai.py +26 -26
- lionagi/integrations/provider/services.py +38 -38
- lionagi/libs/__init__.py +34 -1
- lionagi/libs/ln_api.py +211 -221
- lionagi/libs/ln_async.py +53 -60
- lionagi/libs/ln_convert.py +118 -120
- lionagi/libs/ln_dataframe.py +32 -33
- lionagi/libs/ln_func_call.py +334 -342
- lionagi/libs/ln_nested.py +99 -107
- lionagi/libs/ln_parse.py +161 -165
- lionagi/libs/sys_util.py +52 -52
- lionagi/tests/test_core/test_session.py +254 -266
- lionagi/tests/test_core/test_session_base_util.py +299 -300
- lionagi/tests/test_core/test_tool_manager.py +70 -74
- lionagi/tests/test_libs/test_nested.py +2 -7
- lionagi/tests/test_libs/test_parse.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.0.306.dist-info → lionagi-0.0.307.dist-info}/METADATA +4 -2
- lionagi-0.0.307.dist-info/RECORD +115 -0
- lionagi/core/flow/direct/utils.py +0 -43
- lionagi-0.0.306.dist-info/RECORD +0 -106
- /lionagi/core/{flow/direct → direct}/sentiment.py +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.307.dist-info}/LICENSE +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.307.dist-info}/WHEEL +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.307.dist-info}/top_level.txt +0 -0
@@ -25,18 +25,18 @@ class MonoChat(BaseMonoFlow, MonoChatMixin):
|
|
25
25
|
a chat conversation with LLM, processing instructions and system messages, optionally invoking tools.
|
26
26
|
|
27
27
|
Args:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
branch: The Branch instance to perform chat operations.
|
29
|
+
instruction (Union[Instruction, str]): The instruction for the chat.
|
30
|
+
context (Optional[Any]): Additional context for the chat.
|
31
|
+
sender (Optional[str]): The sender of the chat message.
|
32
|
+
system (Optional[Union[System, str, Dict[str, Any]]]): System message to be processed.
|
33
|
+
tools (Union[bool, Tool, List[Tool], str, List[str]]): Specifies tools to be invoked.
|
34
|
+
out (bool): If True, outputs the chat response.
|
35
|
+
invoke (bool): If True, invokes tools as part of the chat.
|
36
|
+
**kwargs: Arbitrary keyword arguments for chat completion.
|
37
37
|
|
38
38
|
Examples:
|
39
|
-
|
39
|
+
>>> await ChatFlow.chat(branch, "Ask about user preferences")
|
40
40
|
"""
|
41
41
|
|
42
42
|
config = self._create_chat_config(
|
@@ -36,32 +36,33 @@ class MonoChatConfigMixin(ABC):
|
|
36
36
|
if "tool_parsed" in kwargs:
|
37
37
|
kwargs.pop("tool_parsed")
|
38
38
|
tool_kwarg = {"tools": tools}
|
39
|
-
kwargs =
|
40
|
-
|
41
|
-
|
42
|
-
kwargs = self.branch.tool_manager.parse_tool(tools=tools, **kwargs)
|
39
|
+
kwargs = tool_kwarg | kwargs
|
40
|
+
elif tools and self.branch.has_tools:
|
41
|
+
kwargs = self.branch.tool_manager.parse_tool(tools=tools, **kwargs)
|
43
42
|
|
44
43
|
config = {**self.branch.llmconfig, **kwargs}
|
45
44
|
if sender is not None:
|
46
|
-
config
|
45
|
+
config["sender"] = sender
|
47
46
|
|
48
47
|
return config
|
49
48
|
|
50
49
|
|
51
50
|
class MonoChatInvokeMixin(ABC):
|
52
51
|
async def _output(self, invoke, out, output_fields, func_calls_=None):
|
52
|
+
# sourcery skip: use-contextlib-suppress
|
53
53
|
content_ = self.branch.last_message_content
|
54
54
|
|
55
55
|
if invoke:
|
56
56
|
try:
|
57
57
|
await self._invoke_tools(content_, func_calls_=func_calls_)
|
58
|
-
except:
|
58
|
+
except Exception:
|
59
59
|
pass
|
60
60
|
if out:
|
61
61
|
return self._return_response(content_, output_fields)
|
62
62
|
|
63
63
|
@staticmethod
|
64
64
|
def _return_response(content_, output_fields):
|
65
|
+
# sourcery skip: assign-if-exp, use-contextlib-suppress
|
65
66
|
out_ = ""
|
66
67
|
|
67
68
|
if len(content_.items()) == 1 and len(nested.get_flattened_keys(content_)) == 1:
|
@@ -75,7 +76,7 @@ class MonoChatInvokeMixin(ABC):
|
|
75
76
|
else:
|
76
77
|
out_ = ParseUtil.md_to_json(out_)
|
77
78
|
out_ = StringMatch.correct_keys(output_fields=output_fields, out_=out_)
|
78
|
-
except:
|
79
|
+
except Exception:
|
79
80
|
pass
|
80
81
|
|
81
82
|
return out_
|
@@ -118,9 +119,9 @@ class MonoChatInvokeMixin(ABC):
|
|
118
119
|
|
119
120
|
async def _call_chatcompletion(self, sender=None, with_sender=False, **kwargs):
|
120
121
|
messages = (
|
121
|
-
self.branch.
|
122
|
-
if
|
123
|
-
else self.branch.
|
122
|
+
self.branch.chat_messages_with_sender
|
123
|
+
if with_sender
|
124
|
+
else self.branch.chat_messages
|
124
125
|
)
|
125
126
|
payload, completion = await self.branch.service.serve_chat(
|
126
127
|
messages=messages, **kwargs
|
@@ -41,16 +41,17 @@ class MonoFollowup(MonoChat):
|
|
41
41
|
try:
|
42
42
|
try:
|
43
43
|
return default.format(num_followup=num_followup)
|
44
|
-
except:
|
44
|
+
except Exception:
|
45
45
|
return default.format(instruction=instruction)
|
46
|
-
except:
|
46
|
+
except Exception:
|
47
47
|
return default
|
48
48
|
|
49
49
|
def _create_followup_config(self, tools, **kwargs):
|
50
50
|
|
51
|
-
if tools is not None
|
52
|
-
|
53
|
-
|
51
|
+
if tools is not None and (
|
52
|
+
isinstance(tools, list) and isinstance(tools[0], Tool)
|
53
|
+
):
|
54
|
+
self.branch.tool_manager.register_tools(tools)
|
54
55
|
|
55
56
|
if not self.branch.tool_manager.has_tools:
|
56
57
|
raise ValueError("No tools found, You need to register tools")
|
@@ -0,0 +1 @@
|
|
1
|
+
from .chat import PolyChat
|
@@ -6,7 +6,6 @@ from lionagi.libs.ln_async import AsyncUtil
|
|
6
6
|
from lionagi.core.messages.schema import Instruction
|
7
7
|
from lionagi.core.branch.branch import Branch
|
8
8
|
|
9
|
-
|
10
9
|
from lionagi.core.flow.base.baseflow import BasePolyFlow
|
11
10
|
|
12
11
|
|
@@ -28,7 +27,7 @@ class PolyChat(BasePolyFlow):
|
|
28
27
|
invoke: bool = True,
|
29
28
|
output_fields=None,
|
30
29
|
persist_path=None,
|
31
|
-
branch_config=
|
30
|
+
branch_config=None,
|
32
31
|
explode=False,
|
33
32
|
**kwargs,
|
34
33
|
) -> Any:
|
@@ -36,6 +35,8 @@ class PolyChat(BasePolyFlow):
|
|
36
35
|
parallel chat
|
37
36
|
"""
|
38
37
|
|
38
|
+
if branch_config is None:
|
39
|
+
branch_config = {}
|
39
40
|
return await self._parallel_chat(
|
40
41
|
instruction,
|
41
42
|
num_instances=num_instances,
|
@@ -67,6 +68,8 @@ class PolyChat(BasePolyFlow):
|
|
67
68
|
persist_path=None,
|
68
69
|
branch_config={},
|
69
70
|
explode=False,
|
71
|
+
include_mapping=True,
|
72
|
+
default_key="response",
|
70
73
|
**kwargs,
|
71
74
|
) -> Any:
|
72
75
|
"""
|
@@ -102,7 +105,16 @@ class PolyChat(BasePolyFlow):
|
|
102
105
|
)
|
103
106
|
|
104
107
|
branches[branch_.id_] = branch_
|
105
|
-
|
108
|
+
if include_mapping:
|
109
|
+
return {
|
110
|
+
"instruction": ins_ or instruction,
|
111
|
+
"context": cxt_ or context,
|
112
|
+
"branch_id": branch_.id_,
|
113
|
+
default_key: res_,
|
114
|
+
}
|
115
|
+
|
116
|
+
else:
|
117
|
+
return res_
|
106
118
|
|
107
119
|
async def _inner_2(i, ins_=None, cxt_=None):
|
108
120
|
"""returns num_instances of branches performing for same task/context"""
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from collections import deque
|
2
|
-
from lionagi.
|
3
|
-
from
|
4
|
-
from
|
2
|
+
from lionagi.libs import AsyncUtil
|
3
|
+
from ..schema import BaseNode
|
4
|
+
from .schema import BaseMail
|
5
5
|
|
6
6
|
|
7
7
|
class MailManager:
|
@@ -12,12 +12,12 @@ class MailManager:
|
|
12
12
|
and deletion of sources, and it handles the collection and dispatch of mails to and from these sources.
|
13
13
|
|
14
14
|
Attributes:
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
sources (Dict[str, Any]): A dictionary mapping source identifiers to their attributes.
|
16
|
+
mails (Dict[str, Dict[str, deque]]): A nested dictionary storing queued mail items, organized by recipient
|
17
|
+
and sender.
|
18
18
|
"""
|
19
19
|
|
20
|
-
def __init__(self, sources
|
20
|
+
def __init__(self, sources):
|
21
21
|
self.sources = {}
|
22
22
|
self.mails = {}
|
23
23
|
self.add_sources(sources)
|
@@ -26,12 +26,12 @@ class MailManager:
|
|
26
26
|
def add_sources(self, sources):
|
27
27
|
if isinstance(sources, dict):
|
28
28
|
for _, v in sources.items():
|
29
|
-
if
|
29
|
+
if v.id_ not in self.sources:
|
30
30
|
self.sources[v.id_] = v
|
31
31
|
self.mails[v.id_] = {}
|
32
32
|
elif isinstance(sources, list):
|
33
33
|
for v in sources:
|
34
|
-
if
|
34
|
+
if v.id_ not in self.sources:
|
35
35
|
self.sources[v.id_] = v
|
36
36
|
self.mails[v.id_] = {}
|
37
37
|
|
@@ -73,15 +73,14 @@ class MailManager:
|
|
73
73
|
raise ValueError(f"Recipient source {recipient_id} does not exist.")
|
74
74
|
if not self.mails[recipient_id]:
|
75
75
|
return
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
self.sources[recipient_id].pending_ins[key].append(mail_)
|
76
|
+
for key in list(self.mails[recipient_id].keys()):
|
77
|
+
mails_deque = self.mails[recipient_id].pop(key)
|
78
|
+
if key not in self.sources[recipient_id].pending_ins:
|
79
|
+
self.sources[recipient_id].pending_ins[key] = mails_deque
|
80
|
+
else:
|
81
|
+
while mails_deque:
|
82
|
+
mail_ = mails_deque.popleft()
|
83
|
+
self.sources[recipient_id].pending_ins[key].append(mail_)
|
85
84
|
|
86
85
|
def collect_all(self):
|
87
86
|
for ids in self.sources:
|
@@ -95,4 +94,4 @@ class MailManager:
|
|
95
94
|
while not self.execute_stop:
|
96
95
|
self.collect_all()
|
97
96
|
self.send_all()
|
98
|
-
await AsyncUtil.sleep(refresh_time)
|
97
|
+
await AsyncUtil.sleep(refresh_time)
|
lionagi/core/mail/schema.py
CHANGED
@@ -10,10 +10,11 @@ class MailCategory(str, Enum):
|
|
10
10
|
SERVICE = "service"
|
11
11
|
MODEL = "model"
|
12
12
|
NODE = "node"
|
13
|
-
|
13
|
+
NODE_LIST = "node_list"
|
14
14
|
NODE_ID = "node_id"
|
15
15
|
START = "start"
|
16
16
|
END = "end"
|
17
|
+
CONDITION = "condition"
|
17
18
|
|
18
19
|
|
19
20
|
class BaseMail:
|
@@ -34,14 +35,14 @@ class BaseMail:
|
|
34
35
|
raise ValueError(
|
35
36
|
f"Invalid request title. Valid titles are "
|
36
37
|
f"{list(MailCategory)}, Error: {e}"
|
37
|
-
)
|
38
|
+
) from e
|
38
39
|
self.package = package
|
39
40
|
|
40
41
|
|
41
42
|
class StartMail(BaseRelatableNode):
|
42
43
|
|
43
|
-
def __init__(self,
|
44
|
-
super().__init__(
|
44
|
+
def __init__(self, **kwargs):
|
45
|
+
super().__init__(**kwargs)
|
45
46
|
self.pending_outs = deque()
|
46
47
|
|
47
48
|
def trigger(self, context, structure_id, executable_id):
|
lionagi/core/messages/schema.py
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
|
3
|
-
from lionagi.libs import
|
4
|
-
from
|
5
|
-
|
6
|
-
from lionagi.core.schema.data_node import DataNode
|
3
|
+
from lionagi.libs import nested, convert
|
4
|
+
from ..schema import DataNode
|
7
5
|
|
8
6
|
_message_fields = ["node_id", "timestamp", "role", "sender", "recipient", "content"]
|
9
7
|
|
8
|
+
|
10
9
|
# ToDo: actually implement the new message classes
|
11
10
|
|
12
11
|
|
@@ -99,9 +98,9 @@ class BaseMessage(DataNode):
|
|
99
98
|
Represents a message in a chatbot-like system, inheriting from BaseNode.
|
100
99
|
|
101
100
|
Attributes:
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
role (str | None): The role of the entity sending the message, e.g., 'user', 'system'.
|
102
|
+
sender (str | None): The identifier of the sender of the message.
|
103
|
+
content (Any): The actual content of the message.
|
105
104
|
"""
|
106
105
|
|
107
106
|
role: str | None = None
|
@@ -114,7 +113,7 @@ class BaseMessage(DataNode):
|
|
114
113
|
Constructs and returns a dictionary representation of the message.
|
115
114
|
|
116
115
|
Returns:
|
117
|
-
|
116
|
+
A dictionary representation of the message with 'role' and 'content' keys.
|
118
117
|
"""
|
119
118
|
return self._to_message()
|
120
119
|
|
@@ -124,7 +123,7 @@ class BaseMessage(DataNode):
|
|
124
123
|
Gets the 'content' field of the message.
|
125
124
|
|
126
125
|
Returns:
|
127
|
-
|
126
|
+
The 'content' part of the message.
|
128
127
|
"""
|
129
128
|
return self.msg["content"]
|
130
129
|
|
@@ -133,14 +132,13 @@ class BaseMessage(DataNode):
|
|
133
132
|
Constructs and returns a dictionary representation of the message.
|
134
133
|
|
135
134
|
Returns:
|
136
|
-
|
135
|
+
dict: A dictionary representation of the message with 'role' and 'content' keys.
|
137
136
|
"""
|
138
|
-
|
139
|
-
return out
|
137
|
+
return {"role": self.role, "content": convert.to_str(self.content)}
|
140
138
|
|
141
139
|
def __str__(self):
|
142
140
|
content_preview = (
|
143
|
-
|
141
|
+
f"{str(self.content)[:75]}..."
|
144
142
|
if self.content and len(self.content) > 75
|
145
143
|
else str(self.content)
|
146
144
|
)
|
@@ -162,7 +160,7 @@ class Instruction(BaseMessage):
|
|
162
160
|
sender: str | None = None,
|
163
161
|
output_fields=None,
|
164
162
|
recipient=None,
|
165
|
-
):
|
163
|
+
): # sourcery skip: avoid-builtin-shadow
|
166
164
|
super().__init__(
|
167
165
|
role="user",
|
168
166
|
sender=sender or "user",
|
@@ -256,13 +254,13 @@ class Response(BaseMessage):
|
|
256
254
|
content_key = content_key or "response"
|
257
255
|
sender = sender or "assistant"
|
258
256
|
recipient = recipient or "user"
|
259
|
-
except:
|
257
|
+
except Exception:
|
260
258
|
content_ = response["content"]
|
261
259
|
content_key = content_key or "response"
|
262
260
|
sender = sender or "assistant"
|
263
261
|
recipient = recipient or "user"
|
264
262
|
|
265
|
-
except:
|
263
|
+
except Exception:
|
266
264
|
sender = sender or "action_response"
|
267
265
|
content_ = response
|
268
266
|
content_key = content_key or "action_response"
|
@@ -281,13 +279,13 @@ class Response(BaseMessage):
|
|
281
279
|
Processes an action request response and extracts relevant information.
|
282
280
|
|
283
281
|
Args:
|
284
|
-
|
282
|
+
response (dict): The response dictionary containing tool calls and other information.
|
285
283
|
|
286
284
|
Returns:
|
287
|
-
|
285
|
+
list: A list of dictionaries, each representing a function call with action and arguments.
|
288
286
|
|
289
287
|
Raises:
|
290
|
-
|
288
|
+
ValueError: If the response does not conform to the expected format for action requests.
|
291
289
|
"""
|
292
290
|
try:
|
293
291
|
tool_count = 0
|
@@ -300,7 +298,7 @@ class Response(BaseMessage):
|
|
300
298
|
_path2 = ["tool_calls", tool_count, "function", "arguments"]
|
301
299
|
|
302
300
|
func_content = {
|
303
|
-
"action":
|
301
|
+
"action": f"action_{nested.nget(response, _path1)}",
|
304
302
|
"arguments": nested.nget(response, _path2),
|
305
303
|
}
|
306
304
|
func_list.append(func_content)
|
File without changes
|
File without changes
|
lionagi/core/schema/__init__.py
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
from .base_node import BaseNode, BaseRelatableNode, Tool
|
1
|
+
from .base_node import BaseNode, BaseRelatableNode, Tool, TOOL_TYPE
|
2
2
|
from .data_node import DataNode
|
3
3
|
from .data_logger import DLog, DataLogger
|
4
4
|
from .structure import Relationship, Graph, Structure
|
5
5
|
from .action_node import ActionNode
|
6
6
|
|
7
|
-
|
8
7
|
__all__ = [
|
9
8
|
"BaseNode",
|
10
9
|
"BaseRelatableNode",
|
@@ -16,4 +15,5 @@ __all__ = [
|
|
16
15
|
"Graph",
|
17
16
|
"Structure",
|
18
17
|
"ActionNode",
|
18
|
+
"TOOL_TYPE",
|
19
19
|
]
|
@@ -1,11 +1,13 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
|
3
|
-
from
|
3
|
+
from .base_node import BaseNode
|
4
4
|
|
5
5
|
|
6
6
|
class ActionSelection(BaseNode):
|
7
7
|
|
8
|
-
def __init__(self, action: str = "chat", action_kwargs=
|
8
|
+
def __init__(self, action: str = "chat", action_kwargs=None):
|
9
|
+
if action_kwargs is None:
|
10
|
+
action_kwargs = {}
|
9
11
|
super().__init__()
|
10
12
|
self.action = action
|
11
13
|
self.action_kwargs = action_kwargs
|
@@ -13,7 +15,13 @@ class ActionSelection(BaseNode):
|
|
13
15
|
|
14
16
|
class ActionNode(BaseNode):
|
15
17
|
|
16
|
-
def __init__(
|
18
|
+
def __init__(
|
19
|
+
self, instruction, action: str = "chat", tools=None, action_kwargs=None
|
20
|
+
):
|
21
|
+
if tools is None:
|
22
|
+
tools = []
|
23
|
+
if action_kwargs is None:
|
24
|
+
action_kwargs = {}
|
17
25
|
super().__init__()
|
18
26
|
self.instruction = instruction
|
19
27
|
self.action = action
|