lionagi 0.6.1__py3-none-any.whl → 0.7.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.
- lionagi/libs/token_transform/__init__.py +0 -0
- lionagi/libs/token_transform/llmlingua.py +1 -0
- lionagi/libs/token_transform/perplexity.py +439 -0
- lionagi/libs/token_transform/synthlang.py +409 -0
- lionagi/operations/ReAct/ReAct.py +126 -0
- lionagi/operations/ReAct/utils.py +28 -0
- lionagi/operations/__init__.py +1 -9
- lionagi/operations/_act/act.py +73 -0
- lionagi/operations/chat/__init__.py +3 -0
- lionagi/operations/chat/chat.py +173 -0
- lionagi/operations/communicate/__init__.py +0 -0
- lionagi/operations/communicate/communicate.py +108 -0
- lionagi/operations/instruct/__init__.py +3 -0
- lionagi/operations/instruct/instruct.py +29 -0
- lionagi/operations/interpret/__init__.py +3 -0
- lionagi/operations/interpret/interpret.py +39 -0
- lionagi/operations/operate/__init__.py +3 -0
- lionagi/operations/operate/operate.py +194 -0
- lionagi/operations/parse/__init__.py +3 -0
- lionagi/operations/parse/parse.py +89 -0
- lionagi/operations/plan/plan.py +3 -3
- lionagi/operations/select/__init__.py +0 -4
- lionagi/operations/select/select.py +11 -30
- lionagi/operations/select/utils.py +13 -2
- lionagi/operations/translate/__init__.py +0 -0
- lionagi/operations/translate/translate.py +47 -0
- lionagi/operations/types.py +16 -0
- lionagi/operatives/action/manager.py +115 -93
- lionagi/operatives/action/request_response_model.py +31 -0
- lionagi/operatives/action/tool.py +50 -20
- lionagi/operatives/strategies/__init__.py +3 -0
- lionagi/protocols/_concepts.py +1 -1
- lionagi/protocols/adapters/adapter.py +25 -0
- lionagi/protocols/adapters/json_adapter.py +107 -27
- lionagi/protocols/adapters/pandas_/csv_adapter.py +55 -11
- lionagi/protocols/adapters/pandas_/excel_adapter.py +52 -10
- lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +54 -4
- lionagi/protocols/adapters/pandas_/pd_series_adapter.py +40 -0
- lionagi/protocols/generic/element.py +1 -1
- lionagi/protocols/generic/pile.py +5 -8
- lionagi/protocols/graph/edge.py +1 -1
- lionagi/protocols/graph/graph.py +16 -8
- lionagi/protocols/graph/node.py +1 -1
- lionagi/protocols/mail/exchange.py +126 -15
- lionagi/protocols/mail/mail.py +33 -0
- lionagi/protocols/mail/mailbox.py +62 -0
- lionagi/protocols/mail/manager.py +97 -41
- lionagi/protocols/mail/package.py +57 -3
- lionagi/protocols/messages/action_request.py +77 -26
- lionagi/protocols/messages/action_response.py +55 -26
- lionagi/protocols/messages/assistant_response.py +50 -15
- lionagi/protocols/messages/base.py +36 -0
- lionagi/protocols/messages/instruction.py +175 -145
- lionagi/protocols/messages/manager.py +152 -56
- lionagi/protocols/messages/message.py +61 -25
- lionagi/protocols/messages/system.py +54 -19
- lionagi/service/imodel.py +24 -0
- lionagi/session/branch.py +1116 -939
- lionagi/utils.py +1 -0
- lionagi/version.py +1 -1
- {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/METADATA +1 -1
- {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/RECORD +75 -56
- lionagi/libs/compress/models.py +0 -66
- lionagi/libs/compress/utils.py +0 -69
- lionagi/operations/select/prompt.py +0 -5
- /lionagi/{libs/compress → operations/ReAct}/__init__.py +0 -0
- /lionagi/operations/{strategies → _act}/__init__.py +0 -0
- /lionagi/{operations → operatives}/strategies/base.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/concurrent_sequential_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/params.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/sequential_concurrent_chunk.py +0 -0
- /lionagi/{operations → operatives}/strategies/utils.py +0 -0
- {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/WHEEL +0 -0
- {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -2,56 +2,37 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
-
|
6
5
|
from enum import Enum
|
7
|
-
from typing import Any
|
6
|
+
from typing import TYPE_CHECKING, Any
|
8
7
|
|
9
|
-
from pydantic import BaseModel
|
8
|
+
from pydantic import BaseModel
|
10
9
|
|
11
10
|
from lionagi.operatives.types import Instruct
|
12
|
-
from lionagi.session.branch import Branch
|
13
|
-
|
14
|
-
from .prompt import PROMPT
|
15
|
-
from .utils import parse_selection, parse_to_representation
|
16
11
|
|
12
|
+
from .utils import SelectionModel
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
selected: list[Any] = Field(default_factory=list)
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from lionagi.session.branch import Branch
|
22
16
|
|
23
17
|
|
24
18
|
async def select(
|
19
|
+
branch: "Branch",
|
25
20
|
instruct: Instruct | dict[str, Any],
|
26
21
|
choices: list[str] | type[Enum] | dict[str, Any],
|
27
22
|
max_num_selections: int = 1,
|
28
|
-
branch: Branch | None = None,
|
29
23
|
branch_kwargs: dict[str, Any] | None = None,
|
30
24
|
return_branch: bool = False,
|
31
25
|
verbose: bool = False,
|
32
26
|
**kwargs: Any,
|
33
|
-
) -> SelectionModel | tuple[SelectionModel, Branch]:
|
34
|
-
"""Perform a selection operation from given choices.
|
35
|
-
|
36
|
-
Args:
|
37
|
-
instruct: Instruction model or dictionary.
|
38
|
-
choices: Options to select from.
|
39
|
-
max_num_selections: Maximum selections allowed.
|
40
|
-
branch: Existing branch or None to create a new one.
|
41
|
-
branch_kwargs: Additional arguments for branch creation.
|
42
|
-
return_branch: If True, return the branch with the selection.
|
43
|
-
verbose: Whether to enable verbose output.
|
44
|
-
**kwargs: Additional keyword arguments.
|
45
|
-
|
46
|
-
Returns:
|
47
|
-
A SelectionModel instance, optionally with the branch.
|
48
|
-
"""
|
27
|
+
) -> SelectionModel | tuple[SelectionModel, "Branch"]:
|
49
28
|
if verbose:
|
50
29
|
print(f"Starting selection with up to {max_num_selections} choices.")
|
51
30
|
|
31
|
+
from .utils import SelectionModel, parse_selection, parse_to_representation
|
32
|
+
|
52
33
|
branch = branch or Branch(**(branch_kwargs or {}))
|
53
34
|
selections, contents = parse_to_representation(choices)
|
54
|
-
prompt = PROMPT.format(
|
35
|
+
prompt = SelectionModel.PROMPT.format(
|
55
36
|
max_num_selections=max_num_selections, choices=selections
|
56
37
|
)
|
57
38
|
|
@@ -73,7 +54,7 @@ async def select(
|
|
73
54
|
instruct["context"] = context
|
74
55
|
|
75
56
|
response_model: SelectionModel = await branch.operate(
|
76
|
-
|
57
|
+
response_format=SelectionModel,
|
77
58
|
**kwargs,
|
78
59
|
**instruct,
|
79
60
|
)
|
@@ -4,14 +4,25 @@
|
|
4
4
|
|
5
5
|
import inspect
|
6
6
|
from enum import Enum
|
7
|
-
from typing import Any
|
7
|
+
from typing import Any, ClassVar
|
8
8
|
|
9
|
-
from pydantic import BaseModel, JsonValue
|
9
|
+
from pydantic import BaseModel, Field, JsonValue
|
10
10
|
|
11
11
|
from lionagi.libs.validate.string_similarity import string_similarity
|
12
12
|
from lionagi.utils import is_same_dtype
|
13
13
|
|
14
14
|
|
15
|
+
# TODO: Make select a field to be added into a model, much like reason and action
|
16
|
+
class SelectionModel(BaseModel):
|
17
|
+
"""Model representing the selection output."""
|
18
|
+
|
19
|
+
PROMPT: ClassVar[str] = (
|
20
|
+
"Please select up to {max_num_selections} items from the following list {choices}. Provide the selection(s) into appropriate field in format required, and no comments from you"
|
21
|
+
)
|
22
|
+
|
23
|
+
selected: list[Any] = Field(default_factory=list)
|
24
|
+
|
25
|
+
|
15
26
|
def parse_to_representation(
|
16
27
|
choices: Enum | dict | list | tuple | set,
|
17
28
|
) -> tuple[list[str], JsonValue]:
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Literal
|
2
|
+
|
3
|
+
from lionagi.service.imodel import iModel
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from lionagi.session.branch import Branch
|
7
|
+
|
8
|
+
|
9
|
+
async def translate(
|
10
|
+
branch: "Branch",
|
11
|
+
text: str,
|
12
|
+
technique: Literal["SynthLang"] = "SynthLang",
|
13
|
+
technique_kwargs: dict = None,
|
14
|
+
compress: bool = False,
|
15
|
+
chat_model: iModel = None,
|
16
|
+
compress_model: iModel = None,
|
17
|
+
compression_ratio: float = 0.2,
|
18
|
+
compress_kwargs=None,
|
19
|
+
verbose: bool = True,
|
20
|
+
new_branch: bool = True,
|
21
|
+
**kwargs,
|
22
|
+
):
|
23
|
+
if technique == "SynthLang":
|
24
|
+
from lionagi.libs.token_transform.synthlang import (
|
25
|
+
translate_to_synthlang,
|
26
|
+
)
|
27
|
+
|
28
|
+
if not technique_kwargs:
|
29
|
+
technique_kwargs = {}
|
30
|
+
if not technique_kwargs.get("template_name"):
|
31
|
+
technique_kwargs["template_name"] = "symbolic_systems"
|
32
|
+
|
33
|
+
technique_kwargs = {**technique_kwargs, **kwargs}
|
34
|
+
|
35
|
+
return await translate_to_synthlang(
|
36
|
+
text=text,
|
37
|
+
compress=compress,
|
38
|
+
chat_model=chat_model or branch.chat_model,
|
39
|
+
compress_model=compress_model,
|
40
|
+
compression_ratio=compression_ratio,
|
41
|
+
compress_kwargs=compress_kwargs,
|
42
|
+
verbose=verbose,
|
43
|
+
branch=branch if not new_branch else None,
|
44
|
+
**technique_kwargs,
|
45
|
+
)
|
46
|
+
|
47
|
+
raise ValueError(f"Technique {technique} is not supported.")
|
lionagi/operations/types.py
CHANGED
@@ -3,11 +3,27 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
from .brainstorm.brainstorm import brainstorm
|
6
|
+
from .chat.chat import chat
|
7
|
+
from .communicate.communicate import communicate
|
8
|
+
from .instruct.instruct import instruct
|
9
|
+
from .interpret.interpret import interpret
|
10
|
+
from .operate.operate import operate
|
11
|
+
from .parse.parse import parse
|
6
12
|
from .plan.plan import plan
|
13
|
+
from .ReAct.ReAct import ReAct
|
7
14
|
from .select.select import select
|
15
|
+
from .translate.translate import translate
|
8
16
|
|
9
17
|
__all__ = (
|
10
18
|
"brainstorm",
|
11
19
|
"plan",
|
12
20
|
"select",
|
21
|
+
"chat",
|
22
|
+
"communicate",
|
23
|
+
"instruct",
|
24
|
+
"interpret",
|
25
|
+
"operate",
|
26
|
+
"parse",
|
27
|
+
"ReAct",
|
28
|
+
"translate",
|
13
29
|
)
|
@@ -2,11 +2,16 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
+
"""
|
6
|
+
Defines the `ActionManager` class, a specialized Manager that registers
|
7
|
+
`Tool` objects (or callables) for function invocation. It can match
|
8
|
+
incoming requests (ActionRequest) to a registered tool, then run it.
|
9
|
+
"""
|
10
|
+
|
5
11
|
from typing import Any
|
6
12
|
|
7
13
|
from lionagi.protocols._concepts import Manager
|
8
|
-
from lionagi.protocols.generic.event import
|
9
|
-
from lionagi.protocols.generic.log import Log
|
14
|
+
from lionagi.protocols.generic.event import Execution
|
10
15
|
from lionagi.protocols.messages.action_request import ActionRequest
|
11
16
|
from lionagi.utils import to_list
|
12
17
|
|
@@ -18,9 +23,22 @@ __all__ = ("ActionManager",)
|
|
18
23
|
|
19
24
|
|
20
25
|
class ActionManager(Manager):
|
26
|
+
"""
|
27
|
+
A manager that registers function-based tools and invokes them
|
28
|
+
when triggered by an ActionRequest. Tools can be registered
|
29
|
+
individually or in bulk, and each tool must have a unique name.
|
30
|
+
"""
|
21
31
|
|
22
32
|
def __init__(self, *args: FuncTool, **kwargs) -> None:
|
33
|
+
"""
|
34
|
+
Create an ActionManager, optionally registering initial tools.
|
23
35
|
|
36
|
+
Args:
|
37
|
+
*args (FuncTool):
|
38
|
+
A variable number of tools or callables.
|
39
|
+
**kwargs:
|
40
|
+
Additional named arguments that are also considered tools.
|
41
|
+
"""
|
24
42
|
super().__init__()
|
25
43
|
self.registry: dict[str, Tool] = {}
|
26
44
|
|
@@ -28,24 +46,19 @@ class ActionManager(Manager):
|
|
28
46
|
if args:
|
29
47
|
tools.extend(to_list(args, dropna=True, flatten=True))
|
30
48
|
if kwargs:
|
31
|
-
tools.extend(
|
32
|
-
|
33
|
-
)
|
49
|
+
tools.extend(to_list(kwargs.values(), dropna=True, flatten=True))
|
50
|
+
|
34
51
|
self.register_tools(tools, update=True)
|
35
52
|
|
36
53
|
def __contains__(self, tool: FuncToolRef) -> bool:
|
37
|
-
"""
|
38
|
-
|
39
|
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
- Callable function
|
43
|
-
|
44
|
-
Args:
|
45
|
-
tool: The tool to check for registration.
|
54
|
+
"""
|
55
|
+
Check if a tool is registered, by either:
|
56
|
+
- The Tool object itself,
|
57
|
+
- A string name for the function,
|
58
|
+
- Or the callable's __name__.
|
46
59
|
|
47
60
|
Returns:
|
48
|
-
bool: True if
|
61
|
+
bool: True if found, else False.
|
49
62
|
"""
|
50
63
|
if isinstance(tool, Tool):
|
51
64
|
return tool.function in self.registry
|
@@ -55,24 +68,21 @@ class ActionManager(Manager):
|
|
55
68
|
return tool.__name__ in self.registry
|
56
69
|
return False
|
57
70
|
|
58
|
-
def register_tool(
|
59
|
-
|
60
|
-
tool
|
61
|
-
update: bool = False,
|
62
|
-
) -> None:
|
63
|
-
"""Register a single tool in the registry.
|
64
|
-
|
65
|
-
If the tool is a callable function, it is automatically converted
|
66
|
-
to a Tool object. Existing tools can be updated if update=True.
|
71
|
+
def register_tool(self, tool: FuncTool, update: bool = False) -> None:
|
72
|
+
"""
|
73
|
+
Register a single tool/callable in the manager.
|
67
74
|
|
68
75
|
Args:
|
69
|
-
tool
|
70
|
-
|
76
|
+
tool (FuncTool):
|
77
|
+
A `Tool` object or a raw callable function.
|
78
|
+
update (bool):
|
79
|
+
If True, allow replacing an existing tool with the same name.
|
71
80
|
|
72
81
|
Raises:
|
73
82
|
ValueError: If tool already registered and update=False.
|
74
|
-
TypeError: If tool is not a Tool
|
83
|
+
TypeError: If `tool` is not a Tool or callable.
|
75
84
|
"""
|
85
|
+
# Check if tool already exists
|
76
86
|
if not update and tool in self:
|
77
87
|
name = None
|
78
88
|
if isinstance(tool, Tool):
|
@@ -81,93 +91,93 @@ class ActionManager(Manager):
|
|
81
91
|
name = tool.__name__
|
82
92
|
raise ValueError(f"Tool {name} is already registered.")
|
83
93
|
|
94
|
+
# Convert raw callable to a Tool if needed
|
84
95
|
if callable(tool):
|
85
96
|
tool = Tool(func_callable=tool)
|
86
97
|
if not isinstance(tool, Tool):
|
87
|
-
raise TypeError(
|
88
|
-
|
98
|
+
raise TypeError(
|
99
|
+
"Must provide a `Tool` object or a callable function."
|
100
|
+
)
|
89
101
|
self.registry[tool.function] = tool
|
90
102
|
|
91
103
|
def register_tools(
|
92
|
-
self,
|
93
|
-
tools: list[FuncTool] | FuncTool,
|
94
|
-
update: bool = False,
|
104
|
+
self, tools: list[FuncTool] | FuncTool, update: bool = False
|
95
105
|
) -> None:
|
96
|
-
"""
|
97
|
-
|
98
|
-
Handles both single tools and lists of tools. Each tool can be
|
99
|
-
either a Tool object or a callable function.
|
106
|
+
"""
|
107
|
+
Register multiple tools at once.
|
100
108
|
|
101
109
|
Args:
|
102
|
-
tools
|
103
|
-
|
110
|
+
tools (list[FuncTool] | FuncTool):
|
111
|
+
A single or list of tools/callables.
|
112
|
+
update (bool):
|
113
|
+
If True, allow updating existing tools.
|
104
114
|
|
105
115
|
Raises:
|
106
|
-
ValueError: If
|
107
|
-
TypeError: If any
|
116
|
+
ValueError: If a duplicate tool is found and update=False.
|
117
|
+
TypeError: If any item is not a Tool or callable.
|
108
118
|
"""
|
109
119
|
tools_list = tools if isinstance(tools, list) else [tools]
|
110
|
-
|
111
|
-
self.register_tool(
|
112
|
-
for tool in to_list(tools_list, dropna=True, flatten=True)
|
113
|
-
]
|
120
|
+
for t in tools_list:
|
121
|
+
self.register_tool(t, update=update)
|
114
122
|
|
115
123
|
def match_tool(
|
116
|
-
self, action_request: ActionRequest | ActionRequestModel
|
124
|
+
self, action_request: ActionRequest | ActionRequestModel | dict
|
117
125
|
) -> FunctionCalling:
|
118
|
-
|
126
|
+
"""
|
127
|
+
Convert an ActionRequest (or dict with "function"/"arguments")
|
128
|
+
into a `FunctionCalling` instance by finding the matching tool.
|
129
|
+
|
130
|
+
Raises:
|
131
|
+
TypeError: If `action_request` is an unsupported type.
|
132
|
+
ValueError: If no matching tool is found in the registry.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
FunctionCalling: The event object that can be invoked.
|
136
|
+
"""
|
137
|
+
if not isinstance(
|
138
|
+
action_request, ActionRequest | ActionRequestModel | dict
|
139
|
+
):
|
119
140
|
raise TypeError(f"Unsupported type {type(action_request)}")
|
120
141
|
|
121
|
-
|
142
|
+
func, args = None, None
|
143
|
+
if isinstance(action_request, dict):
|
144
|
+
func = action_request["function"]
|
145
|
+
args = action_request["arguments"]
|
146
|
+
else:
|
147
|
+
func = action_request.function
|
148
|
+
args = action_request.arguments
|
149
|
+
|
150
|
+
tool = self.registry.get(func, None)
|
122
151
|
if not isinstance(tool, Tool):
|
123
|
-
raise ValueError(
|
124
|
-
|
125
|
-
|
126
|
-
return FunctionCalling(
|
127
|
-
func_tool=tool, arguments=action_request.arguments
|
128
|
-
)
|
152
|
+
raise ValueError(f"Function {func} is not registered.")
|
153
|
+
|
154
|
+
return FunctionCalling(func_tool=tool, arguments=args)
|
129
155
|
|
130
156
|
async def invoke(
|
131
|
-
self,
|
132
|
-
|
133
|
-
|
157
|
+
self,
|
158
|
+
func_call: ActionRequestModel | ActionRequest,
|
159
|
+
) -> FunctionCalling:
|
160
|
+
"""
|
161
|
+
High-level API to parse and run a function call.
|
134
162
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
5. Returns result
|
163
|
+
Steps:
|
164
|
+
1) Convert `func_call` to FunctionCalling via `match_tool`.
|
165
|
+
2) `invoke()` the resulting object.
|
166
|
+
3) Return the `FunctionCalling`, which includes `execution`.
|
140
167
|
|
141
168
|
Args:
|
142
|
-
func_call:
|
143
|
-
log_manager: Optional logger for execution tracking.
|
169
|
+
func_call: The action request model or ActionRequest object.
|
144
170
|
|
145
171
|
Returns:
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
ValueError: If function not registered or call format invalid.
|
150
|
-
"""
|
151
|
-
try:
|
152
|
-
function_calling = self.match_tool(func_call)
|
153
|
-
except ValueError as e:
|
154
|
-
return Log(
|
155
|
-
content={
|
156
|
-
"event_type": "function_call",
|
157
|
-
"status": EventStatus.FAILED,
|
158
|
-
"error": str(e),
|
159
|
-
}
|
160
|
-
)
|
172
|
+
`FunctionCalling` event after it completes execution.
|
173
|
+
"""
|
174
|
+
function_calling = self.match_tool(func_call)
|
161
175
|
await function_calling.invoke()
|
162
176
|
return function_calling
|
163
177
|
|
164
178
|
@property
|
165
179
|
def schema_list(self) -> list[dict[str, Any]]:
|
166
|
-
"""
|
167
|
-
|
168
|
-
Returns:
|
169
|
-
List of OpenAI function schemas for all registered tools.
|
170
|
-
"""
|
180
|
+
"""Return the list of JSON schemas for all registered tools."""
|
171
181
|
return [tool.tool_schema for tool in self.registry.values()]
|
172
182
|
|
173
183
|
def get_tool_schema(
|
@@ -176,20 +186,25 @@ class ActionManager(Manager):
|
|
176
186
|
auto_register: bool = True,
|
177
187
|
update: bool = False,
|
178
188
|
) -> dict:
|
179
|
-
"""
|
189
|
+
"""
|
190
|
+
Retrieve schemas for a subset of tools or for all.
|
180
191
|
|
181
192
|
Args:
|
182
|
-
tools:
|
183
|
-
If True, return all tools.
|
184
|
-
|
185
|
-
|
193
|
+
tools (ToolRef):
|
194
|
+
- If True, return schema for all tools.
|
195
|
+
- If False, return an empty dict.
|
196
|
+
- If specific tool(s), returns only those schemas.
|
197
|
+
auto_register (bool):
|
198
|
+
If a tool (callable) is not yet in the registry, register if True.
|
199
|
+
update (bool):
|
200
|
+
If True, allow updating existing tools.
|
186
201
|
|
187
202
|
Returns:
|
188
|
-
|
203
|
+
dict: e.g., {"tools": [list of schemas]}
|
189
204
|
|
190
205
|
Raises:
|
191
|
-
ValueError: If
|
192
|
-
TypeError: If
|
206
|
+
ValueError: If requested tool is not found and auto_register=False.
|
207
|
+
TypeError: If tool specification is invalid.
|
193
208
|
"""
|
194
209
|
if isinstance(tools, list | tuple) and len(tools) == 1:
|
195
210
|
tools = tools[0]
|
@@ -208,10 +223,15 @@ class ActionManager(Manager):
|
|
208
223
|
tool: Any,
|
209
224
|
auto_register: bool = True,
|
210
225
|
update: bool = False,
|
211
|
-
) -> dict[str, Any] |
|
226
|
+
) -> list[dict[str, Any]] | dict[str, Any]:
|
227
|
+
"""
|
228
|
+
Internal helper to handle retrieval or registration of a single or
|
229
|
+
multiple tools, returning their schema(s).
|
230
|
+
"""
|
212
231
|
if isinstance(tool, dict):
|
213
|
-
return tool
|
232
|
+
return tool # Already a schema
|
214
233
|
if callable(tool):
|
234
|
+
# Possibly unregistered function
|
215
235
|
name = tool.__name__
|
216
236
|
if name not in self.registry:
|
217
237
|
if auto_register:
|
@@ -234,3 +254,5 @@ class ActionManager(Manager):
|
|
234
254
|
|
235
255
|
|
236
256
|
__all__ = ["ActionManager"]
|
257
|
+
|
258
|
+
# File: lionagi/operatives/action/manager.py
|
@@ -2,6 +2,12 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
+
"""
|
6
|
+
Defines Pydantic models for action requests and responses. They typically map
|
7
|
+
to conversation messages describing which function is called, with what arguments,
|
8
|
+
and any returned output.
|
9
|
+
"""
|
10
|
+
|
5
11
|
from typing import Any
|
6
12
|
|
7
13
|
from pydantic import Field, field_validator
|
@@ -28,6 +34,10 @@ __all__ = (
|
|
28
34
|
|
29
35
|
|
30
36
|
class ActionRequestModel(HashableModel):
|
37
|
+
"""
|
38
|
+
Captures a single action request, typically from a user or system message.
|
39
|
+
Includes the name of the function and the arguments to be passed.
|
40
|
+
"""
|
31
41
|
|
32
42
|
function: str | None = Field(
|
33
43
|
None,
|
@@ -43,6 +53,12 @@ class ActionRequestModel(HashableModel):
|
|
43
53
|
|
44
54
|
@field_validator("arguments", mode="before")
|
45
55
|
def validate_arguments(cls, value: Any) -> dict[str, Any]:
|
56
|
+
"""
|
57
|
+
Coerce arguments into a dictionary if possible, recursively.
|
58
|
+
|
59
|
+
Raises:
|
60
|
+
ValueError if the data can't be coerced.
|
61
|
+
"""
|
46
62
|
return to_dict(
|
47
63
|
value,
|
48
64
|
fuzzy_parse=True,
|
@@ -52,10 +68,19 @@ class ActionRequestModel(HashableModel):
|
|
52
68
|
|
53
69
|
@field_validator("function", mode="before")
|
54
70
|
def validate_function(cls, value: str) -> str:
|
71
|
+
"""
|
72
|
+
Ensure the function name is a valid non-empty string (if provided).
|
73
|
+
"""
|
55
74
|
return validate_nullable_string_field(cls, value, "function", False)
|
56
75
|
|
57
76
|
@classmethod
|
58
77
|
def create(cls, content: str):
|
78
|
+
"""
|
79
|
+
Attempt to parse a string (usually from a conversation or JSON) into
|
80
|
+
one or more ActionRequestModel instances.
|
81
|
+
|
82
|
+
If no valid structure is found, returns an empty list.
|
83
|
+
"""
|
59
84
|
try:
|
60
85
|
content = parse_action_request(content)
|
61
86
|
if content:
|
@@ -75,6 +100,10 @@ ACTION_REQUESTS_FIELD = FieldModel(
|
|
75
100
|
|
76
101
|
|
77
102
|
class ActionResponseModel(HashableModel):
|
103
|
+
"""
|
104
|
+
Encapsulates a function's output after being called. Typically
|
105
|
+
references the original function name, arguments, and the result.
|
106
|
+
"""
|
78
107
|
|
79
108
|
function: str = Field(default_factory=str, title="Function")
|
80
109
|
arguments: dict[str, Any] = Field(default_factory=dict)
|
@@ -88,3 +117,5 @@ ACTION_RESPONSES_FIELD = FieldModel(
|
|
88
117
|
title="Actions",
|
89
118
|
description="**do not fill**",
|
90
119
|
)
|
120
|
+
|
121
|
+
# File: lionagi/operatives/action/request_response_model.py
|