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,283 @@
|
|
1
|
+
"""
|
2
|
+
Copyright 2024 HaiyangLi
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import re
|
18
|
+
import json
|
19
|
+
import contextlib
|
20
|
+
|
21
|
+
from lionagi.libs import ParseUtil
|
22
|
+
from lionagi.libs.ln_convert import strip_lower, to_dict
|
23
|
+
from lionagi.libs.ln_nested import nget
|
24
|
+
|
25
|
+
from .message import RoledMessage
|
26
|
+
from .system import System
|
27
|
+
from .instruction import Instruction
|
28
|
+
from .assistant_response import AssistantResponse
|
29
|
+
from .action_request import ActionRequest
|
30
|
+
from .action_response import ActionResponse
|
31
|
+
|
32
|
+
|
33
|
+
def create_message(
|
34
|
+
*,
|
35
|
+
system=None, # system node - JSON serializable
|
36
|
+
instruction=None, # Instruction node - JSON serializable
|
37
|
+
context=None, # JSON serializable
|
38
|
+
assistant_response=None, # JSON
|
39
|
+
function=None,
|
40
|
+
arguments=None,
|
41
|
+
func_outputs=None,
|
42
|
+
action_request=None, # ActionRequest node
|
43
|
+
action_response=None, # ActionResponse node
|
44
|
+
images=None, # base64 encoded image
|
45
|
+
sender=None, # str
|
46
|
+
recipient=None, # str
|
47
|
+
requested_fields=None, # dict[str, str]
|
48
|
+
**kwargs, # additional context fields
|
49
|
+
):
|
50
|
+
# order of handling
|
51
|
+
# action response - action request - other regular messages
|
52
|
+
# if the message is output from function calling we will ignore other message types
|
53
|
+
"""
|
54
|
+
Creates a message based on the provided parameters.
|
55
|
+
|
56
|
+
Args:
|
57
|
+
system (dict, optional): The system node (JSON serializable).
|
58
|
+
instruction (dict, optional): The instruction node (JSON serializable).
|
59
|
+
context (dict, optional): Additional context (JSON serializable).
|
60
|
+
assistant_response (dict, optional): The assistant response node (JSON serializable).
|
61
|
+
function (str, optional): The function name for action requests.
|
62
|
+
arguments (dict, optional): The arguments for the function.
|
63
|
+
func_outputs (Any, optional): The outputs from the function.
|
64
|
+
action_request (ActionRequest, optional): The action request node.
|
65
|
+
action_response (ActionResponse, optional): The action response node.
|
66
|
+
sender (str, optional): The sender of the message.
|
67
|
+
recipient (str, optional): The recipient of the message.
|
68
|
+
requested_fields (dict[str, str], optional): The requested fields for the instruction.
|
69
|
+
**kwargs: Additional context fields.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
RoledMessage: The constructed message based on the provided parameters.
|
73
|
+
|
74
|
+
Raises:
|
75
|
+
ValueError: If the parameters are invalid or missing required values.
|
76
|
+
"""
|
77
|
+
|
78
|
+
if func_outputs or action_response:
|
79
|
+
if not action_request:
|
80
|
+
raise ValueError(
|
81
|
+
"Error: please provide an corresponding action request for an action response."
|
82
|
+
)
|
83
|
+
|
84
|
+
if isinstance(action_response, ActionResponse):
|
85
|
+
action_response.update_request(action_request)
|
86
|
+
return action_response
|
87
|
+
|
88
|
+
return ActionResponse(
|
89
|
+
action_request=action_request,
|
90
|
+
sender=sender,
|
91
|
+
func_outputs=func_outputs,
|
92
|
+
)
|
93
|
+
|
94
|
+
if action_request:
|
95
|
+
if not isinstance(action_request, ActionRequest):
|
96
|
+
raise ValueError(
|
97
|
+
"Error: action request must be an instance of ActionRequest."
|
98
|
+
)
|
99
|
+
return action_request
|
100
|
+
|
101
|
+
if function:
|
102
|
+
if not arguments:
|
103
|
+
raise ValueError("Error: please provide arguments for the function.")
|
104
|
+
return ActionRequest(
|
105
|
+
function=function,
|
106
|
+
arguments=arguments,
|
107
|
+
sender=sender,
|
108
|
+
recipient=recipient,
|
109
|
+
)
|
110
|
+
|
111
|
+
a = {
|
112
|
+
"system": system,
|
113
|
+
"instruction": instruction,
|
114
|
+
"assistant_response": assistant_response,
|
115
|
+
}
|
116
|
+
|
117
|
+
a = {k: v for k, v in a.items() if v is not None}
|
118
|
+
|
119
|
+
if not len(a) == 1:
|
120
|
+
raise ValueError("Error: Message can only have one role")
|
121
|
+
|
122
|
+
if not func_outputs:
|
123
|
+
for k, v in a.items():
|
124
|
+
if isinstance(v, RoledMessage):
|
125
|
+
if isinstance(v, Instruction):
|
126
|
+
if context:
|
127
|
+
v._add_context(context)
|
128
|
+
if requested_fields:
|
129
|
+
v._update_requested_fields(requested_fields)
|
130
|
+
return v
|
131
|
+
|
132
|
+
if system:
|
133
|
+
return System(system=system, sender=sender, recipient=recipient)
|
134
|
+
|
135
|
+
elif assistant_response:
|
136
|
+
return AssistantResponse(
|
137
|
+
assistant_response=assistant_response,
|
138
|
+
sender=sender,
|
139
|
+
recipient=recipient,
|
140
|
+
)
|
141
|
+
|
142
|
+
else:
|
143
|
+
if images:
|
144
|
+
images = images if isinstance(images, list) else [images]
|
145
|
+
|
146
|
+
return Instruction(
|
147
|
+
instruction=instruction,
|
148
|
+
context=context,
|
149
|
+
sender=sender,
|
150
|
+
recipient=recipient,
|
151
|
+
requested_fields=requested_fields,
|
152
|
+
images=images,
|
153
|
+
**kwargs,
|
154
|
+
)
|
155
|
+
|
156
|
+
|
157
|
+
def _parse_action_request(response):
|
158
|
+
"""
|
159
|
+
Parses an action request from the response.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
response (dict): The response containing the action request.
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
list[ActionRequest] or None: A list of action requests or None if invalid.
|
166
|
+
|
167
|
+
Raises:
|
168
|
+
ActionError: If the action request is invalid.
|
169
|
+
"""
|
170
|
+
message = to_dict(response) if not isinstance(response, dict) else response
|
171
|
+
content_ = None
|
172
|
+
|
173
|
+
if strip_lower(nget(message, ["content"])) == "none":
|
174
|
+
content_ = _handle_action_request(message)
|
175
|
+
|
176
|
+
elif nget(message, ["content", "tool_uses"], None):
|
177
|
+
content_ = message["content"]["tool_uses"]
|
178
|
+
|
179
|
+
else:
|
180
|
+
json_block_pattern = re.compile(r"```json\n({.*?tool_uses.*?})\n```", re.DOTALL)
|
181
|
+
|
182
|
+
# Find the JSON block in the text
|
183
|
+
match = json_block_pattern.search(str(message["content"]))
|
184
|
+
if match:
|
185
|
+
json_block = match.group(1)
|
186
|
+
parsed_json = json.loads(json_block)
|
187
|
+
if "tool_uses" in parsed_json:
|
188
|
+
content_ = parsed_json["tool_uses"]
|
189
|
+
elif "actions" in parsed_json:
|
190
|
+
content_ = parsed_json["actions"]
|
191
|
+
else:
|
192
|
+
content_ = []
|
193
|
+
|
194
|
+
if isinstance(content_, dict):
|
195
|
+
content_ = [content_]
|
196
|
+
|
197
|
+
if isinstance(content_, list) and not content_ == []:
|
198
|
+
outs = []
|
199
|
+
for func_calling in content_:
|
200
|
+
if "recipient_name" in func_calling:
|
201
|
+
func_calling["action"] = func_calling["recipient_name"].split(".")[1]
|
202
|
+
func_calling["arguments"] = func_calling["parameters"]
|
203
|
+
elif "function" in func_calling:
|
204
|
+
func_calling["action"] = func_calling["function"]
|
205
|
+
if "parameters" in func_calling:
|
206
|
+
func_calling["arguments"] = func_calling["parameters"]
|
207
|
+
elif "arguments" in func_calling:
|
208
|
+
func_calling["arguments"] = func_calling["arguments"]
|
209
|
+
|
210
|
+
msg = ActionRequest(
|
211
|
+
function=func_calling["action"]
|
212
|
+
.replace("action_", "")
|
213
|
+
.replace("recipient_", ""),
|
214
|
+
arguments=func_calling["arguments"],
|
215
|
+
)
|
216
|
+
outs.append(msg)
|
217
|
+
return outs
|
218
|
+
|
219
|
+
else:
|
220
|
+
try:
|
221
|
+
_content = to_dict(message["content"])
|
222
|
+
if "action_request" in _content:
|
223
|
+
content_ = _content["action_request"]
|
224
|
+
|
225
|
+
if isinstance(content_, dict):
|
226
|
+
content_ = [content_]
|
227
|
+
|
228
|
+
if isinstance(content_, list):
|
229
|
+
outs = []
|
230
|
+
for func_calling in content_:
|
231
|
+
if "function" in func_calling:
|
232
|
+
func_calling["action"] = func_calling["function"]
|
233
|
+
if "parameters" in func_calling:
|
234
|
+
func_calling["arguments"] = func_calling["parameters"]
|
235
|
+
elif "arguments" in func_calling:
|
236
|
+
func_calling["arguments"] = func_calling["arguments"]
|
237
|
+
msg = ActionRequest(
|
238
|
+
function=func_calling["action"]
|
239
|
+
.replace("action_", "")
|
240
|
+
.replace("recipient_", ""),
|
241
|
+
arguments=func_calling["arguments"],
|
242
|
+
)
|
243
|
+
outs.append(msg)
|
244
|
+
return outs
|
245
|
+
except:
|
246
|
+
return None
|
247
|
+
return None
|
248
|
+
|
249
|
+
|
250
|
+
def _handle_action_request(response):
|
251
|
+
"""
|
252
|
+
Handles the action request parsing from the response.
|
253
|
+
|
254
|
+
Args:
|
255
|
+
response (dict): The response containing the action request details.
|
256
|
+
|
257
|
+
Returns:
|
258
|
+
list[dict]: A list of function call details.
|
259
|
+
|
260
|
+
Raises:
|
261
|
+
ValueError: If the response message is invalid.
|
262
|
+
"""
|
263
|
+
try:
|
264
|
+
tool_count = 0
|
265
|
+
func_list = []
|
266
|
+
while tool_count < len(response["tool_calls"]):
|
267
|
+
_path = ["tool_calls", tool_count, "type"]
|
268
|
+
|
269
|
+
if nget(response, _path) == "function":
|
270
|
+
_path1 = ["tool_calls", tool_count, "function", "name"]
|
271
|
+
_path2 = ["tool_calls", tool_count, "function", "arguments"]
|
272
|
+
|
273
|
+
func_content = {
|
274
|
+
"action": f"action_{nget(response, _path1)}",
|
275
|
+
"arguments": nget(response, _path2),
|
276
|
+
}
|
277
|
+
func_list.append(func_content)
|
278
|
+
tool_count += 1
|
279
|
+
return func_list
|
280
|
+
except:
|
281
|
+
raise ValueError(
|
282
|
+
"Response message must be one of regular response or function calling"
|
283
|
+
)
|
@@ -0,0 +1,217 @@
|
|
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
|
+
"""
|
18
|
+
This module defines the BaseForm class, a foundation for form handling in
|
19
|
+
applications. It provides common functionalities for form operations like
|
20
|
+
initialization, validation, and state management. Extend this class to
|
21
|
+
implement specific form behaviors and configurations.
|
22
|
+
"""
|
23
|
+
|
24
|
+
from abc import abstractmethod
|
25
|
+
from typing import Any, List, Dict
|
26
|
+
import contextlib
|
27
|
+
from lionagi.core.collections.abc import Component, Field
|
28
|
+
from ..collections.util import to_list_type
|
29
|
+
|
30
|
+
|
31
|
+
class BaseForm(Component):
|
32
|
+
"""
|
33
|
+
NOTICE:
|
34
|
+
The Form/Report system is inspired by DSPy. (especially in DSPy's usage
|
35
|
+
of `Signature` and `Module`)
|
36
|
+
https://github.com/stanfordnlp/dspy
|
37
|
+
|
38
|
+
MIT License
|
39
|
+
Copyright (c) 2023 Stanford Future Data Systems
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
42
|
+
of this software and associated documentation files (the "Software"), to deal
|
43
|
+
in the Software without restriction, including without limitation the rights
|
44
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
45
|
+
copies of the Software, and to permit persons to whom the Software is
|
46
|
+
furnished to do so, subject to the following conditions:
|
47
|
+
|
48
|
+
The above copyright notice and this permission notice shall be included in all
|
49
|
+
copies or substantial portions of the Software.
|
50
|
+
|
51
|
+
REFERENCES:
|
52
|
+
@article{khattab2023dspy,
|
53
|
+
title={DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines},
|
54
|
+
author={Khattab, Omar and Singhvi, Arnav and Maheshwari, Paridhi and Zhang, Zhiyuan and
|
55
|
+
Santhanam, Keshav and Vardhamanan, Sri and Haq, Saiful and Sharma, Ashutosh and Joshi,
|
56
|
+
Thomas T. and Moazam, Hanna and Miller, Heather and Zaharia, Matei and Potts, Christopher},
|
57
|
+
journal={arXiv preprint arXiv:2310.03714},
|
58
|
+
year={2023}
|
59
|
+
}
|
60
|
+
@article{khattab2022demonstrate,
|
61
|
+
title={Demonstrate-Search-Predict: Composing Retrieval and Language Models for
|
62
|
+
Knowledge-Intensive {NLP}},
|
63
|
+
author={Khattab, Omar and Santhanam, Keshav and Li, Xiang Lisa and Hall, David and Liang,
|
64
|
+
Percy and Potts, Christopher and Zaharia, Matei},
|
65
|
+
journal={arXiv preprint arXiv:2212.14024},
|
66
|
+
year={2022}
|
67
|
+
}
|
68
|
+
|
69
|
+
LionAGI Modifications:
|
70
|
+
- Redesigned focusing on form-based task handling
|
71
|
+
- fully integrated with LionAGI's existing collections and components
|
72
|
+
- developed report system for multi-step task handling
|
73
|
+
- created work system for task execution and management
|
74
|
+
|
75
|
+
Base class for handling form-like structures within an application.
|
76
|
+
Manages form components and operations such as filling forms and
|
77
|
+
checking their state (filled, workable).
|
78
|
+
|
79
|
+
Attributes:
|
80
|
+
assignment (str): The objective of the form specifying input/output fields.
|
81
|
+
input_fields (List[str]): Fields required to carry out the objective of the form.
|
82
|
+
requested_fields (List[str]): Fields requested to be filled by the user.
|
83
|
+
task (Any): The work to be done by the form, including custom instructions.
|
84
|
+
validation_kwargs (Dict[str, Dict[str, Any]]): Additional validation constraints for the form fields.
|
85
|
+
"""
|
86
|
+
|
87
|
+
template_name: str = "default_directive"
|
88
|
+
|
89
|
+
assignment: str | None = Field(
|
90
|
+
None,
|
91
|
+
description="The objective of the form specifying input/output fields.",
|
92
|
+
examples=["input1, input2 -> output"],
|
93
|
+
)
|
94
|
+
|
95
|
+
input_fields: List[str] = Field(
|
96
|
+
default_factory=list,
|
97
|
+
description="Fields required to carry out the objective of the form.",
|
98
|
+
)
|
99
|
+
|
100
|
+
requested_fields: List[str] = Field(
|
101
|
+
default_factory=list,
|
102
|
+
description="Fields requested to be filled by the user.",
|
103
|
+
)
|
104
|
+
|
105
|
+
task: Any = Field(
|
106
|
+
default_factory=str,
|
107
|
+
description="The work to be done by the form, including custom instructions.",
|
108
|
+
)
|
109
|
+
|
110
|
+
validation_kwargs: Dict[str, Dict[str, Any]] = Field(
|
111
|
+
default_factory=dict,
|
112
|
+
description="Additional validation constraints for the form fields.",
|
113
|
+
examples=[{"field": {"config1": "a", "config2": "b"}}],
|
114
|
+
)
|
115
|
+
|
116
|
+
@property
|
117
|
+
def work_fields(self) -> Dict[str, Any]:
|
118
|
+
"""
|
119
|
+
Get the fields relevant to the current task, including input and
|
120
|
+
requested fields. Must be implemented by subclasses.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
Dict[str, Any]: The fields relevant to the current task.
|
124
|
+
"""
|
125
|
+
raise NotImplementedError
|
126
|
+
|
127
|
+
@abstractmethod
|
128
|
+
def fill(self, *args, **kwargs):
|
129
|
+
"""
|
130
|
+
Fill the form from various sources, including other forms and
|
131
|
+
additional fields. Implement this method in subclasses.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
*args: Additional positional arguments.
|
135
|
+
**kwargs: Additional keyword arguments.
|
136
|
+
"""
|
137
|
+
pass
|
138
|
+
|
139
|
+
@abstractmethod
|
140
|
+
def is_workable(self) -> bool:
|
141
|
+
"""
|
142
|
+
Check if the form object is ready for work execution. Raise an error
|
143
|
+
if the form is not workable. Use with the workable property.
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
bool: True if the form is workable, otherwise False.
|
147
|
+
"""
|
148
|
+
pass
|
149
|
+
|
150
|
+
@property
|
151
|
+
def filled(self) -> bool:
|
152
|
+
"""
|
153
|
+
Check if the form is filled with all required fields. Uses the
|
154
|
+
_is_filled method and suppresses any ValueError raised by it.
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
bool: True if the form is filled, otherwise False.
|
158
|
+
"""
|
159
|
+
with contextlib.suppress(ValueError):
|
160
|
+
return self._is_filled()
|
161
|
+
return False
|
162
|
+
|
163
|
+
@property
|
164
|
+
def workable(self) -> bool:
|
165
|
+
"""
|
166
|
+
Check if the form is workable. This property does not raise an error
|
167
|
+
and will return True or False.
|
168
|
+
|
169
|
+
Returns:
|
170
|
+
bool: True if the form is workable, otherwise False.
|
171
|
+
"""
|
172
|
+
with contextlib.suppress(ValueError):
|
173
|
+
return self.is_workable()
|
174
|
+
return False
|
175
|
+
|
176
|
+
def _is_filled(self) -> bool:
|
177
|
+
"""
|
178
|
+
Private method to check if all work fields are filled. Raises a
|
179
|
+
ValueError if any field is not filled.
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
bool: True if all work fields are filled, otherwise raises ValueError.
|
183
|
+
|
184
|
+
Raises:
|
185
|
+
ValueError: If any field is not filled.
|
186
|
+
"""
|
187
|
+
for k, value in self.work_fields.items():
|
188
|
+
if value is None:
|
189
|
+
raise ValueError(f"Field {k} is not filled")
|
190
|
+
return True
|
191
|
+
|
192
|
+
def _get_all_fields(
|
193
|
+
self, form: List["BaseForm"] = None, **kwargs
|
194
|
+
) -> Dict[str, Any]:
|
195
|
+
"""
|
196
|
+
Given a form or collections of forms, and additional fields, gather
|
197
|
+
all fields together including self fields with valid value.
|
198
|
+
|
199
|
+
Args:
|
200
|
+
form (List[BaseForm], optional): A list of forms to gather fields from.
|
201
|
+
**kwargs: Additional fields to include.
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
Dict[str, Any]: A dictionary of all gathered fields.
|
205
|
+
"""
|
206
|
+
form: list["BaseForm"] = to_list_type(form) if form else []
|
207
|
+
all_fields = self.work_fields.copy()
|
208
|
+
all_form_fields = (
|
209
|
+
{}
|
210
|
+
if not form
|
211
|
+
else {k: v for i in form for k, v in i.work_fields.items() if v is not None}
|
212
|
+
)
|
213
|
+
all_fields.update({**all_form_fields, **kwargs})
|
214
|
+
return all_fields
|
215
|
+
|
216
|
+
def copy(self):
|
217
|
+
return self.model_copy()
|