lionagi 0.7.0__py3-none-any.whl → 0.7.2__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/operations/ReAct/ReAct.py +2 -2
- lionagi/operations/_act/act.py +10 -3
- lionagi/operations/communicate/communicate.py +0 -59
- lionagi/operations/interpret/interpret.py +1 -2
- lionagi/operations/operate/operate.py +10 -5
- lionagi/operations/parse/parse.py +0 -36
- lionagi/operations/plan/plan.py +3 -3
- lionagi/operatives/action/manager.py +105 -82
- lionagi/operatives/action/request_response_model.py +31 -0
- lionagi/operatives/action/tool.py +50 -20
- 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 +40 -32
- lionagi/utils.py +1 -0
- lionagi/version.py +1 -1
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/METADATA +1 -1
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/RECORD +43 -43
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/WHEEL +0 -0
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/licenses/LICENSE +0 -0
@@ -2,13 +2,18 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
+
"""
|
6
|
+
Implements the `MessageManager` class, a manager for collecting or
|
7
|
+
manipulating sequences of `RoledMessage` objects, including system,
|
8
|
+
instructions, or action requests/responses.
|
9
|
+
"""
|
10
|
+
|
5
11
|
from typing import Any, Literal
|
6
12
|
|
7
13
|
from jinja2 import Template
|
8
14
|
from pydantic import BaseModel, JsonValue
|
9
15
|
|
10
16
|
from .._concepts import Manager
|
11
|
-
from ..generic.log import Log
|
12
17
|
from ..generic.pile import Pile
|
13
18
|
from ..generic.progression import Progression
|
14
19
|
from .action_request import ActionRequest
|
@@ -22,6 +27,11 @@ DEFAULT_SYSTEM = "You are a helpful AI assistant. Let's think step by step."
|
|
22
27
|
|
23
28
|
|
24
29
|
class MessageManager(Manager):
|
30
|
+
"""
|
31
|
+
A manager maintaining an ordered list of `RoledMessage` items.
|
32
|
+
Capable of setting or replacing a system message, adding instructions,
|
33
|
+
assistant responses, or actions, and retrieving them conveniently.
|
34
|
+
"""
|
25
35
|
|
26
36
|
def __init__(
|
27
37
|
self,
|
@@ -31,6 +41,7 @@ class MessageManager(Manager):
|
|
31
41
|
):
|
32
42
|
super().__init__()
|
33
43
|
m_ = []
|
44
|
+
# Attempt to parse 'messages' as a list or from a dictionary
|
34
45
|
if isinstance(messages, list):
|
35
46
|
for i in messages:
|
36
47
|
if isinstance(i, dict):
|
@@ -58,10 +69,7 @@ class MessageManager(Manager):
|
|
58
69
|
|
59
70
|
def set_system(self, system: System) -> None:
|
60
71
|
"""
|
61
|
-
|
62
|
-
|
63
|
-
Args:
|
64
|
-
system: The new system message to set
|
72
|
+
Replace or set the system message. If one existed, remove it.
|
65
73
|
"""
|
66
74
|
if not self.system:
|
67
75
|
self.system = system
|
@@ -73,17 +81,12 @@ class MessageManager(Manager):
|
|
73
81
|
self.messages.exclude(old_system)
|
74
82
|
|
75
83
|
async def aclear_messages(self):
|
76
|
-
"""
|
84
|
+
"""Async clear all messages except system."""
|
77
85
|
async with self.messages:
|
78
86
|
self.clear_messages()
|
79
87
|
|
80
88
|
async def a_add_message(self, **kwargs):
|
81
|
-
"""
|
82
|
-
Asynchronously add a message.
|
83
|
-
|
84
|
-
Args:
|
85
|
-
**kwargs: Message creation parameters
|
86
|
-
"""
|
89
|
+
"""Add a message asynchronously with a manager-level lock."""
|
87
90
|
async with self.messages:
|
88
91
|
return self.add_message(**kwargs)
|
89
92
|
|
@@ -103,15 +106,23 @@ class MessageManager(Manager):
|
|
103
106
|
sender: SenderRecipient = None,
|
104
107
|
recipient: SenderRecipient = None,
|
105
108
|
) -> Instruction:
|
109
|
+
"""
|
110
|
+
Construct or update an Instruction message with advanced parameters.
|
106
111
|
|
107
|
-
|
112
|
+
If `instruction` is an existing Instruction, it is updated in place.
|
113
|
+
Otherwise, a new instance is created.
|
114
|
+
"""
|
115
|
+
params = {
|
116
|
+
k: v
|
117
|
+
for k, v in locals().items()
|
118
|
+
if k != "instruction" and v is not None
|
119
|
+
}
|
108
120
|
|
109
121
|
if isinstance(instruction, Instruction):
|
110
|
-
params.pop("instruction")
|
111
122
|
instruction.update(**params)
|
112
123
|
return instruction
|
113
124
|
else:
|
114
|
-
return Instruction.create(**params)
|
125
|
+
return Instruction.create(instruction=instruction, **params)
|
115
126
|
|
116
127
|
@staticmethod
|
117
128
|
def create_assistant_response(
|
@@ -122,17 +133,25 @@ class MessageManager(Manager):
|
|
122
133
|
template: Template | str = None,
|
123
134
|
template_context: dict[str, Any] = None,
|
124
135
|
) -> AssistantResponse:
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
136
|
+
"""
|
137
|
+
Build or update an `AssistantResponse`. If `assistant_response` is an
|
138
|
+
existing instance, it's updated. Otherwise, a new one is created.
|
139
|
+
"""
|
140
|
+
params = {
|
141
|
+
k: v
|
142
|
+
for k, v in locals().items()
|
143
|
+
if k not in ["assistant_response", "template_context"]
|
144
|
+
}
|
145
|
+
t_ctx = template_context or {}
|
146
|
+
params.update(t_ctx)
|
129
147
|
|
130
148
|
if isinstance(assistant_response, AssistantResponse):
|
131
|
-
params.pop("assistant_response")
|
132
149
|
assistant_response.update(**params)
|
133
150
|
return assistant_response
|
134
151
|
|
135
|
-
return AssistantResponse.create(
|
152
|
+
return AssistantResponse.create(
|
153
|
+
assistant_response=assistant_response, **params
|
154
|
+
)
|
136
155
|
|
137
156
|
@staticmethod
|
138
157
|
def create_action_request(
|
@@ -145,20 +164,33 @@ class MessageManager(Manager):
|
|
145
164
|
template: Template | str = None,
|
146
165
|
template_context: dict[str, Any] = None,
|
147
166
|
) -> ActionRequest:
|
167
|
+
"""
|
168
|
+
Build or update an ActionRequest.
|
148
169
|
|
170
|
+
Args:
|
171
|
+
sender: Sender role or ID.
|
172
|
+
recipient: Recipient role or ID.
|
173
|
+
function: Function name for the request.
|
174
|
+
arguments: Arguments for the function.
|
175
|
+
action_request: Possibly existing ActionRequest to update.
|
176
|
+
template: Optional jinja template.
|
177
|
+
template_context: Extra context for the template.
|
178
|
+
|
179
|
+
Returns:
|
180
|
+
ActionRequest: The new or updated request object.
|
181
|
+
"""
|
149
182
|
params = {
|
150
183
|
"sender": sender,
|
151
184
|
"recipient": recipient,
|
152
185
|
"function": function,
|
153
186
|
"arguments": arguments,
|
154
187
|
"template": template,
|
155
|
-
**(template_context or {}),
|
156
188
|
}
|
189
|
+
params.update(template_context or {})
|
157
190
|
|
158
191
|
if isinstance(action_request, ActionRequest):
|
159
192
|
action_request.update(**params)
|
160
193
|
return action_request
|
161
|
-
|
162
194
|
return ActionRequest.create(**params)
|
163
195
|
|
164
196
|
@staticmethod
|
@@ -170,20 +202,35 @@ class MessageManager(Manager):
|
|
170
202
|
sender: SenderRecipient = None,
|
171
203
|
recipient: SenderRecipient = None,
|
172
204
|
) -> ActionResponse:
|
205
|
+
"""
|
206
|
+
Create or update an ActionResponse, referencing a prior ActionRequest.
|
173
207
|
|
208
|
+
Args:
|
209
|
+
action_request (ActionRequest):
|
210
|
+
The request being answered.
|
211
|
+
action_output (Any):
|
212
|
+
The result of the invoked function.
|
213
|
+
action_response (ActionResponse|Any):
|
214
|
+
Possibly existing ActionResponse to update.
|
215
|
+
sender:
|
216
|
+
Sender ID or role.
|
217
|
+
recipient:
|
218
|
+
Recipient ID or role.
|
219
|
+
|
220
|
+
Returns:
|
221
|
+
ActionResponse: The newly created or updated response object.
|
222
|
+
"""
|
174
223
|
if not isinstance(action_request, ActionRequest):
|
175
224
|
raise ValueError(
|
176
225
|
"Error: please provide a corresponding action request for an "
|
177
226
|
"action response."
|
178
227
|
)
|
179
|
-
|
180
228
|
params = {
|
181
229
|
"action_request": action_request,
|
182
230
|
"output": action_output,
|
183
231
|
"sender": sender,
|
184
232
|
"recipient": recipient,
|
185
233
|
}
|
186
|
-
|
187
234
|
if isinstance(action_response, ActionResponse):
|
188
235
|
action_response.update(**params)
|
189
236
|
return action_response
|
@@ -200,6 +247,10 @@ class MessageManager(Manager):
|
|
200
247
|
template: Template | str = None,
|
201
248
|
template_context: dict[str, Any] = None,
|
202
249
|
) -> System:
|
250
|
+
"""
|
251
|
+
Create or update a `System` message. If `system` is an instance, update.
|
252
|
+
Otherwise, create a new System message.
|
253
|
+
"""
|
203
254
|
params = {
|
204
255
|
"system_datetime": system_datetime,
|
205
256
|
"sender": sender,
|
@@ -247,8 +298,14 @@ class MessageManager(Manager):
|
|
247
298
|
action_output: Any = None,
|
248
299
|
action_request: ActionRequest | None = None,
|
249
300
|
action_response: ActionResponse | Any = None,
|
250
|
-
) ->
|
251
|
-
|
301
|
+
) -> RoledMessage:
|
302
|
+
"""
|
303
|
+
The central method to add a new message of various types:
|
304
|
+
- System
|
305
|
+
- Instruction
|
306
|
+
- AssistantResponse
|
307
|
+
- ActionRequest / ActionResponse
|
308
|
+
"""
|
252
309
|
_msg = None
|
253
310
|
if (
|
254
311
|
sum(
|
@@ -334,75 +391,102 @@ class MessageManager(Manager):
|
|
334
391
|
return _msg
|
335
392
|
|
336
393
|
def clear_messages(self):
|
394
|
+
"""Remove all messages except the system message if it exists."""
|
337
395
|
self.messages.clear()
|
338
396
|
if self.system:
|
339
397
|
self.messages.insert(0, self.system)
|
340
398
|
|
341
399
|
@property
|
342
400
|
def last_response(self) -> AssistantResponse | None:
|
343
|
-
"""
|
344
|
-
|
345
|
-
|
346
|
-
|
401
|
+
"""
|
402
|
+
Retrieve the most recent `AssistantResponse`.
|
403
|
+
"""
|
404
|
+
for mid in reversed(self.messages.progression):
|
405
|
+
if isinstance(self.messages[mid], AssistantResponse):
|
406
|
+
return self.messages[mid]
|
407
|
+
return None
|
347
408
|
|
348
409
|
@property
|
349
410
|
def last_instruction(self) -> Instruction | None:
|
350
|
-
"""
|
351
|
-
|
352
|
-
|
353
|
-
|
411
|
+
"""
|
412
|
+
Retrieve the most recent `Instruction`.
|
413
|
+
"""
|
414
|
+
for mid in reversed(self.messages.progression):
|
415
|
+
if isinstance(self.messages[mid], Instruction):
|
416
|
+
return self.messages[mid]
|
417
|
+
return None
|
354
418
|
|
355
419
|
@property
|
356
420
|
def assistant_responses(self) -> Pile[AssistantResponse]:
|
357
|
-
"""
|
421
|
+
"""All `AssistantResponse` messages in the manager."""
|
422
|
+
return Pile(
|
423
|
+
collections=[
|
424
|
+
self.messages[mid]
|
425
|
+
for mid in self.messages.progression
|
426
|
+
if isinstance(self.messages[mid], AssistantResponse)
|
427
|
+
]
|
428
|
+
)
|
429
|
+
|
430
|
+
@property
|
431
|
+
def actions(self) -> Pile[ActionRequest | ActionResponse]:
|
432
|
+
"""All action messages in the manager."""
|
358
433
|
return Pile(
|
359
434
|
collections=[
|
360
|
-
self.messages[
|
361
|
-
for
|
362
|
-
if isinstance(
|
435
|
+
self.messages[mid]
|
436
|
+
for mid in self.messages.progression
|
437
|
+
if isinstance(
|
438
|
+
self.messages[mid], (ActionRequest, ActionResponse)
|
439
|
+
)
|
363
440
|
]
|
364
441
|
)
|
365
442
|
|
366
443
|
@property
|
367
444
|
def action_requests(self) -> Pile[ActionRequest]:
|
368
|
-
"""
|
445
|
+
"""All `ActionRequest` messages in the manager."""
|
369
446
|
return Pile(
|
370
447
|
collections=[
|
371
|
-
self.messages[
|
372
|
-
for
|
373
|
-
if isinstance(self.messages[
|
448
|
+
self.messages[mid]
|
449
|
+
for mid in self.messages.progression
|
450
|
+
if isinstance(self.messages[mid], ActionRequest)
|
374
451
|
]
|
375
452
|
)
|
376
453
|
|
377
454
|
@property
|
378
455
|
def action_responses(self) -> Pile[ActionResponse]:
|
379
|
-
"""
|
456
|
+
"""All `ActionResponse` messages in the manager."""
|
380
457
|
return Pile(
|
381
458
|
collections=[
|
382
|
-
self.messages[
|
383
|
-
for
|
384
|
-
if isinstance(self.messages[
|
459
|
+
self.messages[mid]
|
460
|
+
for mid in self.messages.progression
|
461
|
+
if isinstance(self.messages[mid], ActionResponse)
|
385
462
|
]
|
386
463
|
)
|
387
464
|
|
388
465
|
@property
|
389
466
|
def instructions(self) -> Pile[Instruction]:
|
390
|
-
"""
|
467
|
+
"""All `Instruction` messages in the manager."""
|
391
468
|
return Pile(
|
392
469
|
collections=[
|
393
|
-
self.messages[
|
394
|
-
for
|
395
|
-
if isinstance(self.messages[
|
470
|
+
self.messages[mid]
|
471
|
+
for mid in self.messages.progression
|
472
|
+
if isinstance(self.messages[mid], Instruction)
|
396
473
|
]
|
397
474
|
)
|
398
475
|
|
399
476
|
def remove_last_instruction_tool_schemas(self) -> None:
|
400
|
-
|
401
|
-
|
477
|
+
"""
|
478
|
+
Convenience method to strip 'tool_schemas' from the most recent Instruction.
|
479
|
+
"""
|
480
|
+
if self.last_instruction:
|
481
|
+
self.messages[self.last_instruction.id].tool_schemas = None
|
402
482
|
|
403
483
|
def concat_recent_action_responses_to_instruction(
|
404
484
|
self, instruction: Instruction
|
405
485
|
) -> None:
|
486
|
+
"""
|
487
|
+
Example method to merge the content of recent ActionResponses
|
488
|
+
into an instruction's context.
|
489
|
+
"""
|
406
490
|
for i in reversed(self.messages.progression):
|
407
491
|
if isinstance(self.messages[i], ActionResponse):
|
408
492
|
instruction.context.append(self.messages[i].content)
|
@@ -410,16 +494,25 @@ class MessageManager(Manager):
|
|
410
494
|
break
|
411
495
|
|
412
496
|
def to_chat_msgs(self, progression=None) -> list[dict]:
|
497
|
+
"""
|
498
|
+
Convert a subset (or all) of messages into a chat representation array.
|
499
|
+
|
500
|
+
Args:
|
501
|
+
progression (Optional[Sequence]): A subset of message IDs or the full progression.
|
502
|
+
|
503
|
+
Returns:
|
504
|
+
list[dict]: Each item is a dict with 'role' and 'content'.
|
505
|
+
"""
|
413
506
|
if progression == []:
|
414
507
|
return []
|
415
508
|
try:
|
416
509
|
return [
|
417
|
-
self.messages[
|
418
|
-
for
|
510
|
+
self.messages[mid].chat_msg
|
511
|
+
for mid in (progression or self.progression)
|
419
512
|
]
|
420
513
|
except Exception as e:
|
421
514
|
raise ValueError(
|
422
|
-
"
|
515
|
+
"One or more messages in the requested progression are invalid."
|
423
516
|
) from e
|
424
517
|
|
425
518
|
def __bool__(self):
|
@@ -427,3 +520,6 @@ class MessageManager(Manager):
|
|
427
520
|
|
428
521
|
def __contains__(self, message: RoledMessage) -> bool:
|
429
522
|
return message in self.messages
|
523
|
+
|
524
|
+
|
525
|
+
# File: lionagi/protocols/messages/manager.py
|
@@ -2,6 +2,11 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
+
"""
|
6
|
+
Implements the `RoledMessage` base for system, user, assistant,
|
7
|
+
and action messages, plus Jinja2 environment and template loading.
|
8
|
+
"""
|
9
|
+
|
5
10
|
import json
|
6
11
|
from pathlib import Path
|
7
12
|
from typing import Any
|
@@ -27,6 +32,10 @@ __all__ = ("RoledMessage",)
|
|
27
32
|
|
28
33
|
|
29
34
|
class RoledMessage(Node, Sendable):
|
35
|
+
"""
|
36
|
+
A base class for all messages that have a `role` and carry structured
|
37
|
+
`content`. Subclasses might be `Instruction`, `ActionRequest`, etc.
|
38
|
+
"""
|
30
39
|
|
31
40
|
content: dict = Field(
|
32
41
|
default_factory=dict,
|
@@ -69,11 +78,11 @@ class RoledMessage(Node, Sendable):
|
|
69
78
|
@property
|
70
79
|
def image_content(self) -> list[dict[str, Any]] | None:
|
71
80
|
"""
|
72
|
-
|
81
|
+
Extract structured image data from the message content if it is
|
82
|
+
represented as a chat message array.
|
73
83
|
|
74
84
|
Returns:
|
75
|
-
|
76
|
-
dictionaries, or None if no images are present.
|
85
|
+
list[dict[str,Any]] | None: If no images found, None.
|
77
86
|
"""
|
78
87
|
msg_ = self.chat_msg
|
79
88
|
if isinstance(msg_, dict) and isinstance(msg_["content"], list):
|
@@ -83,11 +92,10 @@ class RoledMessage(Node, Sendable):
|
|
83
92
|
@property
|
84
93
|
def chat_msg(self) -> dict[str, Any] | None:
|
85
94
|
"""
|
86
|
-
|
95
|
+
A dictionary representation typically used in chat-based contexts.
|
87
96
|
|
88
97
|
Returns:
|
89
|
-
|
90
|
-
or None if formatting fails.
|
98
|
+
dict: `{"role": <role>, "content": <rendered content>}`
|
91
99
|
"""
|
92
100
|
try:
|
93
101
|
return {"role": str(self.role), "content": self.rendered}
|
@@ -96,6 +104,13 @@ class RoledMessage(Node, Sendable):
|
|
96
104
|
|
97
105
|
@property
|
98
106
|
def rendered(self) -> str:
|
107
|
+
"""
|
108
|
+
Attempt to format the message with a Jinja template (if provided).
|
109
|
+
If no template, fallback to JSON.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
str: The final formatted string.
|
113
|
+
"""
|
99
114
|
try:
|
100
115
|
if isinstance(self.template, str):
|
101
116
|
return self.template.format(**self.content)
|
@@ -106,12 +121,19 @@ class RoledMessage(Node, Sendable):
|
|
106
121
|
|
107
122
|
@classmethod
|
108
123
|
def create(cls, **kwargs):
|
109
|
-
raise NotImplementedError(
|
110
|
-
"create method must be implemented in subclass"
|
111
|
-
)
|
124
|
+
raise NotImplementedError("create() must be implemented in subclass.")
|
112
125
|
|
113
126
|
@classmethod
|
114
127
|
def from_dict(cls, dict_: dict):
|
128
|
+
"""
|
129
|
+
Deserialize a dictionary into a RoledMessage or subclass.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
dict_ (dict): The raw data.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
RoledMessage: A newly constructed instance.
|
136
|
+
"""
|
115
137
|
try:
|
116
138
|
self: RoledMessage = super().from_dict(
|
117
139
|
{k: v for k, v in dict_.items() if v}
|
@@ -123,14 +145,23 @@ class RoledMessage(Node, Sendable):
|
|
123
145
|
|
124
146
|
def is_clone(self) -> bool:
|
125
147
|
"""
|
126
|
-
Check if
|
148
|
+
Check if this message is flagged as a clone.
|
127
149
|
|
128
150
|
Returns:
|
129
|
-
bool: True if
|
151
|
+
bool: True if flagged `MESSAGE_CLONE`.
|
130
152
|
"""
|
131
153
|
return self._flag == MessageFlag.MESSAGE_CLONE
|
132
154
|
|
133
155
|
def clone(self, keep_role: bool = True) -> "RoledMessage":
|
156
|
+
"""
|
157
|
+
Create a shallow copy of this message, possibly resetting the role.
|
158
|
+
|
159
|
+
Args:
|
160
|
+
keep_role (bool): If False, set the new message's role to `UNSET`.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
RoledMessage: The new cloned message.
|
164
|
+
"""
|
134
165
|
instance = self.__class__(
|
135
166
|
content=self.content,
|
136
167
|
role=self.role if keep_role else MessageRole.UNSET,
|
@@ -141,27 +172,15 @@ class RoledMessage(Node, Sendable):
|
|
141
172
|
|
142
173
|
def to_log(self) -> Log:
|
143
174
|
"""
|
144
|
-
Convert
|
145
|
-
|
146
|
-
Creates a Log instance containing the message content and additional
|
147
|
-
information as loginfo.
|
175
|
+
Convert this message into a `Log`, preserving all current fields.
|
148
176
|
|
149
177
|
Returns:
|
150
|
-
Log:
|
178
|
+
Log: An immutable log entry derived from this message.
|
151
179
|
"""
|
152
180
|
return Log.create(self)
|
153
181
|
|
154
182
|
@field_serializer("role")
|
155
183
|
def _serialize_role(self, value: MessageRole):
|
156
|
-
"""
|
157
|
-
Serialize the role for storage or transmission.
|
158
|
-
|
159
|
-
Args:
|
160
|
-
value: The MessageRole to serialize
|
161
|
-
|
162
|
-
Returns:
|
163
|
-
str: The string value of the role
|
164
|
-
"""
|
165
184
|
if isinstance(value, MessageRole):
|
166
185
|
return value.value
|
167
186
|
return str(value)
|
@@ -187,11 +206,25 @@ class RoledMessage(Node, Sendable):
|
|
187
206
|
|
188
207
|
@field_serializer("template")
|
189
208
|
def _serialize_template(self, value: Template | str):
|
209
|
+
# We do not store or transmit the raw Template object.
|
190
210
|
if isinstance(value, Template):
|
191
211
|
return None
|
192
212
|
return value
|
193
213
|
|
194
214
|
def update(self, sender, recipient, template, **kwargs):
|
215
|
+
"""
|
216
|
+
Generic update mechanism for customizing the message in place.
|
217
|
+
|
218
|
+
Args:
|
219
|
+
sender (SenderRecipient):
|
220
|
+
New sender or role.
|
221
|
+
recipient (SenderRecipient):
|
222
|
+
New recipient or role.
|
223
|
+
template (Template | str):
|
224
|
+
New jinja Template or format string.
|
225
|
+
**kwargs:
|
226
|
+
Additional content to merge into self.content.
|
227
|
+
"""
|
195
228
|
if sender:
|
196
229
|
self.sender = validate_sender_recipient(sender)
|
197
230
|
if recipient:
|
@@ -214,3 +247,6 @@ class RoledMessage(Node, Sendable):
|
|
214
247
|
f"Message(role={self.role}, sender={self.sender}, "
|
215
248
|
f"content='{content_preview}')"
|
216
249
|
)
|
250
|
+
|
251
|
+
|
252
|
+
# File: lionagi/protocols/messages/message.py
|