lionagi 0.17.10__py3-none-any.whl → 0.18.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 +1 -2
- lionagi/_class_registry.py +1 -2
- lionagi/_errors.py +1 -2
- lionagi/adapters/async_postgres_adapter.py +2 -10
- lionagi/config.py +1 -2
- lionagi/fields/action.py +1 -2
- lionagi/fields/base.py +3 -0
- lionagi/fields/code.py +3 -0
- lionagi/fields/file.py +3 -0
- lionagi/fields/instruct.py +1 -2
- lionagi/fields/reason.py +1 -2
- lionagi/fields/research.py +3 -0
- lionagi/libs/__init__.py +1 -2
- lionagi/libs/file/__init__.py +1 -2
- lionagi/libs/file/chunk.py +1 -2
- lionagi/libs/file/process.py +1 -2
- lionagi/libs/schema/__init__.py +1 -2
- lionagi/libs/schema/as_readable.py +1 -2
- lionagi/libs/schema/extract_code_block.py +1 -2
- lionagi/libs/schema/extract_docstring.py +1 -2
- lionagi/libs/schema/function_to_schema.py +1 -2
- lionagi/libs/schema/load_pydantic_model_from_schema.py +1 -2
- lionagi/libs/schema/minimal_yaml.py +98 -0
- lionagi/libs/validate/__init__.py +1 -2
- lionagi/libs/validate/common_field_validators.py +1 -2
- lionagi/libs/validate/validate_boolean.py +1 -2
- lionagi/ln/fuzzy/_string_similarity.py +1 -2
- lionagi/ln/types.py +32 -5
- lionagi/models/__init__.py +1 -2
- lionagi/models/field_model.py +9 -1
- lionagi/models/hashable_model.py +4 -2
- lionagi/models/model_params.py +1 -2
- lionagi/models/operable_model.py +1 -2
- lionagi/models/schema_model.py +1 -2
- lionagi/operations/ReAct/ReAct.py +475 -239
- lionagi/operations/ReAct/__init__.py +1 -2
- lionagi/operations/ReAct/utils.py +4 -2
- lionagi/operations/__init__.py +1 -2
- lionagi/operations/act/__init__.py +2 -0
- lionagi/operations/act/act.py +206 -0
- lionagi/operations/brainstorm/__init__.py +1 -2
- lionagi/operations/brainstorm/brainstorm.py +1 -2
- lionagi/operations/brainstorm/prompt.py +1 -2
- lionagi/operations/builder.py +1 -2
- lionagi/operations/chat/__init__.py +1 -2
- lionagi/operations/chat/chat.py +131 -116
- lionagi/operations/communicate/communicate.py +102 -44
- lionagi/operations/flow.py +5 -6
- lionagi/operations/instruct/__init__.py +1 -2
- lionagi/operations/instruct/instruct.py +1 -2
- lionagi/operations/interpret/__init__.py +1 -2
- lionagi/operations/interpret/interpret.py +66 -22
- lionagi/operations/operate/__init__.py +1 -2
- lionagi/operations/operate/operate.py +213 -108
- lionagi/operations/parse/__init__.py +1 -2
- lionagi/operations/parse/parse.py +171 -144
- lionagi/operations/plan/__init__.py +1 -2
- lionagi/operations/plan/plan.py +1 -2
- lionagi/operations/plan/prompt.py +1 -2
- lionagi/operations/select/__init__.py +1 -2
- lionagi/operations/select/select.py +79 -19
- lionagi/operations/select/utils.py +2 -3
- lionagi/operations/types.py +120 -25
- lionagi/operations/utils.py +1 -2
- lionagi/protocols/__init__.py +1 -2
- lionagi/protocols/_concepts.py +1 -2
- lionagi/protocols/action/__init__.py +1 -2
- lionagi/protocols/action/function_calling.py +3 -20
- lionagi/protocols/action/manager.py +34 -4
- lionagi/protocols/action/tool.py +1 -2
- lionagi/protocols/contracts.py +1 -2
- lionagi/protocols/forms/__init__.py +1 -2
- lionagi/protocols/forms/base.py +1 -2
- lionagi/protocols/forms/flow.py +1 -2
- lionagi/protocols/forms/form.py +1 -2
- lionagi/protocols/forms/report.py +1 -2
- lionagi/protocols/generic/__init__.py +1 -2
- lionagi/protocols/generic/element.py +17 -65
- lionagi/protocols/generic/event.py +1 -2
- lionagi/protocols/generic/log.py +17 -14
- lionagi/protocols/generic/pile.py +3 -4
- lionagi/protocols/generic/processor.py +1 -2
- lionagi/protocols/generic/progression.py +1 -2
- lionagi/protocols/graph/__init__.py +1 -2
- lionagi/protocols/graph/edge.py +1 -2
- lionagi/protocols/graph/graph.py +1 -2
- lionagi/protocols/graph/node.py +1 -2
- lionagi/protocols/ids.py +1 -2
- lionagi/protocols/mail/__init__.py +1 -2
- lionagi/protocols/mail/exchange.py +1 -2
- lionagi/protocols/mail/mail.py +1 -2
- lionagi/protocols/mail/mailbox.py +1 -2
- lionagi/protocols/mail/manager.py +1 -2
- lionagi/protocols/mail/package.py +1 -2
- lionagi/protocols/messages/__init__.py +28 -2
- lionagi/protocols/messages/action_request.py +87 -186
- lionagi/protocols/messages/action_response.py +74 -133
- lionagi/protocols/messages/assistant_response.py +131 -161
- lionagi/protocols/messages/base.py +27 -20
- lionagi/protocols/messages/instruction.py +281 -626
- lionagi/protocols/messages/manager.py +113 -64
- lionagi/protocols/messages/message.py +88 -199
- lionagi/protocols/messages/system.py +53 -125
- lionagi/protocols/operatives/__init__.py +1 -2
- lionagi/protocols/operatives/operative.py +1 -2
- lionagi/protocols/operatives/step.py +1 -2
- lionagi/protocols/types.py +1 -4
- lionagi/service/connections/__init__.py +1 -2
- lionagi/service/connections/api_calling.py +1 -2
- lionagi/service/connections/endpoint.py +1 -10
- lionagi/service/connections/endpoint_config.py +1 -2
- lionagi/service/connections/header_factory.py +1 -2
- lionagi/service/connections/match_endpoint.py +1 -2
- lionagi/service/connections/mcp/__init__.py +1 -2
- lionagi/service/connections/mcp/wrapper.py +1 -2
- lionagi/service/connections/providers/__init__.py +1 -2
- lionagi/service/connections/providers/anthropic_.py +1 -2
- lionagi/service/connections/providers/claude_code_cli.py +1 -2
- lionagi/service/connections/providers/exa_.py +1 -2
- lionagi/service/connections/providers/nvidia_nim_.py +2 -27
- lionagi/service/connections/providers/oai_.py +30 -96
- lionagi/service/connections/providers/ollama_.py +4 -4
- lionagi/service/connections/providers/perplexity_.py +1 -2
- lionagi/service/hooks/__init__.py +1 -1
- lionagi/service/hooks/_types.py +1 -1
- lionagi/service/hooks/_utils.py +1 -1
- lionagi/service/hooks/hook_event.py +1 -1
- lionagi/service/hooks/hook_registry.py +1 -1
- lionagi/service/hooks/hooked_event.py +3 -4
- lionagi/service/imodel.py +1 -2
- lionagi/service/manager.py +1 -2
- lionagi/service/rate_limited_processor.py +1 -2
- lionagi/service/resilience.py +1 -2
- lionagi/service/third_party/anthropic_models.py +1 -2
- lionagi/service/third_party/claude_code.py +4 -4
- lionagi/service/third_party/openai_models.py +433 -0
- lionagi/service/token_calculator.py +1 -2
- lionagi/session/__init__.py +1 -2
- lionagi/session/branch.py +171 -180
- lionagi/session/session.py +4 -11
- lionagi/tools/__init__.py +1 -2
- lionagi/tools/base.py +1 -2
- lionagi/tools/file/__init__.py +1 -2
- lionagi/tools/file/reader.py +3 -4
- lionagi/tools/types.py +1 -2
- lionagi/utils.py +1 -2
- lionagi/version.py +1 -1
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/METADATA +1 -2
- lionagi-0.18.0.dist-info/RECORD +191 -0
- lionagi/operations/_act/__init__.py +0 -3
- lionagi/operations/_act/act.py +0 -87
- lionagi/protocols/messages/templates/README.md +0 -28
- lionagi/protocols/messages/templates/action_request.jinja2 +0 -5
- lionagi/protocols/messages/templates/action_response.jinja2 +0 -9
- lionagi/protocols/messages/templates/assistant_response.jinja2 +0 -6
- lionagi/protocols/messages/templates/instruction_message.jinja2 +0 -61
- lionagi/protocols/messages/templates/system_message.jinja2 +0 -11
- lionagi/protocols/messages/templates/tool_schemas.jinja2 +0 -7
- lionagi/service/connections/providers/types.py +0 -28
- lionagi/service/third_party/openai_model_names.py +0 -198
- lionagi/service/types.py +0 -59
- lionagi-0.17.10.dist-info/RECORD +0 -199
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/WHEEL +0 -0
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/licenses/LICENSE +0 -0
lionagi/protocols/graph/edge.py
CHANGED
lionagi/protocols/graph/graph.py
CHANGED
lionagi/protocols/graph/node.py
CHANGED
lionagi/protocols/ids.py
CHANGED
lionagi/protocols/mail/mail.py
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
from .action_request import ActionRequest, ActionRequestContent
|
5
|
+
from .action_response import ActionResponse, ActionResponseContent
|
6
|
+
from .assistant_response import AssistantResponse, AssistantResponseContent
|
7
|
+
from .base import MessageRole
|
8
|
+
from .instruction import Instruction, InstructionContent
|
9
|
+
from .manager import MessageManager
|
10
|
+
from .message import MessageContent, MessageRole, RoledMessage
|
11
|
+
from .system import System, SystemContent
|
12
|
+
|
13
|
+
__all__ = (
|
14
|
+
"ActionRequest",
|
15
|
+
"ActionRequestContent",
|
16
|
+
"ActionResponse",
|
17
|
+
"ActionResponseContent",
|
18
|
+
"AssistantResponse",
|
19
|
+
"AssistantResponseContent",
|
20
|
+
"Instruction",
|
21
|
+
"InstructionContent",
|
22
|
+
"MessageContent",
|
23
|
+
"MessageRole",
|
24
|
+
"RoledMessage",
|
25
|
+
"System",
|
26
|
+
"SystemContent",
|
27
|
+
"MessageManager",
|
28
|
+
"MessageRole",
|
29
|
+
)
|
@@ -1,210 +1,111 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
4
3
|
|
5
4
|
from collections.abc import Callable
|
5
|
+
from dataclasses import dataclass, field
|
6
6
|
from typing import Any
|
7
7
|
|
8
|
-
from
|
9
|
-
|
10
|
-
from ..generic.element import IDType
|
11
|
-
from .base import SenderRecipient
|
12
|
-
from .message import MessageRole, RoledMessage, Template, jinja_env
|
8
|
+
from pydantic import field_validator
|
13
9
|
|
10
|
+
from lionagi.utils import copy, to_dict
|
14
11
|
|
15
|
-
|
16
|
-
function: str | Callable,
|
17
|
-
arguments: dict,
|
18
|
-
) -> dict[str, Any]:
|
19
|
-
"""
|
20
|
-
Build a structured dict describing the request details.
|
21
|
-
|
22
|
-
Args:
|
23
|
-
function (str | Callable):
|
24
|
-
The name (or callable) representing the function to invoke.
|
25
|
-
arguments (dict):
|
26
|
-
The arguments necessary for the function call.
|
27
|
-
|
28
|
-
Returns:
|
29
|
-
dict[str, Any]: A standardized dictionary containing
|
30
|
-
'action_request' -> {'function':..., 'arguments':...}
|
12
|
+
from .message import MessageContent, MessageRole, RoledMessage
|
31
13
|
|
32
|
-
Raises:
|
33
|
-
ValueError: If `function` is neither a string nor callable, or
|
34
|
-
if `arguments` cannot be turned into a dictionary.
|
35
|
-
"""
|
36
|
-
if isinstance(function, Callable):
|
37
|
-
function = function.__name__
|
38
|
-
if hasattr(function, "function"):
|
39
|
-
function = function.function
|
40
|
-
if not isinstance(function, str):
|
41
|
-
raise ValueError("Function must be a string or callable.")
|
42
|
-
|
43
|
-
arguments = copy(arguments)
|
44
|
-
if not isinstance(arguments, dict):
|
45
|
-
try:
|
46
|
-
arguments = to_dict(arguments, fuzzy_parse=True)
|
47
|
-
if isinstance(arguments, list | tuple) and len(arguments) > 0:
|
48
|
-
arguments = arguments[0]
|
49
|
-
except Exception:
|
50
|
-
raise ValueError("Arguments must be a dictionary.")
|
51
|
-
return {"action_request": {"function": function, "arguments": arguments}}
|
52
14
|
|
15
|
+
@dataclass(slots=True)
|
16
|
+
class ActionRequestContent(MessageContent):
|
17
|
+
"""Content for action/function call requests.
|
53
18
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
arguments, and optional linking to a subsequent `ActionResponse`.
|
19
|
+
Fields:
|
20
|
+
function: Function name to invoke
|
21
|
+
arguments: Arguments for the function call
|
22
|
+
action_response_id: Link to corresponding response (if any)
|
59
23
|
"""
|
60
24
|
|
61
|
-
|
62
|
-
|
63
|
-
|
25
|
+
function: str = ""
|
26
|
+
arguments: dict[str, Any] = field(default_factory=dict)
|
27
|
+
action_response_id: str | None = None
|
64
28
|
|
65
29
|
@property
|
66
|
-
def
|
67
|
-
"""
|
68
|
-
|
69
|
-
|
70
|
-
Returns:
|
71
|
-
IDType | None: The ID of the action response, or None if none assigned.
|
72
|
-
"""
|
73
|
-
return self.content.get("action_response_id", None)
|
74
|
-
|
75
|
-
@action_response_id.setter
|
76
|
-
def action_response_id(self, action_response_id: IDType) -> None:
|
77
|
-
self.content["action_response_id"] = str(action_response_id)
|
30
|
+
def rendered(self) -> str:
|
31
|
+
"""Render action request as YAML."""
|
32
|
+
from lionagi.libs.schema.minimal_yaml import minimal_yaml
|
78
33
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
34
|
+
doc = {
|
35
|
+
"Function": self.function,
|
36
|
+
"Arguments": self.arguments,
|
37
|
+
}
|
38
|
+
return minimal_yaml(doc).strip()
|
83
39
|
|
84
|
-
|
85
|
-
|
86
|
-
"""
|
87
|
-
|
40
|
+
@classmethod
|
41
|
+
def from_dict(cls, data: dict[str, Any]) -> "ActionRequestContent":
|
42
|
+
"""Construct ActionRequestContent from dictionary."""
|
43
|
+
# Handle nested structure from old format
|
44
|
+
if "action_request" in data:
|
45
|
+
req = data["action_request"]
|
46
|
+
function = req.get("function", "")
|
47
|
+
arguments = req.get("arguments", {})
|
48
|
+
else:
|
49
|
+
function = data.get("function", "")
|
50
|
+
arguments = data.get("arguments", {})
|
51
|
+
|
52
|
+
# Handle callable
|
53
|
+
if isinstance(function, Callable):
|
54
|
+
function = function.__name__
|
55
|
+
if hasattr(function, "function"):
|
56
|
+
function = function.function
|
57
|
+
if not isinstance(function, str):
|
58
|
+
raise ValueError("Function must be a string or callable")
|
59
|
+
|
60
|
+
# Normalize arguments
|
61
|
+
arguments = copy(arguments)
|
62
|
+
if not isinstance(arguments, dict):
|
63
|
+
try:
|
64
|
+
arguments = to_dict(arguments, fuzzy_parse=True)
|
65
|
+
if isinstance(arguments, list | tuple) and len(arguments) > 0:
|
66
|
+
arguments = arguments[0]
|
67
|
+
except Exception:
|
68
|
+
raise ValueError("Arguments must be a dictionary")
|
69
|
+
|
70
|
+
action_response_id = data.get("action_response_id")
|
71
|
+
if action_response_id:
|
72
|
+
action_response_id = str(action_response_id)
|
73
|
+
|
74
|
+
return cls(
|
75
|
+
function=function,
|
76
|
+
arguments=arguments,
|
77
|
+
action_response_id=action_response_id,
|
78
|
+
)
|
88
79
|
|
89
|
-
@property
|
90
|
-
def arguments(self) -> dict[str, Any]:
|
91
|
-
"""
|
92
|
-
Access just the 'arguments' from the action request.
|
93
80
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
81
|
+
class ActionRequest(RoledMessage):
|
82
|
+
"""Message requesting an action or function execution."""
|
83
|
+
|
84
|
+
role: MessageRole = MessageRole.ACTION
|
85
|
+
content: ActionRequestContent
|
86
|
+
|
87
|
+
@field_validator("content", mode="before")
|
88
|
+
def _validate_content(cls, v):
|
89
|
+
if v is None:
|
90
|
+
return ActionRequestContent()
|
91
|
+
if isinstance(v, dict):
|
92
|
+
return ActionRequestContent.from_dict(v)
|
93
|
+
if isinstance(v, ActionRequestContent):
|
94
|
+
return v
|
95
|
+
raise TypeError(
|
96
|
+
"content must be dict or ActionRequestContent instance"
|
97
|
+
)
|
98
98
|
|
99
99
|
@property
|
100
100
|
def function(self) -> str:
|
101
|
-
"""
|
102
|
-
|
103
|
-
|
104
|
-
Returns:
|
105
|
-
str: The function name or empty string if none provided.
|
106
|
-
"""
|
107
|
-
return self.request.get("function", "")
|
101
|
+
"""Access the function name."""
|
102
|
+
return self.content.function
|
108
103
|
|
109
|
-
@
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
arguments: dict | None = None,
|
114
|
-
sender: SenderRecipient | None = None,
|
115
|
-
recipient: SenderRecipient | None = None,
|
116
|
-
template: Template | str | None = None,
|
117
|
-
**kwargs,
|
118
|
-
) -> "ActionRequest":
|
119
|
-
"""
|
120
|
-
Build a new ActionRequest.
|
121
|
-
|
122
|
-
Args:
|
123
|
-
function (str | Callable | None):
|
124
|
-
The function or callable name.
|
125
|
-
arguments (dict | None):
|
126
|
-
Arguments for that function call.
|
127
|
-
sender (SenderRecipient | None):
|
128
|
-
The sender identifier or role.
|
129
|
-
recipient (SenderRecipient | None):
|
130
|
-
The recipient identifier or role.
|
131
|
-
template (Template | str | None):
|
132
|
-
Optional custom template.
|
133
|
-
**kwargs:
|
134
|
-
Extra key-value pairs to merge into the content.
|
135
|
-
|
136
|
-
Returns:
|
137
|
-
ActionRequest: A newly constructed instance.
|
138
|
-
"""
|
139
|
-
content = prepare_action_request(function, arguments)
|
140
|
-
content.update(kwargs)
|
141
|
-
params = {
|
142
|
-
"content": content,
|
143
|
-
"sender": sender,
|
144
|
-
"recipient": recipient,
|
145
|
-
"role": MessageRole.ACTION,
|
146
|
-
}
|
147
|
-
if template:
|
148
|
-
params["template"] = template
|
149
|
-
return cls(**{k: v for k, v in params.items() if v is not None})
|
150
|
-
|
151
|
-
def update(
|
152
|
-
self,
|
153
|
-
function: str = None,
|
154
|
-
arguments: dict | None = None,
|
155
|
-
sender: SenderRecipient = None,
|
156
|
-
recipient: SenderRecipient = None,
|
157
|
-
action_response: "ActionResponse" = None, # type: ignore
|
158
|
-
template: Template | str | None = None,
|
159
|
-
**kwargs,
|
160
|
-
):
|
161
|
-
"""
|
162
|
-
Update this request with new function, arguments, or link to an
|
163
|
-
action response.
|
164
|
-
|
165
|
-
Args:
|
166
|
-
function (str): New function name, if changing.
|
167
|
-
arguments (dict): New arguments dictionary, if changing.
|
168
|
-
sender (SenderRecipient): New sender.
|
169
|
-
recipient (SenderRecipient): New recipient.
|
170
|
-
action_response (ActionResponse):
|
171
|
-
If provided, this request is flagged as responded.
|
172
|
-
template (Template | str | None):
|
173
|
-
Optional new template.
|
174
|
-
**kwargs:
|
175
|
-
Additional fields to store in content.
|
176
|
-
|
177
|
-
Raises:
|
178
|
-
ValueError: If the request is already responded to.
|
179
|
-
"""
|
180
|
-
if self.is_responded():
|
181
|
-
raise ValueError("Cannot update a responded action request.")
|
182
|
-
|
183
|
-
# Link action response if given
|
184
|
-
if (
|
185
|
-
isinstance(action_response, RoledMessage)
|
186
|
-
and action_response.class_name() == "ActionResponse"
|
187
|
-
):
|
188
|
-
self.action_response_id = action_response.id
|
189
|
-
|
190
|
-
# If new function or arguments, create new 'action_request' content
|
191
|
-
if any([function, arguments]):
|
192
|
-
action_request = prepare_action_request(
|
193
|
-
function or self.function, arguments or self.arguments
|
194
|
-
)
|
195
|
-
self.content.update(action_request)
|
196
|
-
super().update(
|
197
|
-
sender=sender, recipient=recipient, template=template, **kwargs
|
198
|
-
)
|
104
|
+
@property
|
105
|
+
def arguments(self) -> dict[str, Any]:
|
106
|
+
"""Access the function arguments."""
|
107
|
+
return self.content.arguments
|
199
108
|
|
200
109
|
def is_responded(self) -> bool:
|
201
|
-
"""
|
202
|
-
|
203
|
-
|
204
|
-
Returns:
|
205
|
-
bool: True if an action response ID is present.
|
206
|
-
"""
|
207
|
-
return self.action_response_id is not None
|
208
|
-
|
209
|
-
|
210
|
-
# File: lionagi/protocols/messages/action_request.py
|
110
|
+
"""Check if this request has been responded to."""
|
111
|
+
return self.content.action_response_id is not None
|
@@ -1,156 +1,97 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
4
3
|
|
4
|
+
from dataclasses import dataclass, field
|
5
5
|
from typing import Any
|
6
6
|
|
7
|
-
from
|
7
|
+
from pydantic import field_validator
|
8
8
|
|
9
|
-
from
|
10
|
-
from lionagi.utils import copy
|
9
|
+
from .message import MessageContent, MessageRole, RoledMessage
|
11
10
|
|
12
|
-
from .action_request import ActionRequest
|
13
|
-
from .base import MessageRole, SenderRecipient
|
14
|
-
from .message import RoledMessage, Template, jinja_env
|
15
11
|
|
12
|
+
@dataclass(slots=True)
|
13
|
+
class ActionResponseContent(MessageContent):
|
14
|
+
"""Content for action/function call responses.
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
Fields:
|
17
|
+
function: Function name that was invoked
|
18
|
+
arguments: Arguments used in the function call
|
19
|
+
output: Result returned from the function
|
20
|
+
action_request_id: Link to the original request
|
21
21
|
"""
|
22
|
-
Convert an ActionRequest + function output into response-friendly dictionary.
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
function: str = ""
|
24
|
+
arguments: dict[str, Any] = field(default_factory=dict)
|
25
|
+
output: Any = None
|
26
|
+
action_request_id: str | None = None
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"action_request_id": str(action_request.id),
|
33
|
-
"action_response": {
|
34
|
-
"function": action_request.function,
|
35
|
-
"arguments": action_request.arguments,
|
36
|
-
"output": output,
|
37
|
-
},
|
38
|
-
}
|
28
|
+
@property
|
29
|
+
def rendered(self) -> str:
|
30
|
+
"""Render action response as YAML."""
|
31
|
+
from lionagi.libs.schema.minimal_yaml import minimal_yaml
|
39
32
|
|
33
|
+
doc = {
|
34
|
+
"Function": self.function,
|
35
|
+
"Arguments": self.arguments,
|
36
|
+
"Output": self.output,
|
37
|
+
}
|
38
|
+
return minimal_yaml(doc).strip()
|
40
39
|
|
41
|
-
|
42
|
-
""
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
@classmethod
|
41
|
+
def from_dict(cls, data: dict[str, Any]) -> "ActionResponseContent":
|
42
|
+
"""Construct ActionResponseContent from dictionary."""
|
43
|
+
# Handle nested structure from old format
|
44
|
+
if "action_response" in data:
|
45
|
+
resp = data["action_response"]
|
46
|
+
function = resp.get("function", "")
|
47
|
+
arguments = resp.get("arguments", {})
|
48
|
+
output = resp.get("output")
|
49
|
+
else:
|
50
|
+
function = data.get("function", "")
|
51
|
+
arguments = data.get("arguments", {})
|
52
|
+
output = data.get("output")
|
53
|
+
|
54
|
+
action_request_id = data.get("action_request_id")
|
55
|
+
if action_request_id:
|
56
|
+
action_request_id = str(action_request_id)
|
57
|
+
|
58
|
+
return cls(
|
59
|
+
function=function,
|
60
|
+
arguments=arguments,
|
61
|
+
output=output,
|
62
|
+
action_request_id=action_request_id,
|
63
|
+
)
|
46
64
|
|
47
|
-
|
48
|
-
|
49
|
-
|
65
|
+
|
66
|
+
class ActionResponse(RoledMessage):
|
67
|
+
"""Message containing the result of an action/function execution."""
|
68
|
+
|
69
|
+
role: MessageRole = MessageRole.ACTION
|
70
|
+
content: ActionResponseContent
|
71
|
+
|
72
|
+
@field_validator("content", mode="before")
|
73
|
+
def _validate_content(cls, v):
|
74
|
+
if v is None:
|
75
|
+
return ActionResponseContent()
|
76
|
+
if isinstance(v, dict):
|
77
|
+
return ActionResponseContent.from_dict(v)
|
78
|
+
if isinstance(v, ActionResponseContent):
|
79
|
+
return v
|
80
|
+
raise TypeError(
|
81
|
+
"content must be dict or ActionResponseContent instance"
|
82
|
+
)
|
50
83
|
|
51
84
|
@property
|
52
85
|
def function(self) -> str:
|
53
|
-
"""
|
54
|
-
return self.content.
|
86
|
+
"""Access the function name."""
|
87
|
+
return self.content.function
|
55
88
|
|
56
89
|
@property
|
57
90
|
def arguments(self) -> dict[str, Any]:
|
58
|
-
"""
|
59
|
-
return self.content.
|
91
|
+
"""Access the function arguments."""
|
92
|
+
return self.content.arguments
|
60
93
|
|
61
94
|
@property
|
62
95
|
def output(self) -> Any:
|
63
|
-
"""
|
64
|
-
return self.content.
|
65
|
-
|
66
|
-
@property
|
67
|
-
def response(self) -> dict[str, Any]:
|
68
|
-
"""
|
69
|
-
A helper to get the entire 'action_response' dictionary.
|
70
|
-
|
71
|
-
Returns:
|
72
|
-
dict[str, Any]: The entire response, including function, arguments, and output.
|
73
|
-
"""
|
74
|
-
return copy(self.content.get("action_response", {}))
|
75
|
-
|
76
|
-
@property
|
77
|
-
def action_request_id(self) -> IDType:
|
78
|
-
"""The ID of the original action request."""
|
79
|
-
return IDType.validate(self.content.get("action_request_id"))
|
80
|
-
|
81
|
-
@override
|
82
|
-
@classmethod
|
83
|
-
def create(
|
84
|
-
cls,
|
85
|
-
action_request: ActionRequest,
|
86
|
-
output: Any | None = None,
|
87
|
-
response_model=None,
|
88
|
-
sender: SenderRecipient | None = None,
|
89
|
-
recipient: SenderRecipient | None = None,
|
90
|
-
) -> "ActionResponse":
|
91
|
-
"""
|
92
|
-
Build an ActionResponse from a matching `ActionRequest` and output.
|
93
|
-
|
94
|
-
Args:
|
95
|
-
action_request (ActionRequest): The original request being fulfilled.
|
96
|
-
output (Any, optional): The function output or result.
|
97
|
-
response_model (Any, optional):
|
98
|
-
If present and has `.output`, this is used instead of `output`.
|
99
|
-
sender (SenderRecipient, optional):
|
100
|
-
The role or ID of the sender (defaults to the request's recipient).
|
101
|
-
recipient (SenderRecipient, optional):
|
102
|
-
The role or ID of the recipient (defaults to the request's sender).
|
103
|
-
|
104
|
-
Returns:
|
105
|
-
ActionResponse: A new instance referencing the `ActionRequest`.
|
106
|
-
"""
|
107
|
-
if response_model:
|
108
|
-
output = response_model.output
|
109
|
-
|
110
|
-
instance = ActionResponse(
|
111
|
-
content=prepare_action_response_content(
|
112
|
-
action_request=response_model or action_request, output=output
|
113
|
-
),
|
114
|
-
role=MessageRole.ACTION,
|
115
|
-
sender=sender or action_request.recipient,
|
116
|
-
recipient=recipient or action_request.sender,
|
117
|
-
)
|
118
|
-
action_request.action_response_id = instance.id
|
119
|
-
return instance
|
120
|
-
|
121
|
-
def update(
|
122
|
-
self,
|
123
|
-
action_request: ActionRequest = None,
|
124
|
-
output: Any = None,
|
125
|
-
response_model=None,
|
126
|
-
sender: SenderRecipient = None,
|
127
|
-
recipient: SenderRecipient = None,
|
128
|
-
template: Template | str | None = None,
|
129
|
-
**kwargs,
|
130
|
-
):
|
131
|
-
"""
|
132
|
-
Update this response with a new request reference or new output.
|
133
|
-
|
134
|
-
Args:
|
135
|
-
action_request (ActionRequest): The updated request.
|
136
|
-
output (Any): The new function output data.
|
137
|
-
response_model: If present, uses response_model.output.
|
138
|
-
sender (SenderRecipient): New sender ID or role.
|
139
|
-
recipient (SenderRecipient): New recipient ID or role.
|
140
|
-
template (Template | str | None): Optional new template.
|
141
|
-
**kwargs: Additional fields to store in content.
|
142
|
-
"""
|
143
|
-
if response_model:
|
144
|
-
output = response_model.output
|
145
|
-
|
146
|
-
if action_request:
|
147
|
-
self.content = prepare_action_response_content(
|
148
|
-
action_request=action_request, output=output or self.output
|
149
|
-
)
|
150
|
-
action_request.action_response_id = self.id
|
151
|
-
super().update(
|
152
|
-
sender=sender, recipient=recipient, template=template, **kwargs
|
153
|
-
)
|
154
|
-
|
155
|
-
|
156
|
-
# File: lionagi/protocols/messages/action_response.py
|
96
|
+
"""Access the function output."""
|
97
|
+
return self.content.output
|