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/branch/base.py
DELETED
@@ -1,653 +0,0 @@
|
|
1
|
-
from abc import ABC
|
2
|
-
from typing import Any
|
3
|
-
|
4
|
-
from pathlib import Path
|
5
|
-
from lionagi.libs import convert, dataframe, SysUtil
|
6
|
-
|
7
|
-
from lionagi.core.generic import BaseNode, DataLogger, DLog
|
8
|
-
from lionagi.core.messages.schema import (
|
9
|
-
BranchColumns,
|
10
|
-
System,
|
11
|
-
Response,
|
12
|
-
Instruction,
|
13
|
-
BaseMessage,
|
14
|
-
)
|
15
|
-
from lionagi.core.branch.util import MessageUtil
|
16
|
-
|
17
|
-
|
18
|
-
class BaseBranch(BaseNode, ABC):
|
19
|
-
"""
|
20
|
-
Base class for managing branches of conversation, incorporating messages
|
21
|
-
and logging functionality.
|
22
|
-
|
23
|
-
Attributes:
|
24
|
-
messages (dataframe.ln_DataFrame): Holds the messages in the branch.
|
25
|
-
datalogger (DataLogger): Logs data related to the branch's operation.
|
26
|
-
persist_path (str | Path): Filesystem path for data persistence.
|
27
|
-
"""
|
28
|
-
|
29
|
-
_columns: list[str] = BranchColumns.COLUMNS.value
|
30
|
-
|
31
|
-
def __init__(
|
32
|
-
self,
|
33
|
-
messages: dataframe.ln_DataFrame | None = None,
|
34
|
-
datalogger: DataLogger | None = None,
|
35
|
-
persist_path: str | Path | None = None,
|
36
|
-
name=None,
|
37
|
-
**kwargs,
|
38
|
-
) -> None:
|
39
|
-
super().__init__(**kwargs)
|
40
|
-
if isinstance(messages, dataframe.ln_DataFrame):
|
41
|
-
if MessageUtil.validate_messages(messages):
|
42
|
-
self.messages = messages
|
43
|
-
else:
|
44
|
-
raise ValueError("Invalid messages format")
|
45
|
-
else:
|
46
|
-
self.messages = dataframe.ln_DataFrame(columns=self._columns)
|
47
|
-
|
48
|
-
self.datalogger = datalogger or DataLogger(persist_path=persist_path)
|
49
|
-
self.name = name
|
50
|
-
|
51
|
-
def add_message(
|
52
|
-
self,
|
53
|
-
system: dict | list | System | None = None,
|
54
|
-
instruction: dict | list | Instruction | None = None,
|
55
|
-
context: str | dict[str, Any] | None = None,
|
56
|
-
response: dict | list | BaseMessage | None = None,
|
57
|
-
output_fields=None,
|
58
|
-
recipient=None,
|
59
|
-
**kwargs,
|
60
|
-
) -> None:
|
61
|
-
"""
|
62
|
-
Adds a message to the branch.
|
63
|
-
|
64
|
-
Args:
|
65
|
-
system: Information for creating a System message.
|
66
|
-
instruction: Information for creating an Instruction message.
|
67
|
-
context: Context information for the message.
|
68
|
-
response: Response data for creating a message.
|
69
|
-
**kwargs: Additional keyword arguments for message creation.
|
70
|
-
"""
|
71
|
-
_msg = MessageUtil.create_message(
|
72
|
-
system=system,
|
73
|
-
instruction=instruction,
|
74
|
-
context=context,
|
75
|
-
response=response,
|
76
|
-
output_fields=output_fields,
|
77
|
-
recipient=recipient,
|
78
|
-
**kwargs,
|
79
|
-
)
|
80
|
-
|
81
|
-
if isinstance(_msg, System):
|
82
|
-
self.system_node = _msg
|
83
|
-
|
84
|
-
# sourcery skip: merge-nested-ifs
|
85
|
-
if isinstance(_msg, Instruction):
|
86
|
-
if recipient is None and self.name is not None:
|
87
|
-
_msg.recipient = self.name
|
88
|
-
|
89
|
-
if isinstance(_msg, Response):
|
90
|
-
if "action_response" in _msg.content.keys():
|
91
|
-
if recipient is None and self.name is not None:
|
92
|
-
_msg.recipient = self.name
|
93
|
-
if recipient is not None and self.name is None:
|
94
|
-
_msg.recipient = recipient
|
95
|
-
if "response" in _msg.content.keys():
|
96
|
-
if self.name is not None:
|
97
|
-
_msg.sender = self.name
|
98
|
-
|
99
|
-
setattr(_msg, "node_id", _msg.id_)
|
100
|
-
_msg.content = _msg.msg_content
|
101
|
-
self.messages.loc[len(self.messages)] = _msg.to_pd_series()
|
102
|
-
|
103
|
-
def _to_chatcompletion_message(
|
104
|
-
self, with_sender: bool = False
|
105
|
-
) -> list[dict[str, Any]]:
|
106
|
-
"""
|
107
|
-
Converts messages to a list of dictionaries formatted for chat completion,
|
108
|
-
optionally including sender information.
|
109
|
-
|
110
|
-
Args:
|
111
|
-
with_sender: Flag to include sender information in the output.
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
A list of message dictionaries, each with 'role' and 'content' keys,
|
115
|
-
and optionally prefixed by 'Sender' if with_sender is True.
|
116
|
-
"""
|
117
|
-
|
118
|
-
message = []
|
119
|
-
|
120
|
-
for _, row in self.messages.iterrows():
|
121
|
-
content_ = row["content"]
|
122
|
-
if content_.startswith("Sender"):
|
123
|
-
content_ = content_.split(":", 1)[1]
|
124
|
-
|
125
|
-
# if isinstance(content_, str):
|
126
|
-
# try:
|
127
|
-
# content_ = json.dumps(to_dict(content_))
|
128
|
-
# except Exception as e:
|
129
|
-
# raise ValueError(
|
130
|
-
# f"Error in serializing, {row['node_id']} {content_}: {e}"
|
131
|
-
# )
|
132
|
-
|
133
|
-
out = {"role": row["role"], "content": content_}
|
134
|
-
if with_sender:
|
135
|
-
out["content"] = f"Sender {row['sender']}: {content_}"
|
136
|
-
|
137
|
-
message.append(out)
|
138
|
-
return message
|
139
|
-
|
140
|
-
@property
|
141
|
-
def chat_messages(self) -> list[dict[str, Any]]:
|
142
|
-
"""
|
143
|
-
Retrieves all chat messages without sender information.
|
144
|
-
|
145
|
-
Returns:
|
146
|
-
A list of dictionaries representing chat messages.
|
147
|
-
"""
|
148
|
-
|
149
|
-
return self._to_chatcompletion_message()
|
150
|
-
|
151
|
-
@property
|
152
|
-
def chat_messages_with_sender(self) -> list[dict[str, Any]]:
|
153
|
-
"""
|
154
|
-
Retrieves all chat messages, including sender information.
|
155
|
-
|
156
|
-
Returns:
|
157
|
-
A list of dictionaries representing chat messages, each prefixed with its sender.
|
158
|
-
"""
|
159
|
-
|
160
|
-
return self._to_chatcompletion_message(with_sender=True)
|
161
|
-
|
162
|
-
@property
|
163
|
-
def last_message(self) -> dataframe.ln_DataFrame:
|
164
|
-
"""
|
165
|
-
Retrieves the last message from the branch as a pandas Series.
|
166
|
-
|
167
|
-
Returns:
|
168
|
-
A pandas Series representing the last message in the branch.
|
169
|
-
"""
|
170
|
-
|
171
|
-
return MessageUtil.get_message_rows(self.messages, n=1, from_="last")
|
172
|
-
|
173
|
-
@property
|
174
|
-
def last_message_content(self) -> dict[str, Any]:
|
175
|
-
"""
|
176
|
-
Extracts the content of the last message in the branch.
|
177
|
-
|
178
|
-
Returns:
|
179
|
-
A dictionary representing the content of the last message.
|
180
|
-
"""
|
181
|
-
|
182
|
-
return convert.to_dict(self.messages.content.iloc[-1])
|
183
|
-
|
184
|
-
@property
|
185
|
-
def first_system(self) -> dataframe.ln_DataFrame:
|
186
|
-
"""
|
187
|
-
Retrieves the first message marked with the 'system' role.
|
188
|
-
|
189
|
-
Returns:
|
190
|
-
A pandas Series representing the first 'system' message in the branch.
|
191
|
-
"""
|
192
|
-
|
193
|
-
return MessageUtil.get_message_rows(
|
194
|
-
self.messages, role="system", n=1, from_="front"
|
195
|
-
)
|
196
|
-
|
197
|
-
@property
|
198
|
-
def last_response(self) -> dataframe.ln_DataFrame:
|
199
|
-
"""
|
200
|
-
Retrieves the last message marked with the 'assistant' role.
|
201
|
-
|
202
|
-
Returns:
|
203
|
-
A pandas Series representing the last 'assistant' (response) message in the branch.
|
204
|
-
"""
|
205
|
-
|
206
|
-
return MessageUtil.get_message_rows(
|
207
|
-
self.messages, role="assistant", n=1, from_="last"
|
208
|
-
)
|
209
|
-
|
210
|
-
@property
|
211
|
-
def last_response_content(self) -> dict[str, Any]:
|
212
|
-
"""
|
213
|
-
Extracts the content of the last 'assistant' (response) message.
|
214
|
-
|
215
|
-
Returns:
|
216
|
-
A dictionary representing the content of the last 'assistant' message.
|
217
|
-
"""
|
218
|
-
|
219
|
-
return convert.to_dict(self.last_response.content.iloc[-1])
|
220
|
-
|
221
|
-
@property
|
222
|
-
def action_request(self) -> dataframe.ln_DataFrame:
|
223
|
-
"""
|
224
|
-
Filters and retrieves all messages sent by 'action_request'.
|
225
|
-
|
226
|
-
Returns:
|
227
|
-
A pandas DataFrame containing all 'action_request' messages.
|
228
|
-
"""
|
229
|
-
|
230
|
-
return convert.to_df(self.messages[self.messages.sender == "action_request"])
|
231
|
-
|
232
|
-
@property
|
233
|
-
def action_response(self) -> dataframe.ln_DataFrame:
|
234
|
-
"""
|
235
|
-
Filters and retrieves all messages sent by 'action_response'.
|
236
|
-
|
237
|
-
Returns:
|
238
|
-
A pandas DataFrame containing all 'action_response' messages.
|
239
|
-
"""
|
240
|
-
|
241
|
-
return convert.to_df(self.messages[self.messages.sender == "action_response"])
|
242
|
-
|
243
|
-
@property
|
244
|
-
def responses(self) -> dataframe.ln_DataFrame:
|
245
|
-
"""
|
246
|
-
Retrieves all messages marked with the 'assistant' role.
|
247
|
-
|
248
|
-
Returns:
|
249
|
-
A pandas DataFrame containing all messages with an 'assistant' role.
|
250
|
-
"""
|
251
|
-
|
252
|
-
return convert.to_df(self.messages[self.messages.role == "assistant"])
|
253
|
-
|
254
|
-
@property
|
255
|
-
def assistant_responses(self) -> dataframe.ln_DataFrame:
|
256
|
-
"""
|
257
|
-
Filters 'assistant' role messages excluding 'action_request' and 'action_response'.
|
258
|
-
|
259
|
-
Returns:
|
260
|
-
A pandas DataFrame of 'assistant' messages excluding action requests/responses.
|
261
|
-
"""
|
262
|
-
|
263
|
-
a_responses = self.responses[self.responses.sender != "action_response"]
|
264
|
-
a_responses = a_responses[a_responses.sender != "action_request"]
|
265
|
-
return convert.to_df(a_responses)
|
266
|
-
|
267
|
-
@property
|
268
|
-
def last_assistant_response(self):
|
269
|
-
return self.assistant_responses.iloc[-1]
|
270
|
-
|
271
|
-
@property
|
272
|
-
def info(self) -> dict[str, Any]:
|
273
|
-
"""
|
274
|
-
Summarizes branch information, including message counts by role.
|
275
|
-
|
276
|
-
Returns:
|
277
|
-
A dictionary containing counts of messages categorized by their role.
|
278
|
-
"""
|
279
|
-
|
280
|
-
return self._info()
|
281
|
-
|
282
|
-
@property
|
283
|
-
def sender_info(self) -> dict[str, int]:
|
284
|
-
"""
|
285
|
-
Provides a summary of message counts categorized by sender.
|
286
|
-
|
287
|
-
Returns:
|
288
|
-
A dictionary with senders as keys and counts of their messages as values.
|
289
|
-
"""
|
290
|
-
|
291
|
-
return self._info(use_sender=True)
|
292
|
-
|
293
|
-
@property
|
294
|
-
def describe(self) -> dict[str, Any]:
|
295
|
-
"""
|
296
|
-
Provides a detailed description of the branch, including a summary of messages.
|
297
|
-
|
298
|
-
Returns:
|
299
|
-
A dictionary with a summary of total messages, a breakdown by role, and
|
300
|
-
a preview of the first five messages.
|
301
|
-
"""
|
302
|
-
|
303
|
-
return {
|
304
|
-
"total_messages": len(self.messages),
|
305
|
-
"summary_by_role": self._info(),
|
306
|
-
"messages": [msg.to_dict() for _, msg in self.messages.iterrows()][
|
307
|
-
: len(self.messages) - 1 if len(self.messages) < 5 else 5
|
308
|
-
],
|
309
|
-
}
|
310
|
-
|
311
|
-
@classmethod
|
312
|
-
def _from_csv(cls, filename: str, read_kwargs=None, **kwargs) -> "BaseBranch":
|
313
|
-
read_kwargs = {} if read_kwargs is None else read_kwargs
|
314
|
-
messages = dataframe.read_csv(filename, **read_kwargs)
|
315
|
-
return cls(messages=messages, **kwargs)
|
316
|
-
|
317
|
-
@classmethod
|
318
|
-
def from_csv(cls, **kwargs) -> "BaseBranch":
|
319
|
-
|
320
|
-
return cls._from_csv(**kwargs)
|
321
|
-
|
322
|
-
@classmethod
|
323
|
-
def from_json_string(cls, **kwargs) -> "BaseBranch":
|
324
|
-
|
325
|
-
return cls._from_json(**kwargs)
|
326
|
-
|
327
|
-
@classmethod
|
328
|
-
def _from_json(cls, filename: str, read_kwargs=None, **kwargs) -> "BaseBranch":
|
329
|
-
read_kwargs = {} if read_kwargs is None else read_kwargs
|
330
|
-
messages = dataframe.read_json(filename, **read_kwargs)
|
331
|
-
return cls(messages=messages, **kwargs)
|
332
|
-
|
333
|
-
def to_csv_file(
|
334
|
-
self,
|
335
|
-
filename: str | Path = "messages.csv",
|
336
|
-
dir_exist_ok: bool = True,
|
337
|
-
timestamp: bool = True,
|
338
|
-
time_prefix: bool = False,
|
339
|
-
verbose: bool = True,
|
340
|
-
clear: bool = True,
|
341
|
-
**kwargs,
|
342
|
-
) -> None:
|
343
|
-
"""
|
344
|
-
Exports the branch messages to a CSV file.
|
345
|
-
|
346
|
-
Args:
|
347
|
-
filepath: Destination path for the CSV file. Defaults to 'messages.csv'.
|
348
|
-
dir_exist_ok: If False, an error is raised if the directory exists. Defaults to True.
|
349
|
-
timestamp: If True, appends a timestamp to the filename. Defaults to True.
|
350
|
-
time_prefix: If True, prefixes the filename with a timestamp. Defaults to False.
|
351
|
-
verbose: If True, prints a message upon successful export. Defaults to True.
|
352
|
-
clear: If True, clears the messages after exporting. Defaults to True.
|
353
|
-
**kwargs: Additional keyword arguments for pandas.DataFrame.to_csv().
|
354
|
-
"""
|
355
|
-
|
356
|
-
if not filename.endswith(".csv"):
|
357
|
-
filename += ".csv"
|
358
|
-
|
359
|
-
filename = SysUtil.create_path(
|
360
|
-
self.datalogger.persist_path,
|
361
|
-
filename,
|
362
|
-
timestamp=timestamp,
|
363
|
-
dir_exist_ok=dir_exist_ok,
|
364
|
-
time_prefix=time_prefix,
|
365
|
-
)
|
366
|
-
|
367
|
-
try:
|
368
|
-
self.messages.to_csv(filename, **kwargs)
|
369
|
-
if verbose:
|
370
|
-
print(f"{len(self.messages)} messages saved to {filename}")
|
371
|
-
if clear:
|
372
|
-
self.clear_messages()
|
373
|
-
except Exception as e:
|
374
|
-
raise ValueError(f"Error in saving to csv: {e}") from e
|
375
|
-
|
376
|
-
def to_json_file(
|
377
|
-
self,
|
378
|
-
filename: str | Path = "messages.json",
|
379
|
-
dir_exist_ok: bool = True,
|
380
|
-
timestamp: bool = True,
|
381
|
-
time_prefix: bool = False,
|
382
|
-
verbose: bool = True,
|
383
|
-
clear: bool = True,
|
384
|
-
**kwargs,
|
385
|
-
) -> None:
|
386
|
-
"""
|
387
|
-
Exports the branch messages to a JSON file.
|
388
|
-
|
389
|
-
Args:
|
390
|
-
filename: Destination path for the JSON file. Defaults to 'messages.json'.
|
391
|
-
dir_exist_ok: If False, an error is raised if the dirctory exists. Defaults to True.
|
392
|
-
timestamp: If True, appends a timestamp to the filename. Defaults to True.
|
393
|
-
time_prefix: If True, prefixes the filename with a timestamp. Defaults to False.
|
394
|
-
verbose: If True, prints a message upon successful export. Defaults to True.
|
395
|
-
clear: If True, clears the messages after exporting. Defaults to True.
|
396
|
-
**kwargs: Additional keyword arguments for pandas.DataFrame.to_json().
|
397
|
-
"""
|
398
|
-
|
399
|
-
if not filename.endswith(".json"):
|
400
|
-
filename += ".json"
|
401
|
-
|
402
|
-
filename = SysUtil.create_path(
|
403
|
-
self.datalogger.persist_path,
|
404
|
-
filename,
|
405
|
-
timestamp=timestamp,
|
406
|
-
dir_exist_ok=dir_exist_ok,
|
407
|
-
time_prefix=time_prefix,
|
408
|
-
)
|
409
|
-
|
410
|
-
try:
|
411
|
-
self.messages.to_json(
|
412
|
-
filename, orient="records", lines=True, date_format="iso", **kwargs
|
413
|
-
)
|
414
|
-
if verbose:
|
415
|
-
print(f"{len(self.messages)} messages saved to {filename}")
|
416
|
-
if clear:
|
417
|
-
self.clear_messages()
|
418
|
-
except Exception as e:
|
419
|
-
raise ValueError(f"Error in saving to json: {e}") from e
|
420
|
-
|
421
|
-
def log_to_csv(
|
422
|
-
self,
|
423
|
-
filename: str | Path = "log.csv",
|
424
|
-
dir_exist_ok: bool = True,
|
425
|
-
timestamp: bool = True,
|
426
|
-
time_prefix: bool = False,
|
427
|
-
verbose: bool = True,
|
428
|
-
clear: bool = True,
|
429
|
-
flatten_=True,
|
430
|
-
sep="[^_^]",
|
431
|
-
**kwargs,
|
432
|
-
) -> None:
|
433
|
-
"""
|
434
|
-
Exports the data logger contents to a CSV file.
|
435
|
-
|
436
|
-
Args:
|
437
|
-
filename: Destination path for the CSV file. Defaults to 'log.csv'.
|
438
|
-
dir_exist_ok: If False, an error is raised if the directory exists. Defaults to True.
|
439
|
-
timestamp: If True, appends a timestamp to the filename. Defaults to True.
|
440
|
-
time_prefix: If True, prefixes the filename with a timestamp. Defaults to False.
|
441
|
-
verbose: If True, prints a message upon successful export. Defaults to True.
|
442
|
-
clear: If True, clears the logger after exporting. Defaults to True.
|
443
|
-
**kwargs: Additional keyword arguments for pandas.DataFrame.to_csv().
|
444
|
-
"""
|
445
|
-
self.datalogger.to_csv_file(
|
446
|
-
filename=filename,
|
447
|
-
dir_exist_ok=dir_exist_ok,
|
448
|
-
timestamp=timestamp,
|
449
|
-
time_prefix=time_prefix,
|
450
|
-
verbose=verbose,
|
451
|
-
clear=clear,
|
452
|
-
flatten_=flatten_,
|
453
|
-
sep=sep,
|
454
|
-
**kwargs,
|
455
|
-
)
|
456
|
-
|
457
|
-
def log_to_json(
|
458
|
-
self,
|
459
|
-
filename: str | Path = "log.json",
|
460
|
-
dir_exist_ok: bool = True,
|
461
|
-
timestamp: bool = True,
|
462
|
-
time_prefix: bool = False,
|
463
|
-
verbose: bool = True,
|
464
|
-
clear: bool = True,
|
465
|
-
flatten_=True,
|
466
|
-
sep="[^_^]",
|
467
|
-
**kwargs,
|
468
|
-
) -> None:
|
469
|
-
"""
|
470
|
-
Exports the data logger contents to a JSON file.
|
471
|
-
|
472
|
-
Args:
|
473
|
-
filename: Destination path for the JSON file. Defaults to 'log.json'.
|
474
|
-
dir_exist_ok: If False, an error is raised if the directory exists. Defaults to True.
|
475
|
-
timestamp: If True, appends a timestamp to the filename. Defaults to True.
|
476
|
-
time_prefix: If True, prefixes the filename with a timestamp. Defaults to False.
|
477
|
-
verbose: If True, prints a message upon successful export. Defaults to True.
|
478
|
-
clear: If True, clears the logger after exporting. Defaults to True.
|
479
|
-
**kwargs: Additional keyword arguments for pandas.DataFrame.to_json().
|
480
|
-
"""
|
481
|
-
|
482
|
-
self.datalogger.to_json_file(
|
483
|
-
filename=filename,
|
484
|
-
dir_exist_ok=dir_exist_ok,
|
485
|
-
timestamp=timestamp,
|
486
|
-
time_prefix=time_prefix,
|
487
|
-
verbose=verbose,
|
488
|
-
clear=clear,
|
489
|
-
flatten_=flatten_,
|
490
|
-
sep=sep,
|
491
|
-
**kwargs,
|
492
|
-
)
|
493
|
-
|
494
|
-
def load_log(self, filename, flattened=True, sep="[^_^]", verbose=True, **kwargs):
|
495
|
-
df = ""
|
496
|
-
try:
|
497
|
-
if filename.endswith(".csv"):
|
498
|
-
df = dataframe.read_csv(filename, **kwargs)
|
499
|
-
|
500
|
-
elif filename.endswith(".json"):
|
501
|
-
df = dataframe.read_json(filename, **kwargs)
|
502
|
-
|
503
|
-
for _, row in df.iterrows():
|
504
|
-
self.datalogger.log.append(
|
505
|
-
DLog.deserialize(
|
506
|
-
input_str=row.input_data,
|
507
|
-
output_str=row.output_data,
|
508
|
-
unflatten_=flattened,
|
509
|
-
sep=sep,
|
510
|
-
)
|
511
|
-
)
|
512
|
-
|
513
|
-
if verbose:
|
514
|
-
print(f"Loaded {len(df)} logs from {filename}")
|
515
|
-
except Exception as e:
|
516
|
-
raise ValueError(f"Error in loading log: {e}") from e
|
517
|
-
|
518
|
-
def remove_message(self, node_id: str) -> None:
|
519
|
-
"""
|
520
|
-
Removes a message from the branch based on its node ID.
|
521
|
-
|
522
|
-
Args:
|
523
|
-
node_id: The unique identifier of the message to be removed.
|
524
|
-
"""
|
525
|
-
MessageUtil.remove_message(self.messages, node_id)
|
526
|
-
|
527
|
-
def update_message(self, node_id: str, column: str, value: Any) -> bool:
|
528
|
-
"""
|
529
|
-
Updates a specific column of a message identified by node_id with a new value.
|
530
|
-
|
531
|
-
Args:
|
532
|
-
value: The new value to update the message with.
|
533
|
-
node_id: The unique identifier of the message to update.
|
534
|
-
column: The column of the message to update.
|
535
|
-
"""
|
536
|
-
|
537
|
-
index = self.messages[self.messages["node_id"] == node_id].index[0]
|
538
|
-
|
539
|
-
return dataframe.update_row(
|
540
|
-
self.messages, row=index, column=column, value=value
|
541
|
-
)
|
542
|
-
|
543
|
-
def change_first_system_message(
|
544
|
-
self, system: str | dict[str, Any] | System, sender: str | None = None
|
545
|
-
) -> None:
|
546
|
-
"""
|
547
|
-
Updates the first system message with new content and/or sender.
|
548
|
-
|
549
|
-
Args:
|
550
|
-
system: The new system message content or a System object.
|
551
|
-
sender: The identifier of the sender for the system message.
|
552
|
-
"""
|
553
|
-
|
554
|
-
if len(self.messages[self.messages["role"] == "system"]) == 0:
|
555
|
-
raise ValueError("There is no system message in the messages.")
|
556
|
-
|
557
|
-
if not isinstance(system, (str, dict, System)):
|
558
|
-
raise ValueError("Input cannot be converted into a system message.")
|
559
|
-
|
560
|
-
if isinstance(system, (str, dict)):
|
561
|
-
system = System(system, sender=sender)
|
562
|
-
|
563
|
-
if isinstance(system, System):
|
564
|
-
system.timestamp = SysUtil.get_timestamp()
|
565
|
-
sys_index = self.messages[self.messages.role == "system"].index
|
566
|
-
self.messages.loc[sys_index[0]] = system.to_pd_series()
|
567
|
-
|
568
|
-
def rollback(self, steps: int) -> None:
|
569
|
-
"""
|
570
|
-
Removes the last 'n' messages from the branch.
|
571
|
-
|
572
|
-
Args:
|
573
|
-
steps: The number of messages to remove from the end.
|
574
|
-
"""
|
575
|
-
|
576
|
-
self.messages = dataframe.remove_last_n_rows(self.messages, steps)
|
577
|
-
|
578
|
-
def clear_messages(self) -> None:
|
579
|
-
"""
|
580
|
-
Clears all messages from the branch.
|
581
|
-
"""
|
582
|
-
self.messages = dataframe.ln_DataFrame(columns=self._columns)
|
583
|
-
|
584
|
-
def replace_keyword(
|
585
|
-
self,
|
586
|
-
keyword: str,
|
587
|
-
replacement: str,
|
588
|
-
column: str = "content",
|
589
|
-
case_sensitive: bool = False,
|
590
|
-
) -> None:
|
591
|
-
|
592
|
-
dataframe.replace_keyword(
|
593
|
-
self.messages,
|
594
|
-
keyword,
|
595
|
-
replacement,
|
596
|
-
column=column,
|
597
|
-
case_sensitive=case_sensitive,
|
598
|
-
)
|
599
|
-
|
600
|
-
def search_keywords(
|
601
|
-
self,
|
602
|
-
keywords: str | list[str],
|
603
|
-
case_sensitive: bool = False,
|
604
|
-
reset_index: bool = False,
|
605
|
-
dropna: bool = False,
|
606
|
-
) -> dataframe.ln_DataFrame:
|
607
|
-
return dataframe.search_keywords(
|
608
|
-
self.messages,
|
609
|
-
keywords,
|
610
|
-
case_sensitive=case_sensitive,
|
611
|
-
reset_index=reset_index,
|
612
|
-
dropna=dropna,
|
613
|
-
)
|
614
|
-
|
615
|
-
def extend(self, messages: dataframe.ln_DataFrame, **kwargs) -> None:
|
616
|
-
|
617
|
-
self.messages = MessageUtil.extend(self.messages, messages, **kwargs)
|
618
|
-
|
619
|
-
def filter_by(
|
620
|
-
self,
|
621
|
-
role: str | None = None,
|
622
|
-
sender: str | None = None,
|
623
|
-
start_time=None,
|
624
|
-
end_time=None,
|
625
|
-
content_keywords: str | list[str] | None = None,
|
626
|
-
case_sensitive: bool = False,
|
627
|
-
) -> dataframe.ln_DataFrame:
|
628
|
-
|
629
|
-
return MessageUtil.filter_messages_by(
|
630
|
-
self.messages,
|
631
|
-
role=role,
|
632
|
-
sender=sender,
|
633
|
-
start_time=start_time,
|
634
|
-
end_time=end_time,
|
635
|
-
content_keywords=content_keywords,
|
636
|
-
case_sensitive=case_sensitive,
|
637
|
-
)
|
638
|
-
|
639
|
-
def _info(self, use_sender: bool = False) -> dict[str, int]:
|
640
|
-
"""
|
641
|
-
Helper method to generate summaries of messages either by role or sender.
|
642
|
-
|
643
|
-
Args:
|
644
|
-
use_sender: If True, summary is categorized by sender. Otherwise, by role.
|
645
|
-
|
646
|
-
Returns:
|
647
|
-
A dictionary summarizing the count of messages either by role or sender.
|
648
|
-
"""
|
649
|
-
|
650
|
-
messages = self.messages["sender"] if use_sender else self.messages["role"]
|
651
|
-
result = messages.value_counts().to_dict()
|
652
|
-
result["total"] = len(self.messages)
|
653
|
-
return result
|