lionagi 0.1.2__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.
Files changed (268) hide show
  1. lionagi/__init__.py +60 -5
  2. lionagi/core/__init__.py +0 -25
  3. lionagi/core/_setting/_setting.py +59 -0
  4. lionagi/core/action/__init__.py +14 -0
  5. lionagi/core/action/function_calling.py +136 -0
  6. lionagi/core/action/manual.py +1 -0
  7. lionagi/core/action/node.py +109 -0
  8. lionagi/core/action/tool.py +114 -0
  9. lionagi/core/action/tool_manager.py +356 -0
  10. lionagi/core/agent/base_agent.py +27 -13
  11. lionagi/core/agent/eval/evaluator.py +1 -0
  12. lionagi/core/agent/eval/vote.py +40 -0
  13. lionagi/core/agent/learn/learner.py +59 -0
  14. lionagi/core/agent/plan/unit_template.py +1 -0
  15. lionagi/core/collections/__init__.py +17 -0
  16. lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
  17. lionagi/core/collections/abc/__init__.py +53 -0
  18. lionagi/core/collections/abc/component.py +615 -0
  19. lionagi/core/collections/abc/concepts.py +297 -0
  20. lionagi/core/collections/abc/exceptions.py +150 -0
  21. lionagi/core/collections/abc/util.py +45 -0
  22. lionagi/core/collections/exchange.py +161 -0
  23. lionagi/core/collections/flow.py +426 -0
  24. lionagi/core/collections/model.py +419 -0
  25. lionagi/core/collections/pile.py +913 -0
  26. lionagi/core/collections/progression.py +236 -0
  27. lionagi/core/collections/util.py +64 -0
  28. lionagi/core/director/direct.py +314 -0
  29. lionagi/core/director/director.py +2 -0
  30. lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
  31. lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
  32. lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
  33. lionagi/core/executor/base_executor.py +90 -0
  34. lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
  35. lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
  36. lionagi/core/generic/__init__.py +3 -33
  37. lionagi/core/generic/edge.py +29 -79
  38. lionagi/core/generic/edge_condition.py +16 -0
  39. lionagi/core/generic/graph.py +236 -0
  40. lionagi/core/generic/hyperedge.py +1 -0
  41. lionagi/core/generic/node.py +156 -221
  42. lionagi/core/generic/tree.py +48 -0
  43. lionagi/core/generic/tree_node.py +79 -0
  44. lionagi/core/mail/__init__.py +12 -0
  45. lionagi/core/mail/mail.py +25 -0
  46. lionagi/core/mail/mail_manager.py +139 -58
  47. lionagi/core/mail/package.py +45 -0
  48. lionagi/core/mail/start_mail.py +36 -0
  49. lionagi/core/message/__init__.py +19 -0
  50. lionagi/core/message/action_request.py +133 -0
  51. lionagi/core/message/action_response.py +135 -0
  52. lionagi/core/message/assistant_response.py +95 -0
  53. lionagi/core/message/instruction.py +234 -0
  54. lionagi/core/message/message.py +101 -0
  55. lionagi/core/message/system.py +86 -0
  56. lionagi/core/message/util.py +283 -0
  57. lionagi/core/report/__init__.py +4 -0
  58. lionagi/core/report/base.py +217 -0
  59. lionagi/core/report/form.py +231 -0
  60. lionagi/core/report/report.py +166 -0
  61. lionagi/core/report/util.py +28 -0
  62. lionagi/core/rule/_default.py +16 -0
  63. lionagi/core/rule/action.py +99 -0
  64. lionagi/core/rule/base.py +238 -0
  65. lionagi/core/rule/boolean.py +56 -0
  66. lionagi/core/rule/choice.py +47 -0
  67. lionagi/core/rule/mapping.py +96 -0
  68. lionagi/core/rule/number.py +71 -0
  69. lionagi/core/rule/rulebook.py +109 -0
  70. lionagi/core/rule/string.py +52 -0
  71. lionagi/core/rule/util.py +35 -0
  72. lionagi/core/session/branch.py +431 -0
  73. lionagi/core/session/directive_mixin.py +287 -0
  74. lionagi/core/session/session.py +229 -903
  75. lionagi/core/structure/__init__.py +1 -0
  76. lionagi/core/structure/chain.py +1 -0
  77. lionagi/core/structure/forest.py +1 -0
  78. lionagi/core/structure/graph.py +1 -0
  79. lionagi/core/structure/tree.py +1 -0
  80. lionagi/core/unit/__init__.py +5 -0
  81. lionagi/core/unit/parallel_unit.py +245 -0
  82. lionagi/core/unit/template/action.py +81 -0
  83. lionagi/core/unit/template/base.py +51 -0
  84. lionagi/core/unit/template/plan.py +84 -0
  85. lionagi/core/unit/template/predict.py +109 -0
  86. lionagi/core/unit/template/score.py +124 -0
  87. lionagi/core/unit/template/select.py +104 -0
  88. lionagi/core/unit/unit.py +362 -0
  89. lionagi/core/unit/unit_form.py +305 -0
  90. lionagi/core/unit/unit_mixin.py +1168 -0
  91. lionagi/core/unit/util.py +71 -0
  92. lionagi/core/validator/validator.py +364 -0
  93. lionagi/core/work/work.py +76 -0
  94. lionagi/core/work/work_function.py +101 -0
  95. lionagi/core/work/work_queue.py +103 -0
  96. lionagi/core/work/worker.py +258 -0
  97. lionagi/core/work/worklog.py +120 -0
  98. lionagi/experimental/compressor/base.py +46 -0
  99. lionagi/experimental/compressor/llm_compressor.py +247 -0
  100. lionagi/experimental/compressor/llm_summarizer.py +61 -0
  101. lionagi/experimental/compressor/util.py +70 -0
  102. lionagi/experimental/directive/__init__.py +19 -0
  103. lionagi/experimental/directive/parser/base_parser.py +69 -2
  104. lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
  105. lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
  106. lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
  107. lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
  108. lionagi/experimental/knowledge/base.py +10 -0
  109. lionagi/experimental/memory/__init__.py +0 -0
  110. lionagi/experimental/strategies/__init__.py +0 -0
  111. lionagi/experimental/strategies/base.py +1 -0
  112. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  113. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  114. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  115. lionagi/integrations/chunker/chunk.py +161 -24
  116. lionagi/integrations/config/oai_configs.py +34 -3
  117. lionagi/integrations/config/openrouter_configs.py +14 -2
  118. lionagi/integrations/loader/load.py +122 -21
  119. lionagi/integrations/loader/load_util.py +6 -77
  120. lionagi/integrations/provider/_mapping.py +46 -0
  121. lionagi/integrations/provider/litellm.py +2 -1
  122. lionagi/integrations/provider/mlx_service.py +16 -9
  123. lionagi/integrations/provider/oai.py +91 -4
  124. lionagi/integrations/provider/ollama.py +6 -5
  125. lionagi/integrations/provider/openrouter.py +115 -8
  126. lionagi/integrations/provider/services.py +2 -2
  127. lionagi/integrations/provider/transformers.py +18 -22
  128. lionagi/integrations/storage/__init__.py +3 -3
  129. lionagi/integrations/storage/neo4j.py +52 -60
  130. lionagi/integrations/storage/storage_util.py +44 -46
  131. lionagi/integrations/storage/structure_excel.py +43 -26
  132. lionagi/integrations/storage/to_excel.py +11 -4
  133. lionagi/libs/__init__.py +22 -1
  134. lionagi/libs/ln_api.py +75 -20
  135. lionagi/libs/ln_context.py +37 -0
  136. lionagi/libs/ln_convert.py +21 -9
  137. lionagi/libs/ln_func_call.py +69 -28
  138. lionagi/libs/ln_image.py +107 -0
  139. lionagi/libs/ln_nested.py +26 -11
  140. lionagi/libs/ln_parse.py +82 -23
  141. lionagi/libs/ln_queue.py +16 -0
  142. lionagi/libs/ln_tokenize.py +164 -0
  143. lionagi/libs/ln_validate.py +16 -0
  144. lionagi/libs/special_tokens.py +172 -0
  145. lionagi/libs/sys_util.py +95 -24
  146. lionagi/lions/coder/code_form.py +13 -0
  147. lionagi/lions/coder/coder.py +50 -3
  148. lionagi/lions/coder/util.py +30 -25
  149. lionagi/tests/libs/test_func_call.py +23 -21
  150. lionagi/tests/libs/test_nested.py +36 -21
  151. lionagi/tests/libs/test_parse.py +1 -1
  152. lionagi/tests/test_core/collections/__init__.py +0 -0
  153. lionagi/tests/test_core/collections/test_component.py +206 -0
  154. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  155. lionagi/tests/test_core/collections/test_flow.py +145 -0
  156. lionagi/tests/test_core/collections/test_pile.py +171 -0
  157. lionagi/tests/test_core/collections/test_progression.py +129 -0
  158. lionagi/tests/test_core/generic/test_edge.py +67 -0
  159. lionagi/tests/test_core/generic/test_graph.py +96 -0
  160. lionagi/tests/test_core/generic/test_node.py +106 -0
  161. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  162. lionagi/tests/test_core/test_branch.py +115 -294
  163. lionagi/tests/test_core/test_form.py +46 -0
  164. lionagi/tests/test_core/test_report.py +105 -0
  165. lionagi/tests/test_core/test_validator.py +111 -0
  166. lionagi/version.py +1 -1
  167. lionagi-0.2.1.dist-info/LICENSE +202 -0
  168. lionagi-0.2.1.dist-info/METADATA +272 -0
  169. lionagi-0.2.1.dist-info/RECORD +240 -0
  170. lionagi/core/branch/base.py +0 -653
  171. lionagi/core/branch/branch.py +0 -474
  172. lionagi/core/branch/flow_mixin.py +0 -96
  173. lionagi/core/branch/util.py +0 -323
  174. lionagi/core/direct/__init__.py +0 -19
  175. lionagi/core/direct/cot.py +0 -123
  176. lionagi/core/direct/plan.py +0 -164
  177. lionagi/core/direct/predict.py +0 -166
  178. lionagi/core/direct/react.py +0 -171
  179. lionagi/core/direct/score.py +0 -279
  180. lionagi/core/direct/select.py +0 -170
  181. lionagi/core/direct/sentiment.py +0 -1
  182. lionagi/core/direct/utils.py +0 -110
  183. lionagi/core/direct/vote.py +0 -64
  184. lionagi/core/execute/base_executor.py +0 -47
  185. lionagi/core/flow/baseflow.py +0 -23
  186. lionagi/core/flow/monoflow/ReAct.py +0 -240
  187. lionagi/core/flow/monoflow/__init__.py +0 -9
  188. lionagi/core/flow/monoflow/chat.py +0 -95
  189. lionagi/core/flow/monoflow/chat_mixin.py +0 -253
  190. lionagi/core/flow/monoflow/followup.py +0 -215
  191. lionagi/core/flow/polyflow/__init__.py +0 -1
  192. lionagi/core/flow/polyflow/chat.py +0 -251
  193. lionagi/core/form/action_form.py +0 -26
  194. lionagi/core/form/field_validator.py +0 -287
  195. lionagi/core/form/form.py +0 -302
  196. lionagi/core/form/mixin.py +0 -214
  197. lionagi/core/form/scored_form.py +0 -13
  198. lionagi/core/generic/action.py +0 -26
  199. lionagi/core/generic/component.py +0 -532
  200. lionagi/core/generic/condition.py +0 -46
  201. lionagi/core/generic/mail.py +0 -90
  202. lionagi/core/generic/mailbox.py +0 -36
  203. lionagi/core/generic/relation.py +0 -70
  204. lionagi/core/generic/signal.py +0 -22
  205. lionagi/core/generic/structure.py +0 -362
  206. lionagi/core/generic/transfer.py +0 -20
  207. lionagi/core/generic/work.py +0 -40
  208. lionagi/core/graph/graph.py +0 -126
  209. lionagi/core/graph/tree.py +0 -190
  210. lionagi/core/mail/schema.py +0 -63
  211. lionagi/core/messages/schema.py +0 -325
  212. lionagi/core/tool/__init__.py +0 -5
  213. lionagi/core/tool/tool.py +0 -28
  214. lionagi/core/tool/tool_manager.py +0 -283
  215. lionagi/experimental/report/form.py +0 -64
  216. lionagi/experimental/report/report.py +0 -138
  217. lionagi/experimental/report/util.py +0 -47
  218. lionagi/experimental/tool/function_calling.py +0 -43
  219. lionagi/experimental/tool/manual.py +0 -66
  220. lionagi/experimental/tool/schema.py +0 -59
  221. lionagi/experimental/tool/tool_manager.py +0 -138
  222. lionagi/experimental/tool/util.py +0 -16
  223. lionagi/experimental/validator/rule.py +0 -139
  224. lionagi/experimental/validator/validator.py +0 -56
  225. lionagi/experimental/work/__init__.py +0 -10
  226. lionagi/experimental/work/async_queue.py +0 -54
  227. lionagi/experimental/work/schema.py +0 -73
  228. lionagi/experimental/work/work_function.py +0 -67
  229. lionagi/experimental/work/worker.py +0 -56
  230. lionagi/experimental/work2/form.py +0 -371
  231. lionagi/experimental/work2/report.py +0 -289
  232. lionagi/experimental/work2/schema.py +0 -30
  233. lionagi/experimental/work2/tests.py +0 -72
  234. lionagi/experimental/work2/work_function.py +0 -89
  235. lionagi/experimental/work2/worker.py +0 -12
  236. lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
  237. lionagi/tests/test_core/generic/test_component.py +0 -89
  238. lionagi/tests/test_core/test_base_branch.py +0 -426
  239. lionagi/tests/test_core/test_chat_flow.py +0 -63
  240. lionagi/tests/test_core/test_mail_manager.py +0 -75
  241. lionagi/tests/test_core/test_prompts.py +0 -51
  242. lionagi/tests/test_core/test_session.py +0 -254
  243. lionagi/tests/test_core/test_session_base_util.py +0 -313
  244. lionagi/tests/test_core/test_tool_manager.py +0 -95
  245. lionagi-0.1.2.dist-info/LICENSE +0 -9
  246. lionagi-0.1.2.dist-info/METADATA +0 -174
  247. lionagi-0.1.2.dist-info/RECORD +0 -206
  248. /lionagi/core/{branch → _setting}/__init__.py +0 -0
  249. /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
  250. /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
  251. /lionagi/core/{form → agent/plan}/__init__.py +0 -0
  252. /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
  253. /lionagi/core/{graph → director}/__init__.py +0 -0
  254. /lionagi/core/{messages → engine}/__init__.py +0 -0
  255. /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
  256. /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
  257. /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
  258. /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
  259. /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
  260. /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
  261. /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
  262. /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
  263. /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
  264. /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
  265. /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
  266. /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
  267. {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
  268. {lionagi-0.1.2.dist-info → lionagi-0.2.1.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