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
@@ -0,0 +1,95 @@
|
|
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 .message import RoledMessage, MessageRole
|
19
|
+
|
20
|
+
|
21
|
+
class AssistantResponse(RoledMessage):
|
22
|
+
"""
|
23
|
+
Represents a response generated by an assistant.
|
24
|
+
|
25
|
+
Inherits from `RoledMessage` and provides attributes specific to assistant responses.
|
26
|
+
|
27
|
+
Attributes:
|
28
|
+
assistant_response (Any): The content of the assistant's response.
|
29
|
+
sender (str): The sender of the response.
|
30
|
+
recipient (str): The recipient of the response.
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
assistant_response: Any = None,
|
36
|
+
sender: str | None = None,
|
37
|
+
recipient: str | None = None,
|
38
|
+
**kwargs,
|
39
|
+
):
|
40
|
+
"""
|
41
|
+
Initializes the AssistantResponse.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
assistant_response (Any, optional): The content of the assistant's response.
|
45
|
+
sender (str, optional): The sender of the response.
|
46
|
+
recipient (str, optional): The recipient of the response.
|
47
|
+
**kwargs: Additional keyword arguments to be passed to the parent class.
|
48
|
+
"""
|
49
|
+
|
50
|
+
super().__init__(
|
51
|
+
role=MessageRole.ASSISTANT,
|
52
|
+
sender=sender or "N/A",
|
53
|
+
content={"assistant_response": assistant_response["content"]},
|
54
|
+
recipient=recipient,
|
55
|
+
**kwargs,
|
56
|
+
)
|
57
|
+
|
58
|
+
def clone(self, **kwargs):
|
59
|
+
"""
|
60
|
+
Creates a copy of the current AssistantResponse object with optional additional arguments.
|
61
|
+
|
62
|
+
This method clones the current object, preserving its content.
|
63
|
+
It also retains the original metadata, while allowing
|
64
|
+
for the addition of new attributes through keyword arguments.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
**kwargs: Optional keyword arguments to be included in the cloned object.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
AssistantResponse: A new instance of the object with the same content and additional keyword arguments.
|
71
|
+
"""
|
72
|
+
import json
|
73
|
+
|
74
|
+
content = json.dumps(self.content["assistant_response"])
|
75
|
+
content = {"content": json.loads(content)}
|
76
|
+
response_copy = AssistantResponse(assistant_response=content, **kwargs)
|
77
|
+
response_copy.metadata["origin_ln_id"] = self.ln_id
|
78
|
+
return response_copy
|
79
|
+
|
80
|
+
@property
|
81
|
+
def chat_msg(self) -> dict | None:
|
82
|
+
"""Return message in chat representation."""
|
83
|
+
try:
|
84
|
+
return self._check_chat_msg()
|
85
|
+
except:
|
86
|
+
return None
|
87
|
+
|
88
|
+
def _check_chat_msg(self):
|
89
|
+
text_msg = super()._check_chat_msg()
|
90
|
+
return text_msg
|
91
|
+
|
92
|
+
@property
|
93
|
+
def response(self):
|
94
|
+
"""Return the assistant response content."""
|
95
|
+
return self.content["assistant_response"]
|
@@ -0,0 +1,234 @@
|
|
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 lionagi.core.collections.abc import LionIDable, SYSTEM_FIELDS
|
18
|
+
from lionagi.core.report.form import Form
|
19
|
+
from lionagi.core.message.message import RoledMessage, MessageRole
|
20
|
+
|
21
|
+
|
22
|
+
class Instruction(RoledMessage):
|
23
|
+
"""
|
24
|
+
Represents an instruction message with additional context and requested fields.
|
25
|
+
|
26
|
+
Inherits from `RoledMessage` and provides methods to manage context and
|
27
|
+
requested fields specific to instructions.
|
28
|
+
|
29
|
+
Attributes:
|
30
|
+
instruction (str): The instruction content.
|
31
|
+
context (dict or str): Additional context for the instruction.
|
32
|
+
sender (LionIDable): The sender of the instruction.
|
33
|
+
recipient (LionIDable): The recipient of the instruction.
|
34
|
+
requested_fields (dict): Fields requested in the instruction.
|
35
|
+
"""
|
36
|
+
|
37
|
+
def __init__(
|
38
|
+
self,
|
39
|
+
instruction: str | None = None,
|
40
|
+
context: dict | str | None = None,
|
41
|
+
images: list | None = None,
|
42
|
+
sender: LionIDable | None = None,
|
43
|
+
recipient: LionIDable | None = None,
|
44
|
+
requested_fields: dict | None = None, # {"field": "description"}
|
45
|
+
additional_context: dict | None = None,
|
46
|
+
image_detail: str | None = None,
|
47
|
+
**kwargs,
|
48
|
+
):
|
49
|
+
"""
|
50
|
+
Initializes the Instruction message.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
instruction (str, optional): The instruction content.
|
54
|
+
context (dict or str, optional): Additional context for the instruction.
|
55
|
+
image (str, optional): The image content in base64 encoding.
|
56
|
+
sender (LionIDable, optional): The sender of the instruction.
|
57
|
+
recipient (LionIDable, optional): The recipient of the instruction.
|
58
|
+
requested_fields (dict, optional): Fields requested in the instruction.
|
59
|
+
**kwargs: Additional context fields to be added to the message content, must be JSON serializable.
|
60
|
+
"""
|
61
|
+
if not instruction:
|
62
|
+
if "metadata" in kwargs and "instruction" in kwargs["metadata"]:
|
63
|
+
instruction = kwargs["metadata"].pop("instruction")
|
64
|
+
|
65
|
+
super().__init__(
|
66
|
+
role=MessageRole.USER,
|
67
|
+
sender=sender or "user",
|
68
|
+
content={"instruction": instruction or "N/A"},
|
69
|
+
recipient=recipient or "N/A",
|
70
|
+
**kwargs,
|
71
|
+
)
|
72
|
+
|
73
|
+
additional_context = additional_context or {}
|
74
|
+
self._initiate_content(
|
75
|
+
context=context,
|
76
|
+
requested_fields=requested_fields,
|
77
|
+
images=images,
|
78
|
+
image_detail=image_detail or "low",
|
79
|
+
**additional_context,
|
80
|
+
)
|
81
|
+
|
82
|
+
@property
|
83
|
+
def instruct(self):
|
84
|
+
"""Returns the instruction content."""
|
85
|
+
return self.content["instruction"]
|
86
|
+
|
87
|
+
def _check_chat_msg(self):
|
88
|
+
text_msg = super()._check_chat_msg()
|
89
|
+
if "images" not in self.content:
|
90
|
+
return text_msg
|
91
|
+
|
92
|
+
text_msg["content"].pop("images", None)
|
93
|
+
text_msg["content"].pop("image_detail", None)
|
94
|
+
text_msg["content"] = [
|
95
|
+
{"type": "text", "text": text_msg["content"]},
|
96
|
+
]
|
97
|
+
|
98
|
+
for i in self.content["images"]:
|
99
|
+
text_msg["content"].append(
|
100
|
+
{
|
101
|
+
"type": "image_url",
|
102
|
+
"image_url": {
|
103
|
+
"url": f"data:image/jpeg;base64,{i}",
|
104
|
+
"detail": self.content["image_detail"],
|
105
|
+
},
|
106
|
+
}
|
107
|
+
)
|
108
|
+
return text_msg
|
109
|
+
|
110
|
+
def _add_context(self, context: dict | str | None = None, **kwargs):
|
111
|
+
"""
|
112
|
+
Adds context to the instruction message.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
context (dict or str, optional): Additional context to be added.
|
116
|
+
**kwargs: Additional context fields to be added.
|
117
|
+
"""
|
118
|
+
if "context" not in self.content:
|
119
|
+
self.content["context"] = {}
|
120
|
+
if isinstance(context, dict):
|
121
|
+
self.content["context"].update({**context, **kwargs})
|
122
|
+
elif isinstance(context, str):
|
123
|
+
self.content["context"]["additional_context"] = context
|
124
|
+
|
125
|
+
def _update_requested_fields(self, requested_fields: dict):
|
126
|
+
"""
|
127
|
+
Updates the requested fields in the instruction message.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
requested_fields (dict): The fields requested in the instruction.
|
131
|
+
"""
|
132
|
+
if "context" not in self.content:
|
133
|
+
self.content["context"] = {}
|
134
|
+
self.content["context"]["requested_fields"] = {}
|
135
|
+
self.content["context"]["requested_fields"].update(requested_fields)
|
136
|
+
|
137
|
+
def _initiate_content(
|
138
|
+
self, context, requested_fields, images, image_detail, **kwargs
|
139
|
+
):
|
140
|
+
"""
|
141
|
+
Processes context and requested fields to update the message content.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
context (dict or str, optional): Additional context for the instruction.
|
145
|
+
requested_fields (dict, optional): Fields requested in the instruction.
|
146
|
+
**kwargs: Additional context fields to be added.
|
147
|
+
"""
|
148
|
+
if context:
|
149
|
+
context = {"context": context} if not isinstance(context, dict) else context
|
150
|
+
if (
|
151
|
+
additional_context := {
|
152
|
+
k: v for k, v in kwargs.items() if k not in SYSTEM_FIELDS
|
153
|
+
}
|
154
|
+
) != {}:
|
155
|
+
context["additional_context"] = additional_context
|
156
|
+
self.content.update(context)
|
157
|
+
|
158
|
+
if not requested_fields in [None, {}]:
|
159
|
+
self.content["requested_fields"] = self._format_requested_fields(
|
160
|
+
requested_fields
|
161
|
+
)
|
162
|
+
|
163
|
+
if images:
|
164
|
+
self.content["images"] = images if isinstance(images, list) else [images]
|
165
|
+
self.content["image_detail"] = image_detail
|
166
|
+
|
167
|
+
def clone(self, **kwargs):
|
168
|
+
"""
|
169
|
+
Creates a copy of the current Instruction object with optional additional arguments.
|
170
|
+
|
171
|
+
This method clones the current object, preserving its content.
|
172
|
+
It also retains the original metadata, while allowing
|
173
|
+
for the addition of new attributes through keyword arguments.
|
174
|
+
|
175
|
+
Args:
|
176
|
+
**kwargs: Optional keyword arguments to be included in the cloned object.
|
177
|
+
|
178
|
+
Returns:
|
179
|
+
Instruction: A new instance of the object with the same content and additional keyword arguments.
|
180
|
+
"""
|
181
|
+
import json
|
182
|
+
|
183
|
+
content = json.dumps(self.content)
|
184
|
+
instruction_copy = Instruction(**kwargs)
|
185
|
+
instruction_copy.content = json.loads(content)
|
186
|
+
instruction_copy.metadata["origin_ln_id"] = self.ln_id
|
187
|
+
return instruction_copy
|
188
|
+
|
189
|
+
@staticmethod
|
190
|
+
def _format_requested_fields(requested_fields):
|
191
|
+
"""
|
192
|
+
Formats the requested fields into a JSON-parseable response format.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
requested_fields (dict): The fields requested in the instruction.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
dict: The formatted requested fields.
|
199
|
+
"""
|
200
|
+
format_ = f"""
|
201
|
+
MUST RETURN JSON-PARSEABLE RESPONSE ENCLOSED BY JSON CODE BLOCKS. ----
|
202
|
+
```json
|
203
|
+
{requested_fields}
|
204
|
+
```---
|
205
|
+
"""
|
206
|
+
return {"response_format": format_.strip()}
|
207
|
+
|
208
|
+
@classmethod
|
209
|
+
def from_form(
|
210
|
+
cls,
|
211
|
+
form: Form,
|
212
|
+
sender: str | None = None,
|
213
|
+
recipient=None,
|
214
|
+
image=None,
|
215
|
+
):
|
216
|
+
"""
|
217
|
+
Creates an Instruction instance from a form.
|
218
|
+
|
219
|
+
Args:
|
220
|
+
form (Form): The form containing instruction details.
|
221
|
+
sender (str, optional): The sender of the instruction.
|
222
|
+
recipient (LionIDable, optional): The recipient of the instruction.
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
Instruction: The created Instruction instance.
|
226
|
+
"""
|
227
|
+
return cls(
|
228
|
+
instruction=form._instruction_prompt,
|
229
|
+
context=form._instruction_context,
|
230
|
+
requested_fields=form._instruction_requested_fields,
|
231
|
+
image=image,
|
232
|
+
sender=sender,
|
233
|
+
recipient=recipient,
|
234
|
+
)
|
@@ -0,0 +1,101 @@
|
|
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 enum import Enum
|
18
|
+
from lionagi.core.collections.abc import Sendable, Field
|
19
|
+
from lionagi.core.generic.node import Node
|
20
|
+
|
21
|
+
|
22
|
+
# Enums for defining message fields and roles
|
23
|
+
class MessageField(str, Enum):
|
24
|
+
"""
|
25
|
+
Enum to store message fields for consistent referencing.
|
26
|
+
"""
|
27
|
+
|
28
|
+
LION_ID = "lion_id"
|
29
|
+
TIMESTAMP = "timestamp"
|
30
|
+
ROLE = "role"
|
31
|
+
SENDER = "sender"
|
32
|
+
RECIPIENT = "recipient"
|
33
|
+
CONTENT = "content"
|
34
|
+
|
35
|
+
|
36
|
+
class MessageRole(str, Enum):
|
37
|
+
"""
|
38
|
+
Enum for possible roles a message can assume in a conversation.
|
39
|
+
"""
|
40
|
+
|
41
|
+
SYSTEM = "system"
|
42
|
+
USER = "user"
|
43
|
+
ASSISTANT = "assistant"
|
44
|
+
|
45
|
+
|
46
|
+
# Base class for messages
|
47
|
+
class RoledMessage(Node, Sendable):
|
48
|
+
"""
|
49
|
+
A base class representing a message with validators and properties.
|
50
|
+
"""
|
51
|
+
|
52
|
+
role: MessageRole | None = Field(
|
53
|
+
default=None,
|
54
|
+
description="The role of the message in the conversation.",
|
55
|
+
examples=["system", "user", "assistant"],
|
56
|
+
)
|
57
|
+
|
58
|
+
@property
|
59
|
+
def image_content(self):
|
60
|
+
msg_ = self.chat_msg
|
61
|
+
if isinstance(msg_, dict) and isinstance(msg_["content"], list):
|
62
|
+
return [i for i in msg_["content"] if i["type"] == "image_url"]
|
63
|
+
|
64
|
+
return None
|
65
|
+
|
66
|
+
@property
|
67
|
+
def chat_msg(self) -> dict | None:
|
68
|
+
"""return message in chat representation"""
|
69
|
+
try:
|
70
|
+
return self._check_chat_msg()
|
71
|
+
except:
|
72
|
+
return None
|
73
|
+
|
74
|
+
def _check_chat_msg(self):
|
75
|
+
if self.role is None:
|
76
|
+
raise ValueError("Message role not set")
|
77
|
+
|
78
|
+
role = self.role.value if isinstance(self.role, Enum) else self.role
|
79
|
+
if role not in [i.value for i in MessageRole]:
|
80
|
+
raise ValueError(f"Invalid message role: {role}")
|
81
|
+
|
82
|
+
content_dict = self.content.copy()
|
83
|
+
|
84
|
+
if not content_dict.get("images", None):
|
85
|
+
if len(content_dict) == 1:
|
86
|
+
content_dict = str(list(content_dict.values())[0])
|
87
|
+
else:
|
88
|
+
content_dict = str(content_dict)
|
89
|
+
|
90
|
+
return {"role": role, "content": content_dict}
|
91
|
+
|
92
|
+
def __str__(self):
|
93
|
+
"""
|
94
|
+
Provides a string representation of the message with content preview.
|
95
|
+
"""
|
96
|
+
content_preview = (
|
97
|
+
f"{str(self.content)[:75]}..."
|
98
|
+
if len(str(self.content)) > 75
|
99
|
+
else str(self.content)
|
100
|
+
)
|
101
|
+
return f"Message(role={self.role}, sender={self.sender}, content='{content_preview}')"
|
@@ -0,0 +1,86 @@
|
|
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 ..collections.abc import Field
|
19
|
+
from .message import RoledMessage, MessageRole
|
20
|
+
|
21
|
+
|
22
|
+
class System(RoledMessage):
|
23
|
+
"""
|
24
|
+
Represents a system message with system-related information.
|
25
|
+
|
26
|
+
Inherits from `RoledMessage` and provides methods to manage system-specific content.
|
27
|
+
|
28
|
+
Attributes:
|
29
|
+
system (str | Any | None): The system information.
|
30
|
+
"""
|
31
|
+
|
32
|
+
system: str | Any | None = Field(None)
|
33
|
+
|
34
|
+
def __init__(self, system=None, sender=None, recipient=None, **kwargs):
|
35
|
+
"""
|
36
|
+
Initializes the System message.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
system (str or Any, optional): The system information.
|
40
|
+
sender (str, optional): The sender of the message.
|
41
|
+
recipient (str, optional): The recipient of the message.
|
42
|
+
**kwargs: Additional fields to be added to the message content, must be JSON serializable.
|
43
|
+
"""
|
44
|
+
if not system:
|
45
|
+
if "metadata" in kwargs and "system" in kwargs["metadata"]:
|
46
|
+
system = kwargs["metadata"].pop("system")
|
47
|
+
|
48
|
+
super().__init__(
|
49
|
+
role=MessageRole.SYSTEM,
|
50
|
+
sender=sender or "system",
|
51
|
+
content={"system_info": system},
|
52
|
+
recipient=recipient or "N/A",
|
53
|
+
system=system,
|
54
|
+
**kwargs,
|
55
|
+
)
|
56
|
+
|
57
|
+
@property
|
58
|
+
def system_info(self):
|
59
|
+
"""
|
60
|
+
Retrieves the system information stored in the message content.
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
Any: The system information.
|
64
|
+
"""
|
65
|
+
return self.content["system_info"]
|
66
|
+
|
67
|
+
def clone(self, **kwargs):
|
68
|
+
"""
|
69
|
+
Creates a copy of the current System object with optional additional arguments.
|
70
|
+
|
71
|
+
This method clones the current object, preserving its content.
|
72
|
+
It also retains the original metadata, while allowing
|
73
|
+
for the addition of new attributes through keyword arguments.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
**kwargs: Optional keyword arguments to be included in the cloned object.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
System: A new instance of the object with the same content and additional keyword arguments.
|
80
|
+
"""
|
81
|
+
import json
|
82
|
+
|
83
|
+
system = json.dumps(self.system_info)
|
84
|
+
system_copy = System(system=json.loads(system), **kwargs)
|
85
|
+
system_copy.metadata["origin_ln_id"] = self.ln_id
|
86
|
+
return system_copy
|