lionagi 0.6.1__py3-none-any.whl → 0.7.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|