langroid 0.11.0__tar.gz → 0.13.0__tar.gz
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-0.11.0 → langroid-0.13.0}/PKG-INFO +4 -2
- {langroid-0.11.0 → langroid-0.13.0}/README.md +3 -1
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/batch.py +116 -28
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/doc_chat_agent.py +19 -14
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/task.py +2 -1
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/mock_lm.py +23 -3
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/search.py +14 -11
- {langroid-0.11.0 → langroid-0.13.0}/pyproject.toml +1 -1
- {langroid-0.11.0 → langroid-0.13.0}/LICENSE +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/callbacks/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/callbacks/chainlit.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/chat_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/chat_document.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/helpers.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/junk +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/openai_assistant.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_doc_chat_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_rag/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_rag/critic_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_rag/lance_rag_task.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_rag/query_planner_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/lance_tools.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/neo4j/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/neo4j/csv_kg_chat.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/neo4j/utils/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/neo4j/utils/system_message.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/relevance_extractor_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/retriever_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/sql_chat_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/description_extractors.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/populate_metadata.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/system_message.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/tools.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/table_chat_agent.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/structured_message.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tool_message.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/duckduckgo_search_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/extract_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/generator_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/google_search_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/metaphor_search_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/note_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/orchestration.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/recipient_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/retrieval_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/rewind_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/run_python_code.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/tools/segment_extract_tool.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent/typed_task.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/agent_config.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/cachedb/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/cachedb/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/cachedb/momento_cachedb.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/cachedb/redis_cachedb.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/clustering.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/models.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/protoc/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/protoc/embeddings.proto +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/protoc/embeddings_pb2.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/embedding_models/remote_embeds.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/exceptions.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/.chainlit/config.toml +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/.chainlit/translations/en-US.json +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/azure_openai.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/config.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/openai_gpt.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/hf_formatter.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/llama2_formatter.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/utils.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/mytypes.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/agent_chats.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/code-parsing.md +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/code_parser.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/config.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/document_parser.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/image_text.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/para_sentence_split.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/parse_json.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/parser.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/repo_loader.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/routing.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/spider.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/table_loader.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/url_loader.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/url_loader_cookies.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/urls.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/utils.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/parsing/web_search.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/prompts/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/prompts/chat-gpt4-system-prompt.md +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/prompts/dialog.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/prompts/prompts_config.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/prompts/templates.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/pydantic_v1/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/pydantic_v1/main.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/.chainlit/config.toml +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/.chainlit/translations/en-US.json +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/algorithms/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/algorithms/graph.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/configuration.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/constants.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/docker.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/globals.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/llms/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/llms/strings.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/logging.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/object_registry.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/output/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/output/citations.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/output/printing.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/output/status.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/pandas_utils.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/pydantic_utils.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/system.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/types.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/web/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/utils/web/login.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/__init__.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/base.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/chromadb.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/lancedb.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/meilisearch.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/momento.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/qdrant_cloud.py +0 -0
- {langroid-0.11.0 → langroid-0.13.0}/langroid/vector_store/qdrantdb.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: langroid
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.13.0
|
4
4
|
Summary: Harness LLMs with Multi-Agent Programming
|
5
5
|
License: MIT
|
6
6
|
Author: Prasad Chalasani
|
@@ -239,7 +239,9 @@ teacher_task.run()
|
|
239
239
|
<details>
|
240
240
|
<summary> <b>Click to expand</b></summary>
|
241
241
|
|
242
|
-
- **Aug 2024:**
|
242
|
+
- **Aug 2024:**
|
243
|
+
- **[0.11.0](https://github.com/langroid/langroid/releases/tag/0.11.0)** Polymorphic `Task.run(), Task.run_async`.
|
244
|
+
- **[0.10.0](https://github.com/langroid/langroid/releases/tag/0.10.0)** Allow tool handlers to return arbitrary result type, including other tools.
|
243
245
|
- **[0.9.0](https://github.com/langroid/langroid/releases/tag/0.9.0)** Orchestration Tools, to signal various task statuses, and to pass messages between agents.
|
244
246
|
- **[0.7.0](https://github.com/langroid/langroid/releases/tag/0.7.0)** OpenAI tools API support, including multi-tools.
|
245
247
|
- **Jul 2024:**
|
@@ -132,7 +132,9 @@ teacher_task.run()
|
|
132
132
|
<details>
|
133
133
|
<summary> <b>Click to expand</b></summary>
|
134
134
|
|
135
|
-
- **Aug 2024:**
|
135
|
+
- **Aug 2024:**
|
136
|
+
- **[0.11.0](https://github.com/langroid/langroid/releases/tag/0.11.0)** Polymorphic `Task.run(), Task.run_async`.
|
137
|
+
- **[0.10.0](https://github.com/langroid/langroid/releases/tag/0.10.0)** Allow tool handlers to return arbitrary result type, including other tools.
|
136
138
|
- **[0.9.0](https://github.com/langroid/langroid/releases/tag/0.9.0)** Orchestration Tools, to signal various task statuses, and to pass messages between agents.
|
137
139
|
- **[0.7.0](https://github.com/langroid/langroid/releases/tag/0.7.0)** OpenAI tools API support, including multi-tools.
|
138
140
|
- **Jul 2024:**
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import asyncio
|
2
2
|
import copy
|
3
3
|
import inspect
|
4
|
-
from typing import Any, Callable, Coroutine, Iterable, List, Optional, TypeVar
|
4
|
+
from typing import Any, Callable, Coroutine, Iterable, List, Optional, TypeVar, cast
|
5
5
|
|
6
6
|
from dotenv import load_dotenv
|
7
7
|
|
@@ -26,6 +26,7 @@ def run_batch_task_gen(
|
|
26
26
|
items: list[T],
|
27
27
|
input_map: Callable[[T], str | ChatDocument] = lambda x: str(x),
|
28
28
|
output_map: Callable[[ChatDocument | None], U] = lambda x: x, # type: ignore
|
29
|
+
stop_on_first_result: bool = False,
|
29
30
|
sequential: bool = True,
|
30
31
|
batch_size: Optional[int] = None,
|
31
32
|
turns: int = -1,
|
@@ -33,7 +34,7 @@ def run_batch_task_gen(
|
|
33
34
|
handle_exceptions: bool = False,
|
34
35
|
max_cost: float = 0.0,
|
35
36
|
max_tokens: int = 0,
|
36
|
-
) -> list[U]:
|
37
|
+
) -> list[Optional[U]]:
|
37
38
|
"""
|
38
39
|
Generate and run copies of a task async/concurrently one per item in `items` list.
|
39
40
|
For each item, apply `input_map` to get the initial message to process.
|
@@ -44,7 +45,13 @@ def run_batch_task_gen(
|
|
44
45
|
input_map (Callable[[T], str|ChatDocument]): function to map item to
|
45
46
|
initial message to process
|
46
47
|
output_map (Callable[[ChatDocument|str], U]): function to map result
|
47
|
-
to final result
|
48
|
+
to final result. If stop_on_first_result is enabled, then
|
49
|
+
map any invalid output to None. We continue until some non-None
|
50
|
+
result is obtained.
|
51
|
+
stop_on_first_result (bool): whether to stop after the first valid
|
52
|
+
(not-None) result. In this case all other tasks are
|
53
|
+
cancelled, and their corresponding result is None in the
|
54
|
+
returned list.
|
48
55
|
sequential (bool): whether to run sequentially
|
49
56
|
(e.g. some APIs such as ooba don't support concurrent requests)
|
50
57
|
batch_size (Optional[int]): The number of tasks to run at a time,
|
@@ -57,39 +64,91 @@ def run_batch_task_gen(
|
|
57
64
|
|
58
65
|
|
59
66
|
Returns:
|
60
|
-
list[
|
67
|
+
list[Optional[U]]: list of final results. Always list[U] if
|
68
|
+
`stop_on_first_result` is disabled
|
61
69
|
"""
|
62
70
|
inputs = [input_map(item) for item in items]
|
63
71
|
|
64
|
-
async def _do_task(
|
72
|
+
async def _do_task(
|
73
|
+
input: str | ChatDocument,
|
74
|
+
i: int,
|
75
|
+
return_idx: Optional[int] = None,
|
76
|
+
) -> BaseException | Optional[ChatDocument] | tuple[int, Optional[ChatDocument]]:
|
65
77
|
task_i = gen_task(i)
|
66
78
|
if task_i.agent.llm is not None:
|
67
79
|
task_i.agent.llm.set_stream(False)
|
68
80
|
task_i.agent.config.show_stats = False
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
81
|
+
try:
|
82
|
+
result = await task_i.run_async(
|
83
|
+
input, turns=turns, max_cost=max_cost, max_tokens=max_tokens
|
84
|
+
)
|
85
|
+
if return_idx is not None:
|
86
|
+
return return_idx, result
|
87
|
+
else:
|
88
|
+
return result
|
89
|
+
except asyncio.CancelledError as e:
|
90
|
+
task_i.kill()
|
91
|
+
if handle_exceptions:
|
92
|
+
return e
|
93
|
+
else:
|
94
|
+
raise e
|
95
|
+
except BaseException as e:
|
96
|
+
if handle_exceptions:
|
97
|
+
return e
|
98
|
+
else:
|
99
|
+
raise e
|
74
100
|
|
75
101
|
async def _do_all(
|
76
102
|
inputs: Iterable[str | ChatDocument], start_idx: int = 0
|
77
|
-
) -> list[U]:
|
103
|
+
) -> list[Optional[U]]:
|
78
104
|
results: list[Optional[ChatDocument]] = []
|
79
|
-
if
|
80
|
-
|
105
|
+
if stop_on_first_result:
|
106
|
+
outputs: list[Optional[U]] = [None] * len(list(inputs))
|
107
|
+
tasks = set(
|
108
|
+
asyncio.create_task(_do_task(input, i + start_idx, return_idx=i))
|
109
|
+
for i, input in enumerate(inputs)
|
110
|
+
)
|
111
|
+
while tasks:
|
81
112
|
try:
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
113
|
+
done, tasks = await asyncio.wait(
|
114
|
+
tasks, return_when=asyncio.FIRST_COMPLETED
|
115
|
+
)
|
116
|
+
for task in done:
|
117
|
+
idx_result = task.result()
|
118
|
+
if not isinstance(idx_result, tuple):
|
119
|
+
continue
|
120
|
+
index, output = idx_result
|
121
|
+
outputs[index] = output_map(output)
|
122
|
+
|
123
|
+
if any(r is not None for r in outputs):
|
124
|
+
return outputs
|
125
|
+
finally:
|
126
|
+
# Cancel all remaining tasks
|
127
|
+
for task in tasks:
|
128
|
+
task.cancel()
|
129
|
+
# Wait for cancellations to complete
|
130
|
+
try:
|
131
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
132
|
+
except BaseException as e:
|
133
|
+
if not handle_exceptions:
|
134
|
+
raise e
|
135
|
+
return outputs
|
136
|
+
elif sequential:
|
137
|
+
for i, input in enumerate(inputs):
|
138
|
+
result: Optional[ChatDocument] | BaseException = await _do_task(
|
139
|
+
input, i + start_idx
|
140
|
+
) # type: ignore
|
141
|
+
|
142
|
+
if isinstance(result, BaseException):
|
143
|
+
result = None
|
144
|
+
|
88
145
|
results.append(result)
|
89
146
|
else:
|
90
|
-
results_with_exceptions =
|
91
|
-
|
92
|
-
|
147
|
+
results_with_exceptions = cast(
|
148
|
+
list[Optional[ChatDocument | BaseException]],
|
149
|
+
await asyncio.gather(
|
150
|
+
*(_do_task(input, i + start_idx) for i, input in enumerate(inputs)),
|
151
|
+
),
|
93
152
|
)
|
94
153
|
|
95
154
|
results = [
|
@@ -99,7 +158,7 @@ def run_batch_task_gen(
|
|
99
158
|
|
100
159
|
return list(map(output_map, results))
|
101
160
|
|
102
|
-
results: List[U] = []
|
161
|
+
results: List[Optional[U]] = []
|
103
162
|
if batch_size is None:
|
104
163
|
msg = message or f"[bold green]Running {len(items)} tasks:"
|
105
164
|
|
@@ -113,8 +172,11 @@ def run_batch_task_gen(
|
|
113
172
|
complete_str = f", {start_idx} complete" if start_idx > 0 else ""
|
114
173
|
msg = message or f"[bold green]Running {len(items)} tasks{complete_str}:"
|
115
174
|
|
116
|
-
|
117
|
-
results.extend(
|
175
|
+
if stop_on_first_result and any(r is not None for r in results):
|
176
|
+
results.extend([None] * len(batch))
|
177
|
+
else:
|
178
|
+
with status(msg), SuppressLoggerWarnings():
|
179
|
+
results.extend(asyncio.run(_do_all(batch, start_idx=start_idx)))
|
118
180
|
|
119
181
|
return results
|
120
182
|
|
@@ -124,12 +186,13 @@ def run_batch_tasks(
|
|
124
186
|
items: list[T],
|
125
187
|
input_map: Callable[[T], str | ChatDocument] = lambda x: str(x),
|
126
188
|
output_map: Callable[[ChatDocument | None], U] = lambda x: x, # type: ignore
|
189
|
+
stop_on_first_result: bool = False,
|
127
190
|
sequential: bool = True,
|
128
191
|
batch_size: Optional[int] = None,
|
129
192
|
turns: int = -1,
|
130
193
|
max_cost: float = 0.0,
|
131
194
|
max_tokens: int = 0,
|
132
|
-
) -> List[U]:
|
195
|
+
) -> List[Optional[U]]:
|
133
196
|
"""
|
134
197
|
Run copies of `task` async/concurrently one per item in `items` list.
|
135
198
|
For each item, apply `input_map` to get the initial message to process.
|
@@ -150,7 +213,8 @@ def run_batch_tasks(
|
|
150
213
|
max_tokens: int: maximum token usage (in and out) (default 0 for unlimited)
|
151
214
|
|
152
215
|
Returns:
|
153
|
-
list[
|
216
|
+
list[Optional[U]]: list of final results. Always list[U] if
|
217
|
+
`stop_on_first_result` is disabled
|
154
218
|
"""
|
155
219
|
message = f"[bold green]Running {len(items)} copies of {task.name}..."
|
156
220
|
return run_batch_task_gen(
|
@@ -158,6 +222,7 @@ def run_batch_tasks(
|
|
158
222
|
items,
|
159
223
|
input_map,
|
160
224
|
output_map,
|
225
|
+
stop_on_first_result,
|
161
226
|
sequential,
|
162
227
|
batch_size,
|
163
228
|
turns,
|
@@ -176,6 +241,7 @@ def run_batch_agent_method(
|
|
176
241
|
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
177
242
|
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
178
243
|
sequential: bool = True,
|
244
|
+
stop_on_first_result: bool = False,
|
179
245
|
) -> List[Any]:
|
180
246
|
"""
|
181
247
|
Run the `method` on copies of `agent`, async/concurrently one per
|
@@ -225,7 +291,25 @@ def run_batch_agent_method(
|
|
225
291
|
return output_map(result)
|
226
292
|
|
227
293
|
async def _do_all() -> List[Any]:
|
228
|
-
if
|
294
|
+
if stop_on_first_result:
|
295
|
+
tasks = [
|
296
|
+
asyncio.create_task(_do_task(input, i))
|
297
|
+
for i, input in enumerate(inputs)
|
298
|
+
]
|
299
|
+
results = [None] * len(tasks)
|
300
|
+
try:
|
301
|
+
done, pending = await asyncio.wait(
|
302
|
+
tasks, return_when=asyncio.FIRST_COMPLETED
|
303
|
+
)
|
304
|
+
for task in done:
|
305
|
+
index = tasks.index(task)
|
306
|
+
results[index] = await task
|
307
|
+
finally:
|
308
|
+
for task in pending:
|
309
|
+
task.cancel()
|
310
|
+
await asyncio.gather(*pending, return_exceptions=True)
|
311
|
+
return results
|
312
|
+
elif sequential:
|
229
313
|
results = []
|
230
314
|
for i, input in enumerate(inputs):
|
231
315
|
result = await _do_task(input, i)
|
@@ -249,6 +333,7 @@ def llm_response_batch(
|
|
249
333
|
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
250
334
|
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
251
335
|
sequential: bool = True,
|
336
|
+
stop_on_first_result: bool = False,
|
252
337
|
) -> List[Any]:
|
253
338
|
return run_batch_agent_method(
|
254
339
|
agent,
|
@@ -257,6 +342,7 @@ def llm_response_batch(
|
|
257
342
|
input_map=input_map,
|
258
343
|
output_map=output_map,
|
259
344
|
sequential=sequential,
|
345
|
+
stop_on_first_result=stop_on_first_result,
|
260
346
|
)
|
261
347
|
|
262
348
|
|
@@ -266,6 +352,7 @@ def agent_response_batch(
|
|
266
352
|
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
267
353
|
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
268
354
|
sequential: bool = True,
|
355
|
+
stop_on_first_result: bool = False,
|
269
356
|
) -> List[Any]:
|
270
357
|
return run_batch_agent_method(
|
271
358
|
agent,
|
@@ -274,4 +361,5 @@ def agent_response_batch(
|
|
274
361
|
input_map=input_map,
|
275
362
|
output_map=output_map,
|
276
363
|
sequential=sequential,
|
364
|
+
stop_on_first_result=stop_on_first_result,
|
277
365
|
)
|
@@ -49,7 +49,6 @@ from langroid.parsing.search import (
|
|
49
49
|
from langroid.parsing.table_loader import describe_dataframe
|
50
50
|
from langroid.parsing.url_loader import URLLoader
|
51
51
|
from langroid.parsing.urls import get_list_from_user, get_urls_paths_bytes_indices
|
52
|
-
from langroid.parsing.utils import batched
|
53
52
|
from langroid.prompts.prompts_config import PromptsConfig
|
54
53
|
from langroid.prompts.templates import SUMMARY_ANSWER_PROMPT_GPT4
|
55
54
|
from langroid.utils.constants import NO_ANSWER
|
@@ -137,7 +136,6 @@ class DocChatAgentConfig(ChatAgentConfig):
|
|
137
136
|
rerank_diversity: bool = True # rerank to maximize diversity?
|
138
137
|
rerank_periphery: bool = True # rerank to avoid Lost In the Middle effect?
|
139
138
|
rerank_after_adding_context: bool = True # rerank after adding context window?
|
140
|
-
embed_batch_size: int = 500 # get embedding of at most this many at a time
|
141
139
|
cache: bool = True # cache results
|
142
140
|
debug: bool = False
|
143
141
|
stream: bool = True # allow streaming where needed
|
@@ -400,7 +398,11 @@ class DocChatAgent(ChatAgent):
|
|
400
398
|
if split:
|
401
399
|
docs = self.parser.split(docs)
|
402
400
|
else:
|
403
|
-
self.
|
401
|
+
if self.config.n_neighbor_chunks > 0:
|
402
|
+
self.parser.add_window_ids(docs)
|
403
|
+
# we're not splitting, so we mark each doc as a chunk
|
404
|
+
for d in docs:
|
405
|
+
d.metadata.is_chunk = True
|
404
406
|
if self.vecdb is None:
|
405
407
|
raise ValueError("VecDB not set")
|
406
408
|
|
@@ -422,10 +424,9 @@ class DocChatAgent(ChatAgent):
|
|
422
424
|
+ d.content
|
423
425
|
)
|
424
426
|
docs = docs[: self.config.parsing.max_chunks]
|
425
|
-
#
|
426
|
-
|
427
|
-
|
428
|
-
self.vecdb.add_documents(batch)
|
427
|
+
# vecdb should take care of adding docs in batches;
|
428
|
+
# batching can be controlled via vecdb.config.batch_size
|
429
|
+
self.vecdb.add_documents(docs)
|
429
430
|
self.original_docs_length = self.doc_length(docs)
|
430
431
|
self.setup_documents(docs, filter=self.config.filter)
|
431
432
|
return len(docs)
|
@@ -894,7 +895,9 @@ class DocChatAgent(ChatAgent):
|
|
894
895
|
)
|
895
896
|
return docs_scores
|
896
897
|
|
897
|
-
def get_fuzzy_matches(
|
898
|
+
def get_fuzzy_matches(
|
899
|
+
self, query: str, multiple: int
|
900
|
+
) -> List[Tuple[Document, float]]:
|
898
901
|
# find similar docs using fuzzy matching:
|
899
902
|
# these may sometimes be more likely to contain a relevant verbatim extract
|
900
903
|
with status("[cyan]Finding fuzzy matches in chunks..."):
|
@@ -909,8 +912,8 @@ class DocChatAgent(ChatAgent):
|
|
909
912
|
self.chunked_docs,
|
910
913
|
self.chunked_docs_clean,
|
911
914
|
k=self.config.parsing.n_similar_docs * multiple,
|
912
|
-
words_before=self.config.n_fuzzy_neighbor_words,
|
913
|
-
words_after=self.config.n_fuzzy_neighbor_words,
|
915
|
+
words_before=self.config.n_fuzzy_neighbor_words or None,
|
916
|
+
words_after=self.config.n_fuzzy_neighbor_words or None,
|
914
917
|
)
|
915
918
|
return fuzzy_match_docs
|
916
919
|
|
@@ -1127,12 +1130,14 @@ class DocChatAgent(ChatAgent):
|
|
1127
1130
|
# ]
|
1128
1131
|
|
1129
1132
|
if self.config.use_bm25_search:
|
1133
|
+
# TODO: Add score threshold in config
|
1130
1134
|
docs_scores = self.get_similar_chunks_bm25(query, retrieval_multiple)
|
1131
1135
|
passages += [d for (d, _) in docs_scores]
|
1132
1136
|
|
1133
1137
|
if self.config.use_fuzzy_match:
|
1134
|
-
|
1135
|
-
|
1138
|
+
# TODO: Add score threshold in config
|
1139
|
+
fuzzy_match_doc_scores = self.get_fuzzy_matches(query, retrieval_multiple)
|
1140
|
+
passages += [d for (d, _) in fuzzy_match_doc_scores]
|
1136
1141
|
|
1137
1142
|
# keep unique passages
|
1138
1143
|
id2passage = {p.id(): p for p in passages}
|
@@ -1253,12 +1258,12 @@ class DocChatAgent(ChatAgent):
|
|
1253
1258
|
interactive=False,
|
1254
1259
|
)
|
1255
1260
|
|
1256
|
-
extracts = run_batch_tasks(
|
1261
|
+
extracts: list[str] = run_batch_tasks(
|
1257
1262
|
task,
|
1258
1263
|
passages,
|
1259
1264
|
input_map=lambda msg: msg.content,
|
1260
1265
|
output_map=lambda ans: ans.content if ans is not None else NO_ANSWER,
|
1261
|
-
)
|
1266
|
+
) # type: ignore
|
1262
1267
|
|
1263
1268
|
# Caution: Retain ALL other fields in the Documents (which could be
|
1264
1269
|
# other than just `content` and `metadata`), while simply replacing
|
@@ -1000,9 +1000,10 @@ class Task:
|
|
1000
1000
|
and not self.human_tried
|
1001
1001
|
and not self.agent.has_tool_message_attempt(self.pending_message)
|
1002
1002
|
):
|
1003
|
-
# When in interactive mode,
|
1004
1003
|
# Give human first chance if they haven't been tried in last step,
|
1005
1004
|
# and the msg is not a tool-call attempt;
|
1005
|
+
# (When `interactive=False`, human is only allowed to respond only if
|
1006
|
+
# if explicitly addressed)
|
1006
1007
|
# This ensures human gets a chance to respond,
|
1007
1008
|
# other than to a LLM tool-call.
|
1008
1009
|
# When there's a tool msg attempt we want the
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Mock Language Model for testing"""
|
2
2
|
|
3
|
-
from typing import Callable, Dict, List, Optional, Union
|
3
|
+
from typing import Awaitable, Callable, Dict, List, Optional, Union
|
4
4
|
|
5
5
|
import langroid.language_models as lm
|
6
6
|
from langroid.language_models import LLMResponse
|
@@ -28,6 +28,7 @@ class MockLMConfig(LLMConfig):
|
|
28
28
|
|
29
29
|
response_dict: Dict[str, str] = {}
|
30
30
|
response_fn: Callable[[str], None | str] = none_fn
|
31
|
+
response_fn_async: Optional[Callable[[str], Awaitable[Optional[str]]]] = None
|
31
32
|
default_response: str = "Mock response"
|
32
33
|
|
33
34
|
type: str = "mock"
|
@@ -52,6 +53,25 @@ class MockLM(LanguageModel):
|
|
52
53
|
cached=False,
|
53
54
|
)
|
54
55
|
|
56
|
+
async def _response_async(self, msg: str) -> LLMResponse:
|
57
|
+
# response is based on this fallback order:
|
58
|
+
# - response_dict
|
59
|
+
# - response_fn_async
|
60
|
+
# - response_fn
|
61
|
+
# - default_response
|
62
|
+
if self.config.response_fn_async is not None:
|
63
|
+
response = await self.config.response_fn_async(msg)
|
64
|
+
else:
|
65
|
+
response = self.config.response_fn(msg)
|
66
|
+
|
67
|
+
mapped_response = self.config.response_dict.get(
|
68
|
+
msg, response or self.config.default_response
|
69
|
+
)
|
70
|
+
return lm.LLMResponse(
|
71
|
+
message=to_string(mapped_response),
|
72
|
+
cached=False,
|
73
|
+
)
|
74
|
+
|
55
75
|
def chat(
|
56
76
|
self,
|
57
77
|
messages: Union[str, List[lm.LLMMessage]],
|
@@ -80,7 +100,7 @@ class MockLM(LanguageModel):
|
|
80
100
|
Mock chat function for testing
|
81
101
|
"""
|
82
102
|
last_msg = messages[-1].content if isinstance(messages, list) else messages
|
83
|
-
return self.
|
103
|
+
return await self._response_async(last_msg)
|
84
104
|
|
85
105
|
def generate(self, prompt: str, max_tokens: int = 200) -> lm.LLMResponse:
|
86
106
|
"""
|
@@ -92,7 +112,7 @@ class MockLM(LanguageModel):
|
|
92
112
|
"""
|
93
113
|
Mock generate function for testing
|
94
114
|
"""
|
95
|
-
return self.
|
115
|
+
return await self._response_async(prompt)
|
96
116
|
|
97
117
|
def get_stream(self) -> bool:
|
98
118
|
return False
|
@@ -27,7 +27,7 @@ def find_fuzzy_matches_in_docs(
|
|
27
27
|
k: int,
|
28
28
|
words_before: int | None = None,
|
29
29
|
words_after: int | None = None,
|
30
|
-
) -> List[Document]:
|
30
|
+
) -> List[Tuple[Document, float]]:
|
31
31
|
"""
|
32
32
|
Find approximate matches of the query in the docs and return surrounding
|
33
33
|
characters.
|
@@ -35,6 +35,7 @@ def find_fuzzy_matches_in_docs(
|
|
35
35
|
Args:
|
36
36
|
query (str): The search string.
|
37
37
|
docs (List[Document]): List of Document objects to search through.
|
38
|
+
docs_clean (List[Document]): List of Document objects with cleaned content.
|
38
39
|
k (int): Number of best matches to return.
|
39
40
|
words_before (int|None): Number of words to include before each match.
|
40
41
|
Default None => return max
|
@@ -42,8 +43,7 @@ def find_fuzzy_matches_in_docs(
|
|
42
43
|
Default None => return max
|
43
44
|
|
44
45
|
Returns:
|
45
|
-
List[Document]: List of
|
46
|
-
including the given number of words around the match.
|
46
|
+
List[Tuple[Document,float]]: List of (Document, score) tuples.
|
47
47
|
"""
|
48
48
|
if len(docs) == 0:
|
49
49
|
return []
|
@@ -54,19 +54,19 @@ def find_fuzzy_matches_in_docs(
|
|
54
54
|
scorer=fuzz.partial_ratio,
|
55
55
|
)
|
56
56
|
|
57
|
-
real_matches = [m for m, score in best_matches if score > 50]
|
57
|
+
real_matches = [(m, score) for m, score in best_matches if score > 50]
|
58
58
|
# find the original docs that corresponding to the matches
|
59
59
|
orig_doc_matches = []
|
60
|
-
for i, m in enumerate(real_matches):
|
60
|
+
for i, (m, s) in enumerate(real_matches):
|
61
61
|
for j, doc_clean in enumerate(docs_clean):
|
62
62
|
if m in doc_clean.content:
|
63
|
-
orig_doc_matches.append(docs[j])
|
63
|
+
orig_doc_matches.append((docs[j], s))
|
64
64
|
break
|
65
65
|
if words_after is None and words_before is None:
|
66
66
|
return orig_doc_matches
|
67
67
|
if len(orig_doc_matches) == 0:
|
68
68
|
return []
|
69
|
-
if set(orig_doc_matches[0].__fields__) != {"content", "metadata"}:
|
69
|
+
if set(orig_doc_matches[0][0].__fields__) != {"content", "metadata"}:
|
70
70
|
# If there are fields beyond just content and metadata,
|
71
71
|
# we do NOT want to create new document objects with content fields
|
72
72
|
# based on words_before and words_after, since we don't know how to
|
@@ -74,7 +74,7 @@ def find_fuzzy_matches_in_docs(
|
|
74
74
|
return orig_doc_matches
|
75
75
|
|
76
76
|
contextual_matches = []
|
77
|
-
for match in orig_doc_matches:
|
77
|
+
for match, score in orig_doc_matches:
|
78
78
|
choice_text = match.content
|
79
79
|
contexts = []
|
80
80
|
while choice_text != "":
|
@@ -89,9 +89,12 @@ def find_fuzzy_matches_in_docs(
|
|
89
89
|
choice_text = " ".join(words[end_pos:])
|
90
90
|
if len(contexts) > 0:
|
91
91
|
contextual_matches.append(
|
92
|
-
|
93
|
-
|
94
|
-
|
92
|
+
(
|
93
|
+
Document(
|
94
|
+
content=" ... ".join(contexts),
|
95
|
+
metadata=match.metadata,
|
96
|
+
),
|
97
|
+
score,
|
95
98
|
)
|
96
99
|
)
|
97
100
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{langroid-0.11.0 → langroid-0.13.0}/langroid/agent/special/sql/utils/description_extractors.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/.chainlit/translations/en-US.json
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/hf_formatter.py
RENAMED
File without changes
|
{langroid-0.11.0 → langroid-0.13.0}/langroid/language_models/prompt_formatter/llama2_formatter.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|