langroid 0.1.139__py3-none-any.whl → 0.1.219__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/__init__.py +70 -0
- langroid/agent/__init__.py +22 -0
- langroid/agent/base.py +120 -33
- langroid/agent/batch.py +134 -35
- langroid/agent/callbacks/__init__.py +0 -0
- langroid/agent/callbacks/chainlit.py +608 -0
- langroid/agent/chat_agent.py +164 -100
- langroid/agent/chat_document.py +19 -2
- langroid/agent/openai_assistant.py +20 -10
- langroid/agent/special/__init__.py +33 -10
- langroid/agent/special/doc_chat_agent.py +521 -108
- langroid/agent/special/lance_doc_chat_agent.py +258 -0
- langroid/agent/special/lance_rag/__init__.py +9 -0
- langroid/agent/special/lance_rag/critic_agent.py +136 -0
- langroid/agent/special/lance_rag/lance_rag_task.py +80 -0
- langroid/agent/special/lance_rag/query_planner_agent.py +180 -0
- langroid/agent/special/lance_tools.py +44 -0
- langroid/agent/special/neo4j/__init__.py +0 -0
- langroid/agent/special/neo4j/csv_kg_chat.py +174 -0
- langroid/agent/special/neo4j/neo4j_chat_agent.py +370 -0
- langroid/agent/special/neo4j/utils/__init__.py +0 -0
- langroid/agent/special/neo4j/utils/system_message.py +46 -0
- langroid/agent/special/relevance_extractor_agent.py +23 -7
- langroid/agent/special/retriever_agent.py +29 -174
- langroid/agent/special/sql/__init__.py +7 -0
- langroid/agent/special/sql/sql_chat_agent.py +47 -23
- langroid/agent/special/sql/utils/__init__.py +11 -0
- langroid/agent/special/sql/utils/description_extractors.py +95 -46
- langroid/agent/special/sql/utils/populate_metadata.py +28 -21
- langroid/agent/special/table_chat_agent.py +43 -9
- langroid/agent/task.py +423 -114
- langroid/agent/tool_message.py +67 -10
- langroid/agent/tools/__init__.py +8 -0
- langroid/agent/tools/duckduckgo_search_tool.py +66 -0
- langroid/agent/tools/google_search_tool.py +11 -0
- langroid/agent/tools/metaphor_search_tool.py +67 -0
- langroid/agent/tools/recipient_tool.py +6 -24
- langroid/agent/tools/sciphi_search_rag_tool.py +79 -0
- langroid/cachedb/__init__.py +6 -0
- langroid/embedding_models/__init__.py +24 -0
- langroid/embedding_models/base.py +9 -1
- langroid/embedding_models/models.py +117 -17
- langroid/embedding_models/protoc/embeddings.proto +19 -0
- langroid/embedding_models/protoc/embeddings_pb2.py +33 -0
- langroid/embedding_models/protoc/embeddings_pb2.pyi +50 -0
- langroid/embedding_models/protoc/embeddings_pb2_grpc.py +79 -0
- langroid/embedding_models/remote_embeds.py +153 -0
- langroid/language_models/__init__.py +22 -0
- langroid/language_models/azure_openai.py +47 -4
- langroid/language_models/base.py +26 -10
- langroid/language_models/config.py +5 -0
- langroid/language_models/openai_gpt.py +407 -121
- langroid/language_models/prompt_formatter/__init__.py +9 -0
- langroid/language_models/prompt_formatter/base.py +4 -6
- langroid/language_models/prompt_formatter/hf_formatter.py +135 -0
- langroid/language_models/utils.py +10 -9
- langroid/mytypes.py +10 -4
- langroid/parsing/__init__.py +33 -1
- langroid/parsing/document_parser.py +259 -63
- langroid/parsing/image_text.py +32 -0
- langroid/parsing/parse_json.py +143 -0
- langroid/parsing/parser.py +20 -7
- langroid/parsing/repo_loader.py +108 -46
- langroid/parsing/search.py +8 -0
- langroid/parsing/table_loader.py +44 -0
- langroid/parsing/url_loader.py +59 -13
- langroid/parsing/urls.py +18 -9
- langroid/parsing/utils.py +130 -9
- langroid/parsing/web_search.py +73 -0
- langroid/prompts/__init__.py +7 -0
- langroid/prompts/chat-gpt4-system-prompt.md +68 -0
- langroid/prompts/prompts_config.py +1 -1
- langroid/utils/__init__.py +10 -0
- langroid/utils/algorithms/__init__.py +3 -0
- langroid/utils/configuration.py +0 -1
- langroid/utils/constants.py +4 -0
- langroid/utils/logging.py +2 -5
- langroid/utils/output/__init__.py +15 -2
- langroid/utils/output/status.py +33 -0
- langroid/utils/pandas_utils.py +30 -0
- langroid/utils/pydantic_utils.py +446 -4
- langroid/utils/system.py +36 -1
- langroid/vector_store/__init__.py +34 -2
- langroid/vector_store/base.py +33 -2
- langroid/vector_store/chromadb.py +42 -13
- langroid/vector_store/lancedb.py +226 -60
- langroid/vector_store/meilisearch.py +7 -6
- langroid/vector_store/momento.py +3 -2
- langroid/vector_store/qdrantdb.py +82 -11
- {langroid-0.1.139.dist-info → langroid-0.1.219.dist-info}/METADATA +190 -129
- langroid-0.1.219.dist-info/RECORD +127 -0
- langroid/agent/special/recipient_validator_agent.py +0 -157
- langroid/parsing/json.py +0 -64
- langroid/utils/web/selenium_login.py +0 -36
- langroid-0.1.139.dist-info/RECORD +0 -103
- {langroid-0.1.139.dist-info → langroid-0.1.219.dist-info}/LICENSE +0 -0
- {langroid-0.1.139.dist-info → langroid-0.1.219.dist-info}/WHEEL +0 -0
langroid/__init__.py
CHANGED
@@ -20,9 +20,79 @@ from .agent.base import (
|
|
20
20
|
AgentConfig,
|
21
21
|
)
|
22
22
|
|
23
|
+
from .agent.batch import (
|
24
|
+
run_batch_tasks,
|
25
|
+
llm_response_batch,
|
26
|
+
agent_response_batch,
|
27
|
+
)
|
28
|
+
|
29
|
+
from .agent.chat_document import (
|
30
|
+
ChatDocument,
|
31
|
+
ChatDocMetaData,
|
32
|
+
)
|
33
|
+
|
34
|
+
from .agent.tool_message import (
|
35
|
+
ToolMessage,
|
36
|
+
)
|
37
|
+
|
23
38
|
from .agent.chat_agent import (
|
24
39
|
ChatAgent,
|
25
40
|
ChatAgentConfig,
|
26
41
|
)
|
27
42
|
|
28
43
|
from .agent.task import Task
|
44
|
+
|
45
|
+
try:
|
46
|
+
from .agent.callbacks.chainlit import (
|
47
|
+
ChainlitAgentCallbacks,
|
48
|
+
ChainlitTaskCallbacks,
|
49
|
+
ChainlitCallbackConfig,
|
50
|
+
)
|
51
|
+
|
52
|
+
chainlit_available = True
|
53
|
+
ChainlitAgentCallbacks
|
54
|
+
ChainlitTaskCallbacks
|
55
|
+
ChainlitCallbackConfig
|
56
|
+
except ImportError:
|
57
|
+
chainlit_available = False
|
58
|
+
|
59
|
+
|
60
|
+
from .mytypes import (
|
61
|
+
DocMetaData,
|
62
|
+
Document,
|
63
|
+
Entity,
|
64
|
+
)
|
65
|
+
|
66
|
+
__all__ = [
|
67
|
+
"mytypes",
|
68
|
+
"utils",
|
69
|
+
"parsing",
|
70
|
+
"prompts",
|
71
|
+
"cachedb",
|
72
|
+
"language_models",
|
73
|
+
"embedding_models",
|
74
|
+
"vector_store",
|
75
|
+
"agent",
|
76
|
+
"Agent",
|
77
|
+
"AgentConfig",
|
78
|
+
"ChatAgent",
|
79
|
+
"ChatAgentConfig",
|
80
|
+
"ChatDocument",
|
81
|
+
"ChatDocMetaData",
|
82
|
+
"Task",
|
83
|
+
"DocMetaData",
|
84
|
+
"Document",
|
85
|
+
"Entity",
|
86
|
+
"ToolMessage",
|
87
|
+
"run_batch_tasks",
|
88
|
+
"llm_response_batch",
|
89
|
+
"agent_response_batch",
|
90
|
+
]
|
91
|
+
if chainlit_available:
|
92
|
+
__all__.extend(
|
93
|
+
[
|
94
|
+
"ChainlitAgentCallbacks",
|
95
|
+
"ChainlitTaskCallbacks",
|
96
|
+
"ChainlitCallbackConfig",
|
97
|
+
]
|
98
|
+
)
|
langroid/agent/__init__.py
CHANGED
@@ -13,6 +13,28 @@ from . import base
|
|
13
13
|
from . import chat_document
|
14
14
|
from . import chat_agent
|
15
15
|
from . import task
|
16
|
+
from . import batch
|
16
17
|
from . import tool_message
|
17
18
|
from . import tools
|
18
19
|
from . import special
|
20
|
+
|
21
|
+
__all__ = [
|
22
|
+
"Agent",
|
23
|
+
"AgentConfig",
|
24
|
+
"ChatDocAttachment",
|
25
|
+
"ChatDocMetaData",
|
26
|
+
"ChatDocLoggerFields",
|
27
|
+
"ChatDocument",
|
28
|
+
"ChatAgent",
|
29
|
+
"ChatAgentConfig",
|
30
|
+
"ToolMessage",
|
31
|
+
"Task",
|
32
|
+
"base",
|
33
|
+
"chat_document",
|
34
|
+
"chat_agent",
|
35
|
+
"task",
|
36
|
+
"batch",
|
37
|
+
"tool_message",
|
38
|
+
"tools",
|
39
|
+
"special",
|
40
|
+
]
|
langroid/agent/base.py
CHANGED
@@ -4,6 +4,7 @@ import json
|
|
4
4
|
import logging
|
5
5
|
from abc import ABC
|
6
6
|
from contextlib import ExitStack
|
7
|
+
from types import SimpleNamespace
|
7
8
|
from typing import (
|
8
9
|
Any,
|
9
10
|
Callable,
|
@@ -21,6 +22,7 @@ from typing import (
|
|
21
22
|
from pydantic import BaseSettings, ValidationError
|
22
23
|
from rich import print
|
23
24
|
from rich.console import Console
|
25
|
+
from rich.markup import escape
|
24
26
|
from rich.prompt import Prompt
|
25
27
|
|
26
28
|
from langroid.agent.chat_document import ChatDocMetaData, ChatDocument
|
@@ -35,11 +37,12 @@ from langroid.language_models.base import (
|
|
35
37
|
)
|
36
38
|
from langroid.language_models.openai_gpt import OpenAIGPTConfig
|
37
39
|
from langroid.mytypes import Entity
|
38
|
-
from langroid.parsing.
|
40
|
+
from langroid.parsing.parse_json import extract_top_level_json
|
39
41
|
from langroid.parsing.parser import Parser, ParsingConfig
|
40
42
|
from langroid.prompts.prompts_config import PromptsConfig
|
41
43
|
from langroid.utils.configuration import settings
|
42
44
|
from langroid.utils.constants import NO_ANSWER
|
45
|
+
from langroid.utils.output import status
|
43
46
|
from langroid.vector_store.base import VectorStore, VectorStoreConfig
|
44
47
|
|
45
48
|
console = Console(quiet=settings.quiet)
|
@@ -62,6 +65,10 @@ class AgentConfig(BaseSettings):
|
|
62
65
|
show_stats: bool = True # show token usage/cost stats?
|
63
66
|
|
64
67
|
|
68
|
+
def noop_fn(*args: List[Any], **kwargs: Dict[str, Any]) -> None:
|
69
|
+
pass
|
70
|
+
|
71
|
+
|
65
72
|
class Agent(ABC):
|
66
73
|
"""
|
67
74
|
An Agent is an abstraction that encapsulates mainly two components:
|
@@ -73,7 +80,7 @@ class Agent(ABC):
|
|
73
80
|
information about any tool/function-calling messages that have been defined.
|
74
81
|
"""
|
75
82
|
|
76
|
-
def __init__(self, config: AgentConfig):
|
83
|
+
def __init__(self, config: AgentConfig = AgentConfig()):
|
77
84
|
self.config = config
|
78
85
|
self.lock = asyncio.Lock() # for async access to update self.llm.usage_cost
|
79
86
|
self.dialog: List[Tuple[str, str]] = [] # seq of LLM (prompt, response) tuples
|
@@ -90,6 +97,18 @@ class Agent(ABC):
|
|
90
97
|
self.parser: Optional[Parser] = (
|
91
98
|
Parser(config.parsing) if config.parsing else None
|
92
99
|
)
|
100
|
+
self.callbacks = SimpleNamespace(
|
101
|
+
start_llm_stream=lambda: noop_fn,
|
102
|
+
cancel_llm_stream=noop_fn,
|
103
|
+
finish_llm_stream=noop_fn,
|
104
|
+
show_llm_response=noop_fn,
|
105
|
+
show_agent_response=noop_fn,
|
106
|
+
get_user_response=None,
|
107
|
+
get_last_step=noop_fn,
|
108
|
+
set_parent_agent=noop_fn,
|
109
|
+
show_error_message=noop_fn,
|
110
|
+
show_start_response=noop_fn,
|
111
|
+
)
|
93
112
|
|
94
113
|
def entity_responders(
|
95
114
|
self,
|
@@ -253,6 +272,10 @@ class Agent(ABC):
|
|
253
272
|
]
|
254
273
|
return "\n\n".join(sample_convo)
|
255
274
|
|
275
|
+
def agent_response_template(self) -> ChatDocument:
|
276
|
+
"""Template for agent_response."""
|
277
|
+
return self._response_template(Entity.AGENT)
|
278
|
+
|
256
279
|
async def agent_response_async(
|
257
280
|
self,
|
258
281
|
msg: Optional[str | ChatDocument] = None,
|
@@ -290,6 +313,11 @@ class Agent(ABC):
|
|
290
313
|
if not settings.quiet:
|
291
314
|
console.print(f"[red]{self.indent}", end="")
|
292
315
|
print(f"[red]Agent: {results}")
|
316
|
+
maybe_json = len(extract_top_level_json(results)) > 0
|
317
|
+
self.callbacks.show_agent_response(
|
318
|
+
content=results,
|
319
|
+
language="json" if maybe_json else "text",
|
320
|
+
)
|
293
321
|
sender_name = self.config.name
|
294
322
|
if isinstance(msg, ChatDocument) and msg.function_call is not None:
|
295
323
|
# if result was from handling an LLM `function_call`,
|
@@ -307,6 +335,20 @@ class Agent(ABC):
|
|
307
335
|
),
|
308
336
|
)
|
309
337
|
|
338
|
+
def _response_template(self, e: Entity) -> ChatDocument:
|
339
|
+
"""Template for response from entity `e`."""
|
340
|
+
return ChatDocument(
|
341
|
+
content="",
|
342
|
+
tool_messages=[],
|
343
|
+
metadata=ChatDocMetaData(
|
344
|
+
source=e, sender=e, sender_name=self.config.name, tool_ids=[]
|
345
|
+
),
|
346
|
+
)
|
347
|
+
|
348
|
+
def user_response_template(self) -> ChatDocument:
|
349
|
+
"""Template for user_response."""
|
350
|
+
return self._response_template(Entity.USER)
|
351
|
+
|
310
352
|
async def user_response_async(
|
311
353
|
self,
|
312
354
|
msg: Optional[str | ChatDocument] = None,
|
@@ -334,11 +376,18 @@ class Agent(ABC):
|
|
334
376
|
elif not settings.interactive:
|
335
377
|
user_msg = ""
|
336
378
|
else:
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
379
|
+
if self.callbacks.get_user_response is not None:
|
380
|
+
# ask user with empty prompt: no need for prompt
|
381
|
+
# since user has seen the conversation so far.
|
382
|
+
# But non-empty prompt can be useful when Agent
|
383
|
+
# uses a tool that requires user input, or in other scenarios.
|
384
|
+
user_msg = self.callbacks.get_user_response(prompt="")
|
385
|
+
else:
|
386
|
+
user_msg = Prompt.ask(
|
387
|
+
f"[blue]{self.indent}Human "
|
388
|
+
"(respond or q, x to exit current level, "
|
389
|
+
f"or hit enter to continue)\n{self.indent}",
|
390
|
+
).strip()
|
342
391
|
|
343
392
|
tool_ids = []
|
344
393
|
if msg is not None and isinstance(msg, ChatDocument):
|
@@ -377,13 +426,6 @@ class Agent(ABC):
|
|
377
426
|
if self.llm is None:
|
378
427
|
return False
|
379
428
|
|
380
|
-
if isinstance(message, ChatDocument) and message.function_call is not None:
|
381
|
-
# LLM should not handle `function_call` messages,
|
382
|
-
# EVEN if message.function_call is not a legit function_call
|
383
|
-
# The OpenAI API raises error if there is a message in history
|
384
|
-
# from a non-Assistant role, with a `function_call` in it
|
385
|
-
return False
|
386
|
-
|
387
429
|
if message is not None and len(self.get_tool_messages(message)) > 0:
|
388
430
|
# if there is a valid "tool" message (either JSON or via `function_call`)
|
389
431
|
# then LLM cannot respond to it
|
@@ -391,6 +433,10 @@ class Agent(ABC):
|
|
391
433
|
|
392
434
|
return True
|
393
435
|
|
436
|
+
def llm_response_template(self) -> ChatDocument:
|
437
|
+
"""Template for llm_response."""
|
438
|
+
return self._response_template(Entity.LLM)
|
439
|
+
|
394
440
|
@no_type_check
|
395
441
|
async def llm_response_async(
|
396
442
|
self,
|
@@ -434,7 +480,7 @@ class Agent(ABC):
|
|
434
480
|
# streaming was enabled, AND we did not find a cached response.
|
435
481
|
# If we are here, it means the response has not yet been displayed.
|
436
482
|
cached = f"[red]{self.indent}(cached)[/red]" if response.cached else ""
|
437
|
-
print(cached + "[green]" + response.message)
|
483
|
+
print(cached + "[green]" + escape(response.message))
|
438
484
|
async with self.lock:
|
439
485
|
self.update_token_usage(
|
440
486
|
response,
|
@@ -472,7 +518,7 @@ class Agent(ABC):
|
|
472
518
|
with ExitStack() as stack: # for conditionally using rich spinner
|
473
519
|
if not self.llm.get_stream():
|
474
520
|
# show rich spinner only if not streaming!
|
475
|
-
cm =
|
521
|
+
cm = status("LLM responding to message...")
|
476
522
|
stack.enter_context(cm)
|
477
523
|
output_len = self.config.llm.max_output_tokens
|
478
524
|
if (
|
@@ -507,7 +553,7 @@ class Agent(ABC):
|
|
507
553
|
# If we are here, it means the response has not yet been displayed.
|
508
554
|
cached = f"[red]{self.indent}(cached)[/red]" if response.cached else ""
|
509
555
|
console.print(f"[green]{self.indent}", end="")
|
510
|
-
print(cached + "[green]" + response.message)
|
556
|
+
print(cached + "[green]" + escape(response.message))
|
511
557
|
self.update_token_usage(
|
512
558
|
response,
|
513
559
|
prompt,
|
@@ -520,17 +566,38 @@ class Agent(ABC):
|
|
520
566
|
cdoc.metadata.tool_ids = [] if isinstance(msg, str) else msg.metadata.tool_ids
|
521
567
|
return cdoc
|
522
568
|
|
569
|
+
def has_tool_message_attempt(self, msg: str | ChatDocument | None) -> bool:
|
570
|
+
"""Check whether msg contains a Tool/fn-call attempt (by the LLM)"""
|
571
|
+
if msg is None:
|
572
|
+
return False
|
573
|
+
try:
|
574
|
+
tools = self.get_tool_messages(msg)
|
575
|
+
return len(tools) > 0
|
576
|
+
except ValidationError:
|
577
|
+
# there is a tool/fn-call attempt but had a validation error,
|
578
|
+
# so we still consider this a tool message "attempt"
|
579
|
+
return True
|
580
|
+
return False
|
581
|
+
|
523
582
|
def get_tool_messages(self, msg: str | ChatDocument) -> List[ToolMessage]:
|
524
583
|
if isinstance(msg, str):
|
525
584
|
return self.get_json_tool_messages(msg)
|
585
|
+
if len(msg.tool_messages) > 0:
|
586
|
+
# We've already found tool_messages
|
587
|
+
# (either via OpenAI Fn-call or Langroid-native ToolMessage)
|
588
|
+
return msg.tool_messages
|
526
589
|
assert isinstance(msg, ChatDocument)
|
527
590
|
# when `content` is non-empty, we assume there will be no `function_call`
|
528
591
|
if msg.content != "":
|
529
|
-
|
592
|
+
tools = self.get_json_tool_messages(msg.content)
|
593
|
+
msg.tool_messages = tools
|
594
|
+
return tools
|
530
595
|
|
531
596
|
# otherwise, we look for a `function_call`
|
532
597
|
fun_call_cls = self.get_function_call_class(msg)
|
533
|
-
|
598
|
+
tools = [fun_call_cls] if fun_call_cls is not None else []
|
599
|
+
msg.tool_messages = tools
|
600
|
+
return tools
|
534
601
|
|
535
602
|
def get_json_tool_messages(self, input_str: str) -> List[ToolMessage]:
|
536
603
|
"""
|
@@ -554,7 +621,17 @@ class Agent(ABC):
|
|
554
621
|
tool_name = msg.function_call.name
|
555
622
|
tool_msg = msg.function_call.arguments or {}
|
556
623
|
if tool_name not in self.llm_tools_handled:
|
557
|
-
|
624
|
+
logger.warning(
|
625
|
+
f"""
|
626
|
+
The function_call '{tool_name}' is not handled
|
627
|
+
by the agent named '{self.config.name}'!
|
628
|
+
If you intended this agent to handle this function_call,
|
629
|
+
either the fn-call name is incorrectly generated by the LLM,
|
630
|
+
(in which case you may need to adjust your LLM instructions),
|
631
|
+
or you need to enable this agent to handle this fn-call.
|
632
|
+
"""
|
633
|
+
)
|
634
|
+
return None
|
558
635
|
tool_class = self.llm_tools_map[tool_name]
|
559
636
|
tool_msg.update(dict(request=tool_name))
|
560
637
|
tool = tool_class.parse_obj(tool_msg)
|
@@ -573,7 +650,7 @@ class Agent(ABC):
|
|
573
650
|
"""
|
574
651
|
tool_name = cast(ToolMessage, ve.model).default_value("request")
|
575
652
|
bad_field_errors = "\n".join(
|
576
|
-
[f"{e['loc']
|
653
|
+
[f"{e['loc']}: {e['msg']}" for e in ve.errors() if "loc" in e]
|
577
654
|
)
|
578
655
|
return f"""
|
579
656
|
There were one or more errors in your attempt to use the
|
@@ -617,7 +694,7 @@ class Agent(ABC):
|
|
617
694
|
|
618
695
|
results_list = [r for r in results if r is not None]
|
619
696
|
if len(results_list) == 0:
|
620
|
-
return self.handle_message_fallback(msg)
|
697
|
+
return None # self.handle_message_fallback(msg)
|
621
698
|
# there was a non-None result
|
622
699
|
chat_doc_results = [r for r in results_list if isinstance(r, ChatDocument)]
|
623
700
|
if len(chat_doc_results) > 1:
|
@@ -632,19 +709,13 @@ class Agent(ABC):
|
|
632
709
|
|
633
710
|
str_doc_results = [r for r in results_list if isinstance(r, str)]
|
634
711
|
final = "\n".join(str_doc_results)
|
635
|
-
if final == "":
|
636
|
-
logger.warning(
|
637
|
-
"""final result from a tool handler should not be empty str, since
|
638
|
-
it would be considered an invalid result and other responders
|
639
|
-
will be tried, and we may not necessarily want that"""
|
640
|
-
)
|
641
712
|
return final
|
642
713
|
|
643
714
|
def handle_message_fallback(
|
644
715
|
self, msg: str | ChatDocument
|
645
716
|
) -> str | ChatDocument | None:
|
646
717
|
"""
|
647
|
-
Fallback method to handle possible "tool" msg if
|
718
|
+
Fallback method to handle possible "tool" msg if no other method applies
|
648
719
|
or if an error is thrown.
|
649
720
|
This method can be overridden by subclasses.
|
650
721
|
|
@@ -659,7 +730,11 @@ class Agent(ABC):
|
|
659
730
|
def _get_one_tool_message(self, json_str: str) -> Optional[ToolMessage]:
|
660
731
|
json_data = json.loads(json_str)
|
661
732
|
request = json_data.get("request")
|
662
|
-
if
|
733
|
+
if (
|
734
|
+
request is None
|
735
|
+
or not (isinstance(request, str))
|
736
|
+
or request not in self.llm_tools_handled
|
737
|
+
):
|
663
738
|
return None
|
664
739
|
|
665
740
|
message_class = self.llm_tools_map.get(request)
|
@@ -702,7 +777,13 @@ class Agent(ABC):
|
|
702
777
|
if isinstance(prompt, str):
|
703
778
|
return self.parser.num_tokens(prompt)
|
704
779
|
else:
|
705
|
-
return sum(
|
780
|
+
return sum(
|
781
|
+
[
|
782
|
+
self.parser.num_tokens(m.content)
|
783
|
+
+ self.parser.num_tokens(str(m.function_call or ""))
|
784
|
+
for m in prompt
|
785
|
+
]
|
786
|
+
)
|
706
787
|
|
707
788
|
def _get_response_stats(
|
708
789
|
self, chat_length: int, tot_cost: float, response: LLMResponse
|
@@ -727,11 +808,17 @@ class Agent(ABC):
|
|
727
808
|
assert isinstance(self.llm, LanguageModel)
|
728
809
|
context_length = self.llm.chat_context_length()
|
729
810
|
max_out = self.config.llm.max_output_tokens
|
811
|
+
|
812
|
+
llm_model = (
|
813
|
+
"no-LLM" if self.config.llm is None else self.llm.config.chat_model
|
814
|
+
)
|
815
|
+
|
730
816
|
return (
|
731
|
-
f"[bold]Stats:[/bold] [magenta]
|
817
|
+
f"[bold]Stats:[/bold] [magenta]N_MSG={chat_length}, "
|
732
818
|
f"TOKENS: in={in_tokens}, out={out_tokens}, "
|
733
819
|
f"max={max_out}, ctx={context_length}, "
|
734
|
-
f"COST: now=${llm_response_cost}, cumul=${cumul_cost}
|
820
|
+
f"COST: now=${llm_response_cost}, cumul=${cumul_cost} "
|
821
|
+
f"[bold]({llm_model})[/bold][/magenta]"
|
735
822
|
)
|
736
823
|
return ""
|
737
824
|
|