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
@@ -1,59 +0,0 @@
|
|
1
|
-
from typing import Any
|
2
|
-
from pydantic import field_serializer
|
3
|
-
from functools import singledispatchmethod
|
4
|
-
from lionagi import logging as _logging
|
5
|
-
from lionagi.libs import func_call, AsyncUtil
|
6
|
-
from lionagi.core.generic.node import Node
|
7
|
-
from .function_calling import FunctionCalling
|
8
|
-
|
9
|
-
|
10
|
-
class Tool(Node):
|
11
|
-
|
12
|
-
func: Any
|
13
|
-
schema_: dict | None = None
|
14
|
-
manual: Any | None = None
|
15
|
-
parser: Any | None = None
|
16
|
-
pre_processor: Any | None = None
|
17
|
-
post_processor: Any | None = None
|
18
|
-
|
19
|
-
@property
|
20
|
-
def name(self):
|
21
|
-
return self.schema_["function"]["name"]
|
22
|
-
|
23
|
-
@field_serializer("func")
|
24
|
-
def serialize_func(self, func):
|
25
|
-
return func.__name__
|
26
|
-
|
27
|
-
@singledispatchmethod
|
28
|
-
async def invoke(self, values: Any) -> Any:
|
29
|
-
raise TypeError(f"Unsupported type {type(values)}")
|
30
|
-
|
31
|
-
@invoke.register
|
32
|
-
async def _(self, kwargs: dict):
|
33
|
-
|
34
|
-
out = None
|
35
|
-
|
36
|
-
if self.pre_processor:
|
37
|
-
kwargs = await func_call.call_handler(self.pre_processor, kwargs)
|
38
|
-
try:
|
39
|
-
out = await func_call.call_handler(self.func, **kwargs)
|
40
|
-
|
41
|
-
except Exception as e:
|
42
|
-
_logging.error(f"Error invoking function {self.func_name}: {e}")
|
43
|
-
return None
|
44
|
-
|
45
|
-
if self.post_processor:
|
46
|
-
return await func_call.call_handler(self.post_processor, out)
|
47
|
-
|
48
|
-
return out
|
49
|
-
|
50
|
-
@invoke.register
|
51
|
-
async def _(self, function_calls: FunctionCalling):
|
52
|
-
return await self.invoke(function_calls.kwargs)
|
53
|
-
|
54
|
-
@invoke.register
|
55
|
-
async def _(self, values: list):
|
56
|
-
return await func_call.alcall(self.invoke, values)
|
57
|
-
|
58
|
-
|
59
|
-
TOOL_TYPE = bool | Tool | str | list[Tool | str | dict] | dict
|
@@ -1,138 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from functools import singledispatchmethod
|
3
|
-
from collections import deque
|
4
|
-
from typing import Tuple, Any, TypeVar, Callable
|
5
|
-
from lionagi.libs import func_call, convert, ParseUtil
|
6
|
-
from lionagi import logging as _logging
|
7
|
-
from .schema import Tool, TOOL_TYPE
|
8
|
-
from .util import func_to_tool, parse_tool_response
|
9
|
-
from .function_calling import FunctionCalling
|
10
|
-
|
11
|
-
T = TypeVar("T", bound=Tool)
|
12
|
-
|
13
|
-
|
14
|
-
class ToolManager:
|
15
|
-
|
16
|
-
def __init__(
|
17
|
-
self,
|
18
|
-
tool_registry: dict = {},
|
19
|
-
function_calling_tasks: dict[str : deque[FunctionCalling]] = {},
|
20
|
-
):
|
21
|
-
self.registry = tool_registry
|
22
|
-
self.function_calling_tasks = function_calling_tasks
|
23
|
-
|
24
|
-
@singledispatchmethod
|
25
|
-
def register_tools(self, tools: Any):
|
26
|
-
raise TypeError(f"Unsupported type {type(tools)}")
|
27
|
-
|
28
|
-
@register_tools.register(Tool)
|
29
|
-
def _(self, tools):
|
30
|
-
name = tools.schema_["function"]["name"]
|
31
|
-
if self._has_name(name):
|
32
|
-
err_msg = f"Function {name} is already registered."
|
33
|
-
_logging.error(err_msg)
|
34
|
-
raise ValueError(err_msg)
|
35
|
-
else:
|
36
|
-
self.registry[name] = tools
|
37
|
-
self.function_calling_tasks[name] = deque()
|
38
|
-
return True
|
39
|
-
|
40
|
-
@register_tools.register(Callable)
|
41
|
-
def _(self, tools):
|
42
|
-
tool = func_to_tool(tools)[0]
|
43
|
-
return self.register_tools(tool)
|
44
|
-
|
45
|
-
@register_tools.register(list)
|
46
|
-
def _(self, tools):
|
47
|
-
return func_call.lcall(tools, self.register_tools)
|
48
|
-
|
49
|
-
@singledispatchmethod
|
50
|
-
def register_function_calling(self, func_params: Any):
|
51
|
-
raise TypeError(f"Unsupported type {type(func_params)}")
|
52
|
-
|
53
|
-
@register_function_calling.register(tuple)
|
54
|
-
def _(self, func_params):
|
55
|
-
func = self.registry[func_params[0]].func
|
56
|
-
kwargs = func_params[1]
|
57
|
-
_function_calling = FunctionCalling(func=func, kwargs=kwargs)
|
58
|
-
self.function_calling_tasks[func.__name__].append(_function_calling)
|
59
|
-
return True
|
60
|
-
|
61
|
-
@register_function_calling.register(dict)
|
62
|
-
def _(self, response):
|
63
|
-
tuple_ = parse_tool_response(response)
|
64
|
-
return self.register_function_calling(tuple_)
|
65
|
-
|
66
|
-
@register_function_calling.register(list)
|
67
|
-
def _(self, func_params):
|
68
|
-
return func_call.lcall(func_params, self.register_function_calling)
|
69
|
-
|
70
|
-
async def invoke(self, func_params: Tuple[str, dict[str, Any]]) -> Any:
|
71
|
-
name, kwargs = func_params
|
72
|
-
if not self._has_name(name):
|
73
|
-
raise ValueError(f"Function {name} is not registered.")
|
74
|
-
tool = self.registry[name]
|
75
|
-
func = tool.func
|
76
|
-
parser = tool.parser
|
77
|
-
try:
|
78
|
-
out = await func_call.call_handler(func, **kwargs)
|
79
|
-
return parser(out) if parser else out
|
80
|
-
|
81
|
-
except Exception as e:
|
82
|
-
raise ValueError(
|
83
|
-
f"Error when invoking function {name} with arguments {kwargs} with error message {e}"
|
84
|
-
) from e
|
85
|
-
|
86
|
-
@property
|
87
|
-
def _schema_list(self) -> list[dict[str, Any]]:
|
88
|
-
return [tool.schema_ for tool in self.registry.values()]
|
89
|
-
|
90
|
-
def get_tool_schema(self, tools: TOOL_TYPE, **kwargs):
|
91
|
-
if isinstance(tools, bool):
|
92
|
-
tool_kwarg = {"tools": self._schema_list}
|
93
|
-
return tool_kwarg | kwargs
|
94
|
-
|
95
|
-
else:
|
96
|
-
if not isinstance(tools, list):
|
97
|
-
tools = [tools]
|
98
|
-
tool_kwarg = {"tools": self._get_tool_schema(tools)}
|
99
|
-
return tool_kwarg | kwargs
|
100
|
-
|
101
|
-
def _has_name(self, name: str) -> bool:
|
102
|
-
return name in self.registry
|
103
|
-
|
104
|
-
@singledispatchmethod
|
105
|
-
def _get_tool_schema(self, tool: Any) -> dict:
|
106
|
-
raise TypeError(f"Unsupported type {type(tool)}")
|
107
|
-
|
108
|
-
@_get_tool_schema.register(dict)
|
109
|
-
def _(self, tool):
|
110
|
-
"""
|
111
|
-
assuming that the tool is a schema
|
112
|
-
"""
|
113
|
-
return tool
|
114
|
-
|
115
|
-
@_get_tool_schema.register(Tool)
|
116
|
-
def _(self, tool):
|
117
|
-
if self._has_name(tool.name):
|
118
|
-
return self.registry[tool.name].schema_
|
119
|
-
else:
|
120
|
-
err_msg = f"Function {tool.name} is not registered."
|
121
|
-
_logging.error(err_msg)
|
122
|
-
raise ValueError(err_msg)
|
123
|
-
|
124
|
-
@_get_tool_schema.register(str)
|
125
|
-
def _(self, tool):
|
126
|
-
"""
|
127
|
-
assuming that the tool is a name
|
128
|
-
"""
|
129
|
-
if self._has_name(tool):
|
130
|
-
return self.registry[tool].schema_
|
131
|
-
else:
|
132
|
-
err_msg = f"Function {tool} is not registered."
|
133
|
-
_logging.error(err_msg)
|
134
|
-
raise ValueError(err_msg)
|
135
|
-
|
136
|
-
@_get_tool_schema.register(list)
|
137
|
-
def _(self, tools):
|
138
|
-
return func_call.lcall(tools, self._get_tool_schema)
|
@@ -1,16 +0,0 @@
|
|
1
|
-
from typing import Tuple
|
2
|
-
from lionagi.libs import convert
|
3
|
-
|
4
|
-
|
5
|
-
def parse_tool_response(response: dict) -> Tuple[str, dict]:
|
6
|
-
try:
|
7
|
-
func = response["action"][7:]
|
8
|
-
args = convert.to_dict(response["arguments"])
|
9
|
-
return func, args
|
10
|
-
except Exception:
|
11
|
-
try:
|
12
|
-
func = response["recipient_name"].split(".")[-1]
|
13
|
-
args = response["parameters"]
|
14
|
-
return func, args
|
15
|
-
except:
|
16
|
-
raise ValueError("response is not a valid function call")
|
@@ -1,139 +0,0 @@
|
|
1
|
-
from lionagi.libs import validation_funcs
|
2
|
-
from abc import abstractmethod
|
3
|
-
|
4
|
-
|
5
|
-
class Rule:
|
6
|
-
|
7
|
-
def __init__(self, **kwargs):
|
8
|
-
self.validation_kwargs = kwargs
|
9
|
-
self.fix = kwargs.get("fix", False)
|
10
|
-
|
11
|
-
@abstractmethod
|
12
|
-
def condition(self, **kwargs):
|
13
|
-
pass
|
14
|
-
|
15
|
-
@abstractmethod
|
16
|
-
async def validate(self, value, **kwargs):
|
17
|
-
pass
|
18
|
-
|
19
|
-
|
20
|
-
class ChoiceRule(Rule):
|
21
|
-
|
22
|
-
def condition(self, choices=None):
|
23
|
-
return choices is not None
|
24
|
-
|
25
|
-
def check(self, choices=None):
|
26
|
-
if choices and not isinstance(choices, list):
|
27
|
-
try:
|
28
|
-
choices = [i.value for i in choices]
|
29
|
-
except Exception as e:
|
30
|
-
raise ValueError(f"failed to get choices") from e
|
31
|
-
return choices
|
32
|
-
|
33
|
-
def fix(self, value, choices=None, **kwargs):
|
34
|
-
v_ = validation_funcs["enum"](value, choices=choices, fix_=True, **kwargs)
|
35
|
-
return v_
|
36
|
-
|
37
|
-
async def validate(self, value, choices=None, **kwargs):
|
38
|
-
if self.condition(choices):
|
39
|
-
if value in self.check(choices):
|
40
|
-
return value
|
41
|
-
if self.fix:
|
42
|
-
kwargs = {**self.validation_kwargs, **kwargs}
|
43
|
-
return self.fix(value, choices, **kwargs)
|
44
|
-
raise ValueError(f"{value} is not in chocies {choices}")
|
45
|
-
|
46
|
-
|
47
|
-
class ActionRequestRule(Rule):
|
48
|
-
|
49
|
-
def condition(self, annotation=None):
|
50
|
-
return any("actionrequest" in i for i in annotation)
|
51
|
-
|
52
|
-
async def validate(self, value, annotation=None):
|
53
|
-
if self.condition(annotation):
|
54
|
-
try:
|
55
|
-
return validation_funcs["action"](value)
|
56
|
-
except Exception as e:
|
57
|
-
raise ValueError(f"failed to validate field") from e
|
58
|
-
|
59
|
-
|
60
|
-
class BooleanRule(Rule):
|
61
|
-
|
62
|
-
def condition(self, annotation=None):
|
63
|
-
return "bool" in annotation and "str" not in annotation
|
64
|
-
|
65
|
-
async def validate(self, value, annotation=None):
|
66
|
-
if self.condition(annotation):
|
67
|
-
try:
|
68
|
-
return validation_funcs["bool"](
|
69
|
-
value, fix_=self.fix, **self.validation_kwargs
|
70
|
-
)
|
71
|
-
except Exception as e:
|
72
|
-
raise ValueError(f"failed to validate field") from e
|
73
|
-
|
74
|
-
|
75
|
-
class NumberRule(Rule):
|
76
|
-
|
77
|
-
def condition(self, annotation=None):
|
78
|
-
return (
|
79
|
-
any([i in annotation for i in ["int", "float", "number"]])
|
80
|
-
and "str" not in annotation
|
81
|
-
)
|
82
|
-
|
83
|
-
async def validate(self, value, annotation=None):
|
84
|
-
if self.condition(annotation):
|
85
|
-
if "float" in annotation:
|
86
|
-
self.validation_kwargs["num_type"] = float
|
87
|
-
if "precision" not in self.validation_kwargs:
|
88
|
-
self.validation_kwargs["precision"] = 32
|
89
|
-
|
90
|
-
try:
|
91
|
-
return validation_funcs["number"](
|
92
|
-
value, fix_=self.fix, **self.validation_kwargs
|
93
|
-
)
|
94
|
-
except Exception as e:
|
95
|
-
raise ValueError(f"failed to validate field") from e
|
96
|
-
|
97
|
-
|
98
|
-
class DictRule(Rule):
|
99
|
-
|
100
|
-
def condition(self, annotation=None):
|
101
|
-
return "dict" in annotation
|
102
|
-
|
103
|
-
async def validate(self, value, annotation=None, keys=None):
|
104
|
-
if self.condition(annotation):
|
105
|
-
if "str" not in annotation or keys:
|
106
|
-
try:
|
107
|
-
return validation_funcs["dict"](
|
108
|
-
value, keys=keys, fix_=self.fix, **self.validation_kwargs
|
109
|
-
)
|
110
|
-
except Exception as e:
|
111
|
-
raise ValueError(f"failed to validate field") from e
|
112
|
-
raise ValueError(f"failed to validate field")
|
113
|
-
|
114
|
-
|
115
|
-
class StringRule(Rule):
|
116
|
-
|
117
|
-
def condition(self, annotation=None):
|
118
|
-
return "str" in annotation
|
119
|
-
|
120
|
-
async def validate(self, value, annotation=None):
|
121
|
-
if self.condition(annotation):
|
122
|
-
try:
|
123
|
-
return validation_funcs["str"](
|
124
|
-
value, fix_=self.fix, **self.validation_kwargs
|
125
|
-
)
|
126
|
-
except Exception as e:
|
127
|
-
raise ValueError(f"failed to validate field") from e
|
128
|
-
|
129
|
-
|
130
|
-
from enum import Enum
|
131
|
-
|
132
|
-
|
133
|
-
class DEFAULT_RULES(Enum):
|
134
|
-
CHOICE = ChoiceRule
|
135
|
-
ACTION_REQUEST = ActionRequestRule
|
136
|
-
BOOL = BooleanRule
|
137
|
-
NUMBER = NumberRule
|
138
|
-
DICT = DictRule
|
139
|
-
STR = StringRule
|
@@ -1,56 +0,0 @@
|
|
1
|
-
from pydantic import BaseModel, Field
|
2
|
-
from .rule import DEFAULT_RULES, Rule
|
3
|
-
|
4
|
-
|
5
|
-
rules_ = {
|
6
|
-
"choice": DEFAULT_RULES.CHOICE.value,
|
7
|
-
"actionrequest": DEFAULT_RULES.ACTION_REQUEST.value,
|
8
|
-
"bool": DEFAULT_RULES.BOOL.value,
|
9
|
-
"number": DEFAULT_RULES.NUMBER.value,
|
10
|
-
"dict": DEFAULT_RULES.DICT.value,
|
11
|
-
"str": DEFAULT_RULES.STR.value,
|
12
|
-
}
|
13
|
-
|
14
|
-
order_ = [
|
15
|
-
"choice",
|
16
|
-
"actionrequest",
|
17
|
-
"bool",
|
18
|
-
"number",
|
19
|
-
"dict",
|
20
|
-
"str",
|
21
|
-
]
|
22
|
-
|
23
|
-
|
24
|
-
class Validator(BaseModel):
|
25
|
-
"""
|
26
|
-
rules contain all rules that this validator can apply to data
|
27
|
-
the order determines which rule gets applied in what sequence.
|
28
|
-
notice, if a rule is not present in the orders, it will not be applied.
|
29
|
-
"""
|
30
|
-
|
31
|
-
rules: dict[str, Rule] = Field(
|
32
|
-
default=rules_,
|
33
|
-
description="The rules to be used for validation.",
|
34
|
-
)
|
35
|
-
|
36
|
-
order: list[str] = Field(
|
37
|
-
default=order_,
|
38
|
-
description="The order in which the rules should be applied.",
|
39
|
-
)
|
40
|
-
|
41
|
-
async def validate(self, value, *args, strict=False, **kwargs):
|
42
|
-
|
43
|
-
for i in self.order:
|
44
|
-
if i in self.rules:
|
45
|
-
try:
|
46
|
-
if (
|
47
|
-
a := await self.rules[i].validate(value, *args, **kwargs)
|
48
|
-
is not None
|
49
|
-
):
|
50
|
-
return a
|
51
|
-
except Exception as e:
|
52
|
-
raise ValueError(f"failed to validate field") from e
|
53
|
-
if strict:
|
54
|
-
raise ValueError(f"failed to validate field")
|
55
|
-
|
56
|
-
return value
|
@@ -1,54 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
|
3
|
-
|
4
|
-
class WorkQueue:
|
5
|
-
|
6
|
-
def __init__(self, capacity=5):
|
7
|
-
|
8
|
-
self.queue = asyncio.Queue()
|
9
|
-
self._stop_event = asyncio.Event()
|
10
|
-
self.capacity = capacity
|
11
|
-
self.semaphore = asyncio.Semaphore(capacity)
|
12
|
-
|
13
|
-
async def enqueue(self, work) -> None:
|
14
|
-
await self.queue.put(work)
|
15
|
-
|
16
|
-
async def dequeue(self):
|
17
|
-
return await self.queue.get()
|
18
|
-
|
19
|
-
async def join(self) -> None:
|
20
|
-
await self.queue.join()
|
21
|
-
|
22
|
-
async def stop(self) -> None:
|
23
|
-
self._stop_event.set()
|
24
|
-
|
25
|
-
@property
|
26
|
-
def available_capacity(self):
|
27
|
-
if (a:= self.capacity - self.queue.qsize()) > 0:
|
28
|
-
return a
|
29
|
-
return None
|
30
|
-
|
31
|
-
@property
|
32
|
-
def stopped(self) -> bool:
|
33
|
-
return self._stop_event.is_set()
|
34
|
-
|
35
|
-
|
36
|
-
async def process(self, refresh_time=1) -> None:
|
37
|
-
tasks = set()
|
38
|
-
while self.queue.qsize() > 0 and not self.stopped:
|
39
|
-
if not self.available_capacity and tasks:
|
40
|
-
_, done = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
41
|
-
tasks.difference_update(done)
|
42
|
-
|
43
|
-
async with self.semaphore:
|
44
|
-
next = await self.dequeue()
|
45
|
-
if next is None:
|
46
|
-
break
|
47
|
-
task = asyncio.create_task(next.perform())
|
48
|
-
tasks.add(task)
|
49
|
-
|
50
|
-
if tasks:
|
51
|
-
await asyncio.wait(tasks)
|
52
|
-
await asyncio.sleep(refresh_time)
|
53
|
-
|
54
|
-
|
@@ -1,73 +0,0 @@
|
|
1
|
-
from collections import deque
|
2
|
-
from enum import Enum
|
3
|
-
import asyncio
|
4
|
-
from typing import Any
|
5
|
-
|
6
|
-
from lionagi.libs import SysUtil
|
7
|
-
from lionagi.core.generic import BaseComponent
|
8
|
-
|
9
|
-
from .async_queue import WorkQueue
|
10
|
-
|
11
|
-
class WorkStatus(str, Enum):
|
12
|
-
"""Enum to represent different statuses of work."""
|
13
|
-
|
14
|
-
PENDING = "PENDING"
|
15
|
-
IN_PROGRESS = "IN_PROGRESS"
|
16
|
-
COMPLETED = "COMPLETED"
|
17
|
-
FAILED = "FAILED"
|
18
|
-
|
19
|
-
|
20
|
-
class Work(BaseComponent):
|
21
|
-
status: WorkStatus = WorkStatus.PENDING
|
22
|
-
result: Any = None
|
23
|
-
error: Any = None
|
24
|
-
async_task: asyncio.Task | None = None
|
25
|
-
completion_timestamp: str | None = None
|
26
|
-
|
27
|
-
async def perform(self):
|
28
|
-
try:
|
29
|
-
result = await self.async_task
|
30
|
-
self.result = result
|
31
|
-
self.status = WorkStatus.COMPLETED
|
32
|
-
self.async_task = None
|
33
|
-
except Exception as e:
|
34
|
-
self.error = e
|
35
|
-
self.status = WorkStatus.FAILED
|
36
|
-
finally:
|
37
|
-
self.completion_timestamp = SysUtil.get_timestamp()
|
38
|
-
|
39
|
-
|
40
|
-
def __str__(self):
|
41
|
-
return f"Work(id={self.id_}, status={self.status}, created_at={self.timestamp}, completed_at={self.completion_timestamp})"
|
42
|
-
|
43
|
-
class WorkLog:
|
44
|
-
|
45
|
-
def __init__(self, capacity=5, pile=None):
|
46
|
-
self.pile = pile or {}
|
47
|
-
self.pending_sequence = deque()
|
48
|
-
self.queue = WorkQueue(capacity=capacity)
|
49
|
-
|
50
|
-
async def append(self, work: Work):
|
51
|
-
self.pile[work.id_] = work
|
52
|
-
self.pending_sequence.append(work.id_)
|
53
|
-
|
54
|
-
async def forward(self):
|
55
|
-
if not self.queue.available_capacity:
|
56
|
-
return
|
57
|
-
else:
|
58
|
-
while self.pending_sequence and self.queue.available_capacity:
|
59
|
-
work = self.pile[self.pending_sequence.popleft()]
|
60
|
-
work.status = WorkStatus.IN_PROGRESS
|
61
|
-
await self.queue.enqueue(work)
|
62
|
-
|
63
|
-
|
64
|
-
async def stop(self):
|
65
|
-
await self.queue.stop()
|
66
|
-
|
67
|
-
@property
|
68
|
-
def stopped(self):
|
69
|
-
return self.queue.stopped
|
70
|
-
|
71
|
-
@property
|
72
|
-
def completed_work(self):
|
73
|
-
return {k: v for k, v in self.pile.items() if v.status == WorkStatus.COMPLETED}
|
@@ -1,67 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from typing import Callable, Any
|
3
|
-
from lionagi.libs import func_call
|
4
|
-
from functools import wraps
|
5
|
-
from pydantic import Field
|
6
|
-
|
7
|
-
from lionagi.core.generic import BaseComponent
|
8
|
-
|
9
|
-
from .schema import Work, WorkLog
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
class WorkFunction:
|
14
|
-
|
15
|
-
def __init__(
|
16
|
-
self, assignment, function, retry_kwargs=None,
|
17
|
-
instruction = None, capacity=5
|
18
|
-
):
|
19
|
-
|
20
|
-
self.assignment = assignment
|
21
|
-
self.function = function
|
22
|
-
self.retry_kwargs = retry_kwargs or {}
|
23
|
-
self.instruction = instruction or function.__doc__
|
24
|
-
self.worklog = WorkLog(capacity=capacity)
|
25
|
-
|
26
|
-
|
27
|
-
@property
|
28
|
-
def name(self):
|
29
|
-
return self.function.__name__
|
30
|
-
|
31
|
-
async def perform(self, *args, **kwargs):
|
32
|
-
kwargs = {**self.retry_kwargs, **kwargs}
|
33
|
-
return await func_call.rcall(self.function, *args, **kwargs)
|
34
|
-
|
35
|
-
async def process(self, refresh_time=1):
|
36
|
-
await self.worklog.process(refresh_time=refresh_time)
|
37
|
-
|
38
|
-
async def stop(self):
|
39
|
-
await self.worklog.queue.stop()
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def work(assignment, capacity=5):
|
44
|
-
def decorator(func):
|
45
|
-
@wraps(func)
|
46
|
-
async def wrapper(self, *args, retry_kwargs=None, instruction=None, **kwargs):
|
47
|
-
if getattr(self, "work_functions", None) is None:
|
48
|
-
self.work_functions = {}
|
49
|
-
|
50
|
-
if func.__name__ not in self.work_functions:
|
51
|
-
self.work_functions[func.__name__] = WorkFunction(
|
52
|
-
assignment=assignment,
|
53
|
-
function=func,
|
54
|
-
retry_kwargs=retry_kwargs or {},
|
55
|
-
instruction=instruction or func.__doc__,
|
56
|
-
capacity=capacity
|
57
|
-
)
|
58
|
-
|
59
|
-
work_func: WorkFunction = self.work_functions[func.__name__]
|
60
|
-
task = asyncio.create_task(work_func.perform(*args, **kwargs))
|
61
|
-
work = Work(async_task=task)
|
62
|
-
work_func: WorkFunction = self.work_functions[func.__name__]
|
63
|
-
await work_func.worklog.append(work)
|
64
|
-
return True
|
65
|
-
|
66
|
-
return wrapper
|
67
|
-
return decorator
|
@@ -1,56 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
from lionagi import logging as _logging
|
3
|
-
from .work_function import WorkFunction
|
4
|
-
import asyncio
|
5
|
-
|
6
|
-
class Worker(ABC):
|
7
|
-
# This is a class that will be used to create a worker object
|
8
|
-
# work_functions are keyed by assignment {assignment: WorkFunction}
|
9
|
-
|
10
|
-
name: str = "Worker"
|
11
|
-
work_functions: dict[str, WorkFunction] = {}
|
12
|
-
|
13
|
-
def __init__(self) -> None:
|
14
|
-
self.stopped = False
|
15
|
-
|
16
|
-
async def stop(self):
|
17
|
-
self.stopped = True
|
18
|
-
_logging.info(f"Stopping worker {self.name}")
|
19
|
-
non_stopped_ = []
|
20
|
-
|
21
|
-
for func in self.work_functions.values():
|
22
|
-
worklog = func.worklog
|
23
|
-
await worklog.stop()
|
24
|
-
if not worklog.stopped:
|
25
|
-
non_stopped_.append(func.name)
|
26
|
-
|
27
|
-
if len(non_stopped_) > 0:
|
28
|
-
_logging.error(f"Could not stop worklogs: {non_stopped_}")
|
29
|
-
|
30
|
-
_logging.info(f"Stopped worker {self.name}")
|
31
|
-
|
32
|
-
|
33
|
-
async def process(self, refresh_time=1):
|
34
|
-
while not self.stopped:
|
35
|
-
tasks = [
|
36
|
-
asyncio.create_task(func.process(refresh_time=refresh_time))
|
37
|
-
for func in self.work_functions.values()
|
38
|
-
]
|
39
|
-
await asyncio.wait(tasks)
|
40
|
-
await asyncio.sleep(refresh_time)
|
41
|
-
|
42
|
-
|
43
|
-
# # Example
|
44
|
-
# from lionagi import Session
|
45
|
-
# from lionagi.experimental.work.work_function import work
|
46
|
-
|
47
|
-
|
48
|
-
# class MyWorker(Worker):
|
49
|
-
|
50
|
-
# @work(assignment="instruction, context -> response")
|
51
|
-
# async def chat(instruction=None, context=None):
|
52
|
-
# session = Session()
|
53
|
-
# return await session.chat(instruction=instruction, context=context)
|
54
|
-
|
55
|
-
|
56
|
-
# await a.chat(instruction="Hello", context={})
|