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.
Files changed (78) hide show
  1. lionagi/libs/token_transform/__init__.py +0 -0
  2. lionagi/libs/token_transform/llmlingua.py +1 -0
  3. lionagi/libs/token_transform/perplexity.py +439 -0
  4. lionagi/libs/token_transform/synthlang.py +409 -0
  5. lionagi/operations/ReAct/ReAct.py +126 -0
  6. lionagi/operations/ReAct/utils.py +28 -0
  7. lionagi/operations/__init__.py +1 -9
  8. lionagi/operations/_act/act.py +73 -0
  9. lionagi/operations/chat/__init__.py +3 -0
  10. lionagi/operations/chat/chat.py +173 -0
  11. lionagi/operations/communicate/__init__.py +0 -0
  12. lionagi/operations/communicate/communicate.py +108 -0
  13. lionagi/operations/instruct/__init__.py +3 -0
  14. lionagi/operations/instruct/instruct.py +29 -0
  15. lionagi/operations/interpret/__init__.py +3 -0
  16. lionagi/operations/interpret/interpret.py +39 -0
  17. lionagi/operations/operate/__init__.py +3 -0
  18. lionagi/operations/operate/operate.py +194 -0
  19. lionagi/operations/parse/__init__.py +3 -0
  20. lionagi/operations/parse/parse.py +89 -0
  21. lionagi/operations/plan/plan.py +3 -3
  22. lionagi/operations/select/__init__.py +0 -4
  23. lionagi/operations/select/select.py +11 -30
  24. lionagi/operations/select/utils.py +13 -2
  25. lionagi/operations/translate/__init__.py +0 -0
  26. lionagi/operations/translate/translate.py +47 -0
  27. lionagi/operations/types.py +16 -0
  28. lionagi/operatives/action/manager.py +115 -93
  29. lionagi/operatives/action/request_response_model.py +31 -0
  30. lionagi/operatives/action/tool.py +50 -20
  31. lionagi/operatives/strategies/__init__.py +3 -0
  32. lionagi/protocols/_concepts.py +1 -1
  33. lionagi/protocols/adapters/adapter.py +25 -0
  34. lionagi/protocols/adapters/json_adapter.py +107 -27
  35. lionagi/protocols/adapters/pandas_/csv_adapter.py +55 -11
  36. lionagi/protocols/adapters/pandas_/excel_adapter.py +52 -10
  37. lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +54 -4
  38. lionagi/protocols/adapters/pandas_/pd_series_adapter.py +40 -0
  39. lionagi/protocols/generic/element.py +1 -1
  40. lionagi/protocols/generic/pile.py +5 -8
  41. lionagi/protocols/graph/edge.py +1 -1
  42. lionagi/protocols/graph/graph.py +16 -8
  43. lionagi/protocols/graph/node.py +1 -1
  44. lionagi/protocols/mail/exchange.py +126 -15
  45. lionagi/protocols/mail/mail.py +33 -0
  46. lionagi/protocols/mail/mailbox.py +62 -0
  47. lionagi/protocols/mail/manager.py +97 -41
  48. lionagi/protocols/mail/package.py +57 -3
  49. lionagi/protocols/messages/action_request.py +77 -26
  50. lionagi/protocols/messages/action_response.py +55 -26
  51. lionagi/protocols/messages/assistant_response.py +50 -15
  52. lionagi/protocols/messages/base.py +36 -0
  53. lionagi/protocols/messages/instruction.py +175 -145
  54. lionagi/protocols/messages/manager.py +152 -56
  55. lionagi/protocols/messages/message.py +61 -25
  56. lionagi/protocols/messages/system.py +54 -19
  57. lionagi/service/imodel.py +24 -0
  58. lionagi/session/branch.py +1116 -939
  59. lionagi/utils.py +1 -0
  60. lionagi/version.py +1 -1
  61. {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/METADATA +1 -1
  62. {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/RECORD +75 -56
  63. lionagi/libs/compress/models.py +0 -66
  64. lionagi/libs/compress/utils.py +0 -69
  65. lionagi/operations/select/prompt.py +0 -5
  66. /lionagi/{libs/compress → operations/ReAct}/__init__.py +0 -0
  67. /lionagi/operations/{strategies → _act}/__init__.py +0 -0
  68. /lionagi/{operations → operatives}/strategies/base.py +0 -0
  69. /lionagi/{operations → operatives}/strategies/concurrent.py +0 -0
  70. /lionagi/{operations → operatives}/strategies/concurrent_chunk.py +0 -0
  71. /lionagi/{operations → operatives}/strategies/concurrent_sequential_chunk.py +0 -0
  72. /lionagi/{operations → operatives}/strategies/params.py +0 -0
  73. /lionagi/{operations → operatives}/strategies/sequential.py +0 -0
  74. /lionagi/{operations → operatives}/strategies/sequential_chunk.py +0 -0
  75. /lionagi/{operations → operatives}/strategies/sequential_concurrent_chunk.py +0 -0
  76. /lionagi/{operations → operatives}/strategies/utils.py +0 -0
  77. {lionagi-0.6.1.dist-info → lionagi-0.7.1.dist-info}/WHEEL +0 -0
  78. {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, Field
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
- class SelectionModel(BaseModel):
19
- """Model representing the selection output."""
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
- operative_model=SelectionModel,
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.")
@@ -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 EventStatus, Execution
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
- to_list(kwargs, dropna=True, flatten=True, use_values=True)
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
- """Check if a tool is registered in the registry.
38
-
39
- Supports checking by:
40
- - Tool object
41
- - Tool name (string)
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 tool is registered, False otherwise.
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
- self,
60
- tool: FuncTool,
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: The tool to register (Tool object or callable).
70
- update: If True, update existing tool; if False, raise error.
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 object or callable.
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("Please register a Tool object or callable.")
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
- """Register multiple tools in the registry.
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: Single tool or list of tools to register.
103
- update: If True, update existing tools; if False, raise error.
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 any tool is already registered.
107
- TypeError: If any tool is not a Tool object or callable.
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(tool, update=update)
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
- if not isinstance(action_request, ActionRequest | ActionRequestModel):
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
- tool = self.registry.get(action_request.function, None)
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
- f"Function {action_request.function} is not registered."
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, func_call: ActionRequestModel | ActionRequest
132
- ) -> FunctionCalling | Execution | None:
133
- """Invoke a tool based on the provided function call.
157
+ self,
158
+ func_call: ActionRequestModel | ActionRequest,
159
+ ) -> FunctionCalling:
160
+ """
161
+ High-level API to parse and run a function call.
134
162
 
135
- 1. Matches function call to registered tool
136
- 2. Creates FunctionCalling instance
137
- 3. Invokes function with arguments
138
- 4. Logs execution details
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: Function call specification in supported format.
143
- log_manager: Optional logger for execution tracking.
169
+ func_call: The action request model or ActionRequest object.
144
170
 
145
171
  Returns:
146
- Result of tool invocation after processing pipeline.
147
-
148
- Raises:
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
- """List all tool schemas currently registered.
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
- """Retrieve the schema for specific tools or all tools.
189
+ """
190
+ Retrieve schemas for a subset of tools or for all.
180
191
 
181
192
  Args:
182
- tools: Specification of which tools to retrieve schemas for.
183
- If True, return all tools. If False, return empty dict.
184
- Can also be a specific tool or list of tools.
185
- **kwargs: Additional keyword arguments to include in output.
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
- Dictionary containing tool schemas and additional kwargs.
203
+ dict: e.g., {"tools": [list of schemas]}
189
204
 
190
205
  Raises:
191
- ValueError: If a specified tool is not registered.
192
- TypeError: If an unsupported tool type is provided.
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] | list[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