langroid 0.6.7__py3-none-any.whl → 0.9.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.
- langroid/agent/base.py +499 -55
- langroid/agent/callbacks/chainlit.py +1 -1
- langroid/agent/chat_agent.py +191 -37
- langroid/agent/chat_document.py +142 -29
- langroid/agent/openai_assistant.py +20 -4
- langroid/agent/special/lance_doc_chat_agent.py +25 -18
- langroid/agent/special/lance_rag/critic_agent.py +37 -5
- langroid/agent/special/lance_rag/query_planner_agent.py +102 -63
- langroid/agent/special/lance_tools.py +10 -2
- langroid/agent/special/sql/sql_chat_agent.py +69 -13
- langroid/agent/task.py +179 -43
- langroid/agent/tool_message.py +19 -7
- langroid/agent/tools/__init__.py +5 -0
- langroid/agent/tools/orchestration.py +216 -0
- langroid/agent/tools/recipient_tool.py +6 -11
- langroid/agent/tools/rewind_tool.py +1 -1
- langroid/agent/typed_task.py +19 -0
- langroid/language_models/.chainlit/config.toml +121 -0
- langroid/language_models/.chainlit/translations/en-US.json +231 -0
- langroid/language_models/base.py +114 -12
- langroid/language_models/mock_lm.py +10 -1
- langroid/language_models/openai_gpt.py +260 -36
- langroid/mytypes.py +0 -1
- langroid/parsing/parse_json.py +19 -2
- langroid/utils/pydantic_utils.py +19 -0
- langroid/vector_store/base.py +3 -1
- langroid/vector_store/lancedb.py +2 -0
- {langroid-0.6.7.dist-info → langroid-0.9.0.dist-info}/METADATA +4 -1
- {langroid-0.6.7.dist-info → langroid-0.9.0.dist-info}/RECORD +32 -33
- pyproject.toml +2 -1
- langroid/agent/special/lance_rag_new/__init__.py +0 -9
- langroid/agent/special/lance_rag_new/critic_agent.py +0 -171
- langroid/agent/special/lance_rag_new/lance_rag_task.py +0 -144
- langroid/agent/special/lance_rag_new/query_planner_agent.py +0 -222
- langroid/agent/team.py +0 -1758
- {langroid-0.6.7.dist-info → langroid-0.9.0.dist-info}/LICENSE +0 -0
- {langroid-0.6.7.dist-info → langroid-0.9.0.dist-info}/WHEEL +0 -0
@@ -58,7 +58,7 @@ async def setup_llm() -> None:
|
|
58
58
|
timeout = llm_settings.get("timeout", 90)
|
59
59
|
logger.info(f"Using model: {model}")
|
60
60
|
llm_config = lm.OpenAIGPTConfig(
|
61
|
-
chat_model=model or lm.OpenAIChatModel.
|
61
|
+
chat_model=model or lm.OpenAIChatModel.GPT4o,
|
62
62
|
# or, other possibilities for example:
|
63
63
|
# "litellm/ollama_chat/mistral"
|
64
64
|
# "litellm/ollama_chat/mistral:7b-instruct-v0.2-q8_0"
|
langroid/agent/chat_agent.py
CHANGED
@@ -16,8 +16,10 @@ from langroid.language_models.base import (
|
|
16
16
|
LLMFunctionSpec,
|
17
17
|
LLMMessage,
|
18
18
|
LLMResponse,
|
19
|
+
OpenAIToolSpec,
|
19
20
|
Role,
|
20
21
|
StreamingIfAllowed,
|
22
|
+
ToolChoiceTypes,
|
21
23
|
)
|
22
24
|
from langroid.language_models.openai_gpt import OpenAIGPT
|
23
25
|
from langroid.utils.configuration import settings
|
@@ -39,14 +41,22 @@ class ChatAgentConfig(AgentConfig):
|
|
39
41
|
user_message: user message to include in message sequence.
|
40
42
|
Used only if `task` is not specified in the constructor.
|
41
43
|
use_tools: whether to use our own ToolMessages mechanism
|
42
|
-
use_functions_api: whether to use functions native to the LLM API
|
43
|
-
(e.g. OpenAI's `function_call` mechanism)
|
44
|
+
use_functions_api: whether to use functions/tools native to the LLM API
|
45
|
+
(e.g. OpenAI's `function_call` or `tool_call` mechanism)
|
46
|
+
use_tools_api: When `use_functions_api` is True, if this is also True,
|
47
|
+
the OpenAI tool-call API is used, rather than the older/deprecated
|
48
|
+
function-call API. However the tool-call API has some tricky aspects,
|
49
|
+
hence we set this to False by default.
|
50
|
+
enable_orchestration_tool_handling: whether to enable handling of orchestration
|
51
|
+
tools, e.g. ForwardTool, DoneTool, PassTool, etc.
|
44
52
|
"""
|
45
53
|
|
46
54
|
system_message: str = "You are a helpful assistant."
|
47
55
|
user_message: Optional[str] = None
|
48
56
|
use_tools: bool = False
|
49
57
|
use_functions_api: bool = True
|
58
|
+
use_tools_api: bool = False
|
59
|
+
enable_orchestration_tool_handling: bool = True
|
50
60
|
|
51
61
|
def _set_fn_or_tools(self, fn_available: bool) -> None:
|
52
62
|
"""
|
@@ -138,6 +148,30 @@ class ChatAgent(Agent):
|
|
138
148
|
self.llm_functions_usable: Set[str] = set()
|
139
149
|
self.llm_function_force: Optional[Dict[str, str]] = None
|
140
150
|
|
151
|
+
if self.config.enable_orchestration_tool_handling:
|
152
|
+
# Only enable HANDLING by `agent_response`, NOT LLM generation of these.
|
153
|
+
# This is useful where tool-handlers or agent_response generate these
|
154
|
+
# tools, and need to be handled.
|
155
|
+
# We don't want enable orch tool GENERATION by default, since that
|
156
|
+
# might clutter-up the LLM system message unnecessarily.
|
157
|
+
from langroid.agent.tools.orchestration import (
|
158
|
+
AgentDoneTool,
|
159
|
+
AgentSendTool,
|
160
|
+
DonePassTool,
|
161
|
+
DoneTool,
|
162
|
+
ForwardTool,
|
163
|
+
PassTool,
|
164
|
+
SendTool,
|
165
|
+
)
|
166
|
+
|
167
|
+
self.enable_message(ForwardTool, use=False, handle=True)
|
168
|
+
self.enable_message(DoneTool, use=False, handle=True)
|
169
|
+
self.enable_message(AgentDoneTool, use=False, handle=True)
|
170
|
+
self.enable_message(PassTool, use=False, handle=True)
|
171
|
+
self.enable_message(DonePassTool, use=False, handle=True)
|
172
|
+
self.enable_message(SendTool, use=False, handle=True)
|
173
|
+
self.enable_message(AgentSendTool, use=False, handle=True)
|
174
|
+
|
141
175
|
@staticmethod
|
142
176
|
def from_id(id: str) -> "ChatAgent":
|
143
177
|
"""
|
@@ -205,6 +239,23 @@ class ChatAgent(Agent):
|
|
205
239
|
msgs.append(LLMMessage(role=Role.USER, content=self.user_message))
|
206
240
|
return msgs
|
207
241
|
|
242
|
+
def _drop_msg_update_tool_calls(self, msg: LLMMessage) -> None:
|
243
|
+
id2idx = {t.id: i for i, t in enumerate(self.oai_tool_calls)}
|
244
|
+
if msg.role == Role.TOOL:
|
245
|
+
# dropping tool result, so ADD the corresponding tool-call back
|
246
|
+
# to the list of pending calls!
|
247
|
+
id = msg.tool_call_id
|
248
|
+
if id in self.oai_tool_id2call:
|
249
|
+
self.oai_tool_calls.append(self.oai_tool_id2call[id])
|
250
|
+
elif msg.tool_calls is not None:
|
251
|
+
# dropping a msg with tool-calls, so DROP these from pending list
|
252
|
+
# as well as from id -> call map
|
253
|
+
for tool_call in msg.tool_calls:
|
254
|
+
if tool_call.id in id2idx:
|
255
|
+
self.oai_tool_calls.pop(id2idx[tool_call.id])
|
256
|
+
if tool_call.id in self.oai_tool_id2call:
|
257
|
+
del self.oai_tool_id2call[tool_call.id]
|
258
|
+
|
208
259
|
def clear_history(self, start: int = -2) -> None:
|
209
260
|
"""
|
210
261
|
Clear the message history, starting at the index `start`
|
@@ -218,7 +269,10 @@ class ChatAgent(Agent):
|
|
218
269
|
n = len(self.message_history)
|
219
270
|
start = max(0, n + start)
|
220
271
|
dropped = self.message_history[start:]
|
221
|
-
|
272
|
+
# consider the dropped msgs in REVERSE order, so we are
|
273
|
+
# carefully updating self.oai_tool_calls
|
274
|
+
for msg in reversed(dropped):
|
275
|
+
self._drop_msg_update_tool_calls(msg)
|
222
276
|
# clear out the chat document from the ObjectRegistry
|
223
277
|
ChatDocument.delete_id(msg.chat_document_id)
|
224
278
|
self.message_history = self.message_history[:start]
|
@@ -245,19 +299,25 @@ class ChatAgent(Agent):
|
|
245
299
|
Returns:
|
246
300
|
str: formatting rules
|
247
301
|
"""
|
248
|
-
|
249
|
-
|
302
|
+
# ONLY Usable tools (i.e. LLM-generation allowed),
|
303
|
+
usable_tool_classes: List[Type[ToolMessage]] = [
|
304
|
+
t
|
305
|
+
for t in list(self.llm_tools_map.values())
|
306
|
+
if not t._handle_only
|
307
|
+
and t.default_value("request") in self.llm_tools_usable
|
308
|
+
]
|
309
|
+
|
310
|
+
if len(usable_tool_classes) == 0:
|
250
311
|
return "You can ask questions in natural language."
|
251
312
|
json_instructions = "\n\n".join(
|
252
313
|
[
|
253
314
|
msg_cls.json_instructions(tool=self.config.use_tools)
|
254
|
-
for
|
255
|
-
if msg_cls.default_value("request") in self.llm_tools_usable
|
315
|
+
for msg_cls in usable_tool_classes
|
256
316
|
]
|
257
317
|
)
|
258
318
|
# if any of the enabled classes has json_group_instructions, then use that,
|
259
319
|
# else fall back to ToolMessage.json_group_instructions
|
260
|
-
for msg_cls in
|
320
|
+
for msg_cls in usable_tool_classes:
|
261
321
|
if hasattr(msg_cls, "json_group_instructions") and callable(
|
262
322
|
getattr(msg_cls, "json_group_instructions")
|
263
323
|
):
|
@@ -393,9 +453,16 @@ class ChatAgent(Agent):
|
|
393
453
|
# remove leading and trailing newlines and other whitespace
|
394
454
|
return LLMMessage(role=Role.SYSTEM, content=content.strip())
|
395
455
|
|
456
|
+
def unhanded_tools(self) -> set[str]:
|
457
|
+
"""The set of tools that are known but not handled.
|
458
|
+
Useful in task flow: an agent can refuse to accept an incoming msg
|
459
|
+
when it only has unhandled tools.
|
460
|
+
"""
|
461
|
+
return self.llm_tools_known - self.llm_tools_handled
|
462
|
+
|
396
463
|
def enable_message(
|
397
464
|
self,
|
398
|
-
message_class: Optional[Type[ToolMessage]],
|
465
|
+
message_class: Optional[Type[ToolMessage] | List[Type[ToolMessage]]],
|
399
466
|
use: bool = True,
|
400
467
|
handle: bool = True,
|
401
468
|
force: bool = False,
|
@@ -408,8 +475,10 @@ class ChatAgent(Agent):
|
|
408
475
|
- tool HANDLING (i.e. the agent can handle JSON from this tool),
|
409
476
|
|
410
477
|
Args:
|
411
|
-
message_class: The ToolMessage class to enable,
|
478
|
+
message_class: The ToolMessage class OR List of such classes to enable,
|
412
479
|
for USE, or HANDLING, or both.
|
480
|
+
If this is a list of ToolMessage classes, then the remain args are
|
481
|
+
applied to all classes.
|
413
482
|
Optional; if None, then apply the enabling to all tools in the
|
414
483
|
agent's toolset that have been enabled so far.
|
415
484
|
use: IF True, allow the agent (LLM) to use this tool (or all tools),
|
@@ -421,12 +490,23 @@ class ChatAgent(Agent):
|
|
421
490
|
`force` is ignored if `message_class` is None.
|
422
491
|
require_recipient: whether to require that recipient be specified
|
423
492
|
when using the tool message (only applies if `use` is True).
|
424
|
-
|
493
|
+
include_defaults: whether to include fields that have default values,
|
425
494
|
in the "properties" section of the JSON format instructions.
|
426
495
|
(Normally the OpenAI completion API ignores these fields,
|
427
496
|
but the Assistant fn-calling seems to pay attn to these,
|
428
497
|
and if we don't want this, we should set this to False.)
|
429
498
|
"""
|
499
|
+
if message_class is not None and isinstance(message_class, list):
|
500
|
+
for mc in message_class:
|
501
|
+
self.enable_message(
|
502
|
+
mc,
|
503
|
+
use=use,
|
504
|
+
handle=handle,
|
505
|
+
force=force,
|
506
|
+
require_recipient=require_recipient,
|
507
|
+
include_defaults=include_defaults,
|
508
|
+
)
|
509
|
+
return None
|
430
510
|
if require_recipient and message_class is not None:
|
431
511
|
message_class = message_class.require_recipient()
|
432
512
|
super().enable_message_handling(message_class) # enables handling only
|
@@ -441,6 +521,8 @@ class ChatAgent(Agent):
|
|
441
521
|
self.llm_function_force = None
|
442
522
|
|
443
523
|
for t in tools:
|
524
|
+
self.llm_tools_known.add(t)
|
525
|
+
|
444
526
|
if handle:
|
445
527
|
self.llm_tools_handled.add(t)
|
446
528
|
self.llm_functions_handled.add(t)
|
@@ -519,9 +601,14 @@ class ChatAgent(Agent):
|
|
519
601
|
hist, output_len = self._prep_llm_messages(message)
|
520
602
|
if len(hist) == 0:
|
521
603
|
return None
|
604
|
+
tool_choice = (
|
605
|
+
"auto"
|
606
|
+
if isinstance(message, str)
|
607
|
+
else (message.oai_tool_choice if message is not None else "auto")
|
608
|
+
)
|
522
609
|
with StreamingIfAllowed(self.llm, self.llm.get_stream()):
|
523
|
-
response = self.llm_response_messages(hist, output_len)
|
524
|
-
self.message_history.
|
610
|
+
response = self.llm_response_messages(hist, output_len, tool_choice)
|
611
|
+
self.message_history.extend(ChatDocument.to_LLMMessage(response))
|
525
612
|
response.metadata.msg_idx = len(self.message_history) - 1
|
526
613
|
response.metadata.agent_id = self.id
|
527
614
|
# Preserve trail of tool_ids for OpenAI Assistant fn-calls
|
@@ -543,9 +630,16 @@ class ChatAgent(Agent):
|
|
543
630
|
hist, output_len = self._prep_llm_messages(message)
|
544
631
|
if len(hist) == 0:
|
545
632
|
return None
|
633
|
+
tool_choice = (
|
634
|
+
"auto"
|
635
|
+
if isinstance(message, str)
|
636
|
+
else (message.oai_tool_choice if message is not None else "auto")
|
637
|
+
)
|
546
638
|
with StreamingIfAllowed(self.llm, self.llm.get_stream()):
|
547
|
-
response = await self.llm_response_messages_async(
|
548
|
-
|
639
|
+
response = await self.llm_response_messages_async(
|
640
|
+
hist, output_len, tool_choice
|
641
|
+
)
|
642
|
+
self.message_history.extend(ChatDocument.to_LLMMessage(response))
|
549
643
|
response.metadata.msg_idx = len(self.message_history) - 1
|
550
644
|
response.metadata.agent_id = self.id
|
551
645
|
# Preserve trail of tool_ids for OpenAI Assistant fn-calls
|
@@ -622,8 +716,18 @@ class ChatAgent(Agent):
|
|
622
716
|
):
|
623
717
|
# either the message is a str, or it is a fresh ChatDocument
|
624
718
|
# different from the last message in the history
|
625
|
-
|
626
|
-
|
719
|
+
llm_msgs = ChatDocument.to_LLMMessage(message, self.oai_tool_calls)
|
720
|
+
# LLM only responds to the content, so only those msgs with
|
721
|
+
# non-empty content should be kept
|
722
|
+
llm_msgs = [m for m in llm_msgs if m.content != ""]
|
723
|
+
if len(llm_msgs) == 0:
|
724
|
+
return [], 0
|
725
|
+
# process tools if any
|
726
|
+
done_tools = [m.tool_call_id for m in llm_msgs if m.role == Role.TOOL]
|
727
|
+
self.oai_tool_calls = [
|
728
|
+
t for t in self.oai_tool_calls if t.id not in done_tools
|
729
|
+
]
|
730
|
+
self.message_history.extend(llm_msgs)
|
627
731
|
|
628
732
|
hist = self.message_history
|
629
733
|
output_len = self.config.llm.max_output_tokens
|
@@ -707,18 +811,47 @@ class ChatAgent(Agent):
|
|
707
811
|
|
708
812
|
def _function_args(
|
709
813
|
self,
|
710
|
-
) -> Tuple[
|
814
|
+
) -> Tuple[
|
815
|
+
Optional[List[LLMFunctionSpec]],
|
816
|
+
str | Dict[str, str],
|
817
|
+
Optional[List[OpenAIToolSpec]],
|
818
|
+
Optional[Dict[str, Dict[str, str] | str]],
|
819
|
+
]:
|
820
|
+
"""Get function/tool spec arguments for OpenAI-compatible LLM API call"""
|
711
821
|
functions: Optional[List[LLMFunctionSpec]] = None
|
712
822
|
fun_call: str | Dict[str, str] = "none"
|
823
|
+
tools: Optional[List[OpenAIToolSpec]] = None
|
824
|
+
force_tool: Optional[Dict[str, Dict[str, str] | str]] = None
|
713
825
|
if self.config.use_functions_api and len(self.llm_functions_usable) > 0:
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
826
|
+
if not self.config.use_tools_api:
|
827
|
+
functions = [
|
828
|
+
self.llm_functions_map[f] for f in self.llm_functions_usable
|
829
|
+
]
|
830
|
+
fun_call = (
|
831
|
+
"auto"
|
832
|
+
if self.llm_function_force is None
|
833
|
+
else self.llm_function_force
|
834
|
+
)
|
835
|
+
else:
|
836
|
+
tools = [
|
837
|
+
OpenAIToolSpec(type="function", function=self.llm_functions_map[f])
|
838
|
+
for f in self.llm_functions_usable
|
839
|
+
]
|
840
|
+
force_tool = (
|
841
|
+
None
|
842
|
+
if self.llm_function_force is None
|
843
|
+
else {
|
844
|
+
"type": "function",
|
845
|
+
"function": {"name": self.llm_function_force["name"]},
|
846
|
+
}
|
847
|
+
)
|
848
|
+
return functions, fun_call, tools, force_tool
|
719
849
|
|
720
850
|
def llm_response_messages(
|
721
|
-
self,
|
851
|
+
self,
|
852
|
+
messages: List[LLMMessage],
|
853
|
+
output_len: Optional[int] = None,
|
854
|
+
tool_choice: ToolChoiceTypes | Dict[str, str | Dict[str, str]] = "auto",
|
722
855
|
) -> ChatDocument:
|
723
856
|
"""
|
724
857
|
Respond to a series of messages, e.g. with OpenAI ChatCompletion
|
@@ -748,11 +881,13 @@ class ChatAgent(Agent):
|
|
748
881
|
stack.enter_context(cm)
|
749
882
|
if self.llm.get_stream() and not settings.quiet:
|
750
883
|
console.print(f"[green]{self.indent}", end="")
|
751
|
-
functions, fun_call = self._function_args()
|
884
|
+
functions, fun_call, tools, force_tool = self._function_args()
|
752
885
|
assert self.llm is not None
|
753
886
|
response = self.llm.chat(
|
754
887
|
messages,
|
755
888
|
output_len,
|
889
|
+
tools=tools,
|
890
|
+
tool_choice=force_tool or tool_choice,
|
756
891
|
functions=functions,
|
757
892
|
function_call=fun_call,
|
758
893
|
)
|
@@ -775,23 +910,24 @@ class ChatAgent(Agent):
|
|
775
910
|
print_response_stats=self.config.show_stats and not settings.quiet,
|
776
911
|
)
|
777
912
|
chat_doc = ChatDocument.from_LLMResponse(response, displayed=True)
|
913
|
+
self.oai_tool_calls = response.oai_tool_calls or []
|
914
|
+
self.oai_tool_id2call.update(
|
915
|
+
{t.id: t for t in self.oai_tool_calls if t.id is not None}
|
916
|
+
)
|
778
917
|
return chat_doc
|
779
918
|
|
780
919
|
async def llm_response_messages_async(
|
781
|
-
self,
|
920
|
+
self,
|
921
|
+
messages: List[LLMMessage],
|
922
|
+
output_len: Optional[int] = None,
|
923
|
+
tool_choice: ToolChoiceTypes | Dict[str, str | Dict[str, str]] = "auto",
|
782
924
|
) -> ChatDocument:
|
783
925
|
"""
|
784
926
|
Async version of `llm_response_messages`. See there for details.
|
785
927
|
"""
|
786
928
|
assert self.config.llm is not None and self.llm is not None
|
787
929
|
output_len = output_len or self.config.llm.max_output_tokens
|
788
|
-
functions
|
789
|
-
fun_call: str | Dict[str, str] = "none"
|
790
|
-
if self.config.use_functions_api and len(self.llm_functions_usable) > 0:
|
791
|
-
functions = [self.llm_functions_map[f] for f in self.llm_functions_usable]
|
792
|
-
fun_call = (
|
793
|
-
"auto" if self.llm_function_force is None else self.llm_function_force
|
794
|
-
)
|
930
|
+
functions, fun_call, tools, force_tool = self._function_args()
|
795
931
|
assert self.llm is not None
|
796
932
|
|
797
933
|
streamer = noop_fn
|
@@ -802,6 +938,8 @@ class ChatAgent(Agent):
|
|
802
938
|
response = await self.llm.achat(
|
803
939
|
messages,
|
804
940
|
output_len,
|
941
|
+
tools=tools,
|
942
|
+
tool_choice=force_tool or tool_choice,
|
805
943
|
functions=functions,
|
806
944
|
function_call=fun_call,
|
807
945
|
)
|
@@ -824,6 +962,10 @@ class ChatAgent(Agent):
|
|
824
962
|
print_response_stats=self.config.show_stats and not settings.quiet,
|
825
963
|
)
|
826
964
|
chat_doc = ChatDocument.from_LLMResponse(response, displayed=True)
|
965
|
+
self.oai_tool_calls = response.oai_tool_calls or []
|
966
|
+
self.oai_tool_id2call.update(
|
967
|
+
{t.id: t for t in self.oai_tool_calls if t.id is not None}
|
968
|
+
)
|
827
969
|
return chat_doc
|
828
970
|
|
829
971
|
def _render_llm_response(
|
@@ -847,6 +989,7 @@ class ChatAgent(Agent):
|
|
847
989
|
if isinstance(response, ChatDocument)
|
848
990
|
else ChatDocument.from_LLMResponse(response, displayed=True)
|
849
991
|
)
|
992
|
+
# TODO: prepend TOOL: or OAI-TOOL: if it's a tool-call
|
850
993
|
print(cached + "[green]" + escape(str(response)))
|
851
994
|
self.callbacks.show_llm_response(
|
852
995
|
content=str(response),
|
@@ -923,8 +1066,14 @@ class ChatAgent(Agent):
|
|
923
1066
|
# If there is a response, then we will have two additional
|
924
1067
|
# messages in the message history, i.e. the user message and the
|
925
1068
|
# assistant response. We want to (carefully) remove these two messages.
|
926
|
-
|
927
|
-
|
1069
|
+
if len(self.message_history) > n_msgs:
|
1070
|
+
msg = self.message_history.pop()
|
1071
|
+
self._drop_msg_update_tool_calls(msg)
|
1072
|
+
|
1073
|
+
if len(self.message_history) > n_msgs:
|
1074
|
+
msg = self.message_history.pop()
|
1075
|
+
self._drop_msg_update_tool_calls(msg)
|
1076
|
+
|
928
1077
|
return response
|
929
1078
|
|
930
1079
|
async def llm_response_forget_async(self, message: str) -> ChatDocument:
|
@@ -941,8 +1090,13 @@ class ChatAgent(Agent):
|
|
941
1090
|
# If there is a response, then we will have two additional
|
942
1091
|
# messages in the message history, i.e. the user message and the
|
943
1092
|
# assistant response. We want to (carefully) remove these two messages.
|
944
|
-
|
945
|
-
|
1093
|
+
if len(self.message_history) > n_msgs:
|
1094
|
+
msg = self.message_history.pop()
|
1095
|
+
self._drop_msg_update_tool_calls(msg)
|
1096
|
+
|
1097
|
+
if len(self.message_history) > n_msgs:
|
1098
|
+
msg = self.message_history.pop()
|
1099
|
+
self._drop_msg_update_tool_calls(msg)
|
946
1100
|
return response
|
947
1101
|
|
948
1102
|
def chat_num_tokens(self, messages: Optional[List[LLMMessage]] = None) -> int:
|