langroid 0.1.85__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 +95 -0
- langroid/agent/__init__.py +40 -0
- langroid/agent/base.py +222 -91
- langroid/agent/batch.py +264 -0
- langroid/agent/callbacks/chainlit.py +608 -0
- langroid/agent/chat_agent.py +247 -101
- langroid/agent/chat_document.py +41 -4
- langroid/agent/openai_assistant.py +842 -0
- langroid/agent/special/__init__.py +50 -0
- langroid/agent/special/doc_chat_agent.py +837 -141
- 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 +127 -0
- langroid/agent/special/retriever_agent.py +32 -198
- langroid/agent/special/sql/__init__.py +11 -0
- langroid/agent/special/sql/sql_chat_agent.py +47 -23
- langroid/agent/special/sql/utils/__init__.py +22 -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 +475 -122
- langroid/agent/tool_message.py +75 -13
- langroid/agent/tools/__init__.py +13 -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 +16 -29
- langroid/agent/tools/run_python_code.py +60 -0
- langroid/agent/tools/sciphi_search_rag_tool.py +79 -0
- langroid/agent/tools/segment_extract_tool.py +36 -0
- langroid/cachedb/__init__.py +9 -0
- langroid/cachedb/base.py +22 -2
- langroid/cachedb/momento_cachedb.py +26 -2
- langroid/cachedb/redis_cachedb.py +78 -11
- langroid/embedding_models/__init__.py +34 -0
- langroid/embedding_models/base.py +21 -2
- langroid/embedding_models/models.py +120 -18
- 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 +45 -0
- langroid/language_models/azure_openai.py +80 -27
- langroid/language_models/base.py +117 -12
- langroid/language_models/config.py +5 -0
- langroid/language_models/openai_assistants.py +3 -0
- langroid/language_models/openai_gpt.py +558 -174
- langroid/language_models/prompt_formatter/__init__.py +15 -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 +18 -21
- langroid/mytypes.py +25 -8
- langroid/parsing/__init__.py +46 -0
- langroid/parsing/document_parser.py +260 -63
- langroid/parsing/image_text.py +32 -0
- langroid/parsing/parse_json.py +143 -0
- langroid/parsing/parser.py +122 -59
- langroid/parsing/repo_loader.py +114 -52
- langroid/parsing/search.py +68 -63
- langroid/parsing/spider.py +3 -2
- langroid/parsing/table_loader.py +44 -0
- langroid/parsing/url_loader.py +59 -11
- langroid/parsing/urls.py +85 -37
- langroid/parsing/utils.py +298 -4
- langroid/parsing/web_search.py +73 -0
- langroid/prompts/__init__.py +11 -0
- langroid/prompts/chat-gpt4-system-prompt.md +68 -0
- langroid/prompts/prompts_config.py +1 -1
- langroid/utils/__init__.py +17 -0
- langroid/utils/algorithms/__init__.py +3 -0
- langroid/utils/algorithms/graph.py +103 -0
- langroid/utils/configuration.py +36 -5
- langroid/utils/constants.py +4 -0
- langroid/utils/globals.py +2 -2
- langroid/utils/logging.py +2 -5
- langroid/utils/output/__init__.py +21 -0
- langroid/utils/output/printing.py +47 -1
- langroid/utils/output/status.py +33 -0
- langroid/utils/pandas_utils.py +30 -0
- langroid/utils/pydantic_utils.py +616 -2
- langroid/utils/system.py +98 -0
- langroid/vector_store/__init__.py +40 -0
- langroid/vector_store/base.py +203 -6
- langroid/vector_store/chromadb.py +59 -32
- langroid/vector_store/lancedb.py +463 -0
- langroid/vector_store/meilisearch.py +10 -7
- langroid/vector_store/momento.py +262 -0
- langroid/vector_store/qdrantdb.py +104 -22
- {langroid-0.1.85.dist-info → langroid-0.1.219.dist-info}/METADATA +329 -149
- langroid-0.1.219.dist-info/RECORD +127 -0
- {langroid-0.1.85.dist-info → langroid-0.1.219.dist-info}/WHEEL +1 -1
- 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.85.dist-info/RECORD +0 -94
- /langroid/{scripts → agent/callbacks}/__init__.py +0 -0
- {langroid-0.1.85.dist-info → langroid-0.1.219.dist-info}/LICENSE +0 -0
langroid/agent/batch.py
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
import asyncio
|
2
|
+
import copy
|
3
|
+
import inspect
|
4
|
+
from typing import Any, Callable, Coroutine, Iterable, List, Optional, TypeVar
|
5
|
+
|
6
|
+
from dotenv import load_dotenv
|
7
|
+
|
8
|
+
from langroid.agent.base import Agent
|
9
|
+
from langroid.agent.chat_document import ChatDocument
|
10
|
+
from langroid.agent.task import Task
|
11
|
+
from langroid.parsing.utils import batched
|
12
|
+
from langroid.utils.configuration import quiet_mode
|
13
|
+
from langroid.utils.logging import setup_colored_logging
|
14
|
+
from langroid.utils.output import SuppressLoggerWarnings, status
|
15
|
+
|
16
|
+
setup_colored_logging()
|
17
|
+
|
18
|
+
load_dotenv()
|
19
|
+
|
20
|
+
T = TypeVar("T")
|
21
|
+
U = TypeVar("U")
|
22
|
+
|
23
|
+
|
24
|
+
def run_batch_task_gen(
|
25
|
+
gen_task: Callable[[int], Task],
|
26
|
+
items: list[T],
|
27
|
+
input_map: Callable[[T], str | ChatDocument] = lambda x: str(x),
|
28
|
+
output_map: Callable[[ChatDocument | None], U] = lambda x: x, # type: ignore
|
29
|
+
sequential: bool = True,
|
30
|
+
batch_size: Optional[int] = None,
|
31
|
+
turns: int = -1,
|
32
|
+
message: Optional[str] = None,
|
33
|
+
handle_exceptions: bool = False,
|
34
|
+
) -> list[U]:
|
35
|
+
"""
|
36
|
+
Generate and run copies of a task async/concurrently one per item in `items` list.
|
37
|
+
For each item, apply `input_map` to get the initial message to process.
|
38
|
+
For each result, apply `output_map` to get the final result.
|
39
|
+
Args:
|
40
|
+
gen_task (Callable[[int], Task]): generates the tasks to run
|
41
|
+
items (list[T]): list of items to process
|
42
|
+
input_map (Callable[[T], str|ChatDocument]): function to map item to
|
43
|
+
initial message to process
|
44
|
+
output_map (Callable[[ChatDocument|str], U]): function to map result
|
45
|
+
to final result
|
46
|
+
sequential (bool): whether to run sequentially
|
47
|
+
(e.g. some APIs such as ooba don't support concurrent requests)
|
48
|
+
batch_size (Optional[int]): The number of tasks to run at a time,
|
49
|
+
if None, unbatched
|
50
|
+
turns (int): number of turns to run, -1 for infinite
|
51
|
+
message (Optional[str]): optionally overrides the console status messages
|
52
|
+
handle_exceptions: bool: Whether to replace exceptions with outputs of None
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
list[Any]: list of final results
|
56
|
+
"""
|
57
|
+
inputs = [input_map(item) for item in items]
|
58
|
+
|
59
|
+
async def _do_task(input: str | ChatDocument, i: int) -> Optional[ChatDocument]:
|
60
|
+
task_i = gen_task(i)
|
61
|
+
if task_i.agent.llm is not None:
|
62
|
+
task_i.agent.llm.set_stream(False)
|
63
|
+
task_i.agent.config.show_stats = False
|
64
|
+
|
65
|
+
result = await task_i.run_async(input, turns=turns)
|
66
|
+
return result
|
67
|
+
|
68
|
+
async def _do_all(
|
69
|
+
inputs: Iterable[str | ChatDocument], start_idx: int = 0
|
70
|
+
) -> list[U]:
|
71
|
+
results: list[Optional[ChatDocument]] = []
|
72
|
+
if sequential:
|
73
|
+
for i, input in enumerate(inputs):
|
74
|
+
try:
|
75
|
+
result = await _do_task(input, i + start_idx)
|
76
|
+
except BaseException as e:
|
77
|
+
if handle_exceptions:
|
78
|
+
result = None
|
79
|
+
else:
|
80
|
+
raise e
|
81
|
+
results.append(result)
|
82
|
+
else:
|
83
|
+
results_with_exceptions = await asyncio.gather(
|
84
|
+
*(_do_task(input, i + start_idx) for i, input in enumerate(inputs)),
|
85
|
+
return_exceptions=handle_exceptions,
|
86
|
+
)
|
87
|
+
|
88
|
+
results = [
|
89
|
+
r if not isinstance(r, BaseException) else None
|
90
|
+
for r in results_with_exceptions
|
91
|
+
]
|
92
|
+
|
93
|
+
return list(map(output_map, results))
|
94
|
+
|
95
|
+
results: List[U] = []
|
96
|
+
if batch_size is None:
|
97
|
+
msg = message or f"[bold green]Running {len(items)} tasks:"
|
98
|
+
|
99
|
+
with status(msg), SuppressLoggerWarnings():
|
100
|
+
results = asyncio.run(_do_all(inputs))
|
101
|
+
else:
|
102
|
+
batches = batched(inputs, batch_size)
|
103
|
+
|
104
|
+
for batch in batches:
|
105
|
+
start_idx = len(results)
|
106
|
+
complete_str = f", {start_idx} complete" if start_idx > 0 else ""
|
107
|
+
msg = message or f"[bold green]Running {len(items)} tasks{complete_str}:"
|
108
|
+
|
109
|
+
with status(msg), SuppressLoggerWarnings():
|
110
|
+
results.extend(asyncio.run(_do_all(batch, start_idx=start_idx)))
|
111
|
+
|
112
|
+
return results
|
113
|
+
|
114
|
+
|
115
|
+
def run_batch_tasks(
|
116
|
+
task: Task,
|
117
|
+
items: list[T],
|
118
|
+
input_map: Callable[[T], str | ChatDocument] = lambda x: str(x),
|
119
|
+
output_map: Callable[[ChatDocument | None], U] = lambda x: x, # type: ignore
|
120
|
+
sequential: bool = True,
|
121
|
+
batch_size: Optional[int] = None,
|
122
|
+
turns: int = -1,
|
123
|
+
) -> List[U]:
|
124
|
+
"""
|
125
|
+
Run copies of `task` async/concurrently one per item in `items` list.
|
126
|
+
For each item, apply `input_map` to get the initial message to process.
|
127
|
+
For each result, apply `output_map` to get the final result.
|
128
|
+
Args:
|
129
|
+
task (Task): task to run
|
130
|
+
items (list[T]): list of items to process
|
131
|
+
input_map (Callable[[T], str|ChatDocument]): function to map item to
|
132
|
+
initial message to process
|
133
|
+
output_map (Callable[[ChatDocument|str], U]): function to map result
|
134
|
+
to final result
|
135
|
+
sequential (bool): whether to run sequentially
|
136
|
+
(e.g. some APIs such as ooba don't support concurrent requests)
|
137
|
+
batch_size (Optional[int]): The number of tasks to run at a time,
|
138
|
+
if None, unbatched
|
139
|
+
turns (int): number of turns to run, -1 for infinite
|
140
|
+
|
141
|
+
Returns:
|
142
|
+
list[Any]: list of final results
|
143
|
+
"""
|
144
|
+
message = f"[bold green]Running {len(items)} copies of {task.name}..."
|
145
|
+
return run_batch_task_gen(
|
146
|
+
lambda i: task.clone(i),
|
147
|
+
items,
|
148
|
+
input_map,
|
149
|
+
output_map,
|
150
|
+
sequential,
|
151
|
+
batch_size,
|
152
|
+
turns,
|
153
|
+
message,
|
154
|
+
)
|
155
|
+
|
156
|
+
|
157
|
+
def run_batch_agent_method(
|
158
|
+
agent: Agent,
|
159
|
+
method: Callable[
|
160
|
+
[str | ChatDocument | None], Coroutine[Any, Any, ChatDocument | None]
|
161
|
+
],
|
162
|
+
items: List[Any],
|
163
|
+
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
164
|
+
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
165
|
+
sequential: bool = True,
|
166
|
+
) -> List[Any]:
|
167
|
+
"""
|
168
|
+
Run the `method` on copies of `agent`, async/concurrently one per
|
169
|
+
item in `items` list.
|
170
|
+
ASSUMPTION: The `method` is an async method and has signature:
|
171
|
+
method(self, input: str|ChatDocument|None) -> ChatDocument|None
|
172
|
+
So this would typically be used for the agent's "responder" methods,
|
173
|
+
e.g. `llm_response_async` or `agent_responder_async`.
|
174
|
+
|
175
|
+
For each item, apply `input_map` to get the initial message to process.
|
176
|
+
For each result, apply `output_map` to get the final result.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
agent (Agent): agent whose method to run
|
180
|
+
method (str): Async method to run on copies of `agent`.
|
181
|
+
The method is assumed to have signature:
|
182
|
+
`method(self, input: str|ChatDocument|None) -> ChatDocument|None`
|
183
|
+
input_map (Callable[[Any], str|ChatDocument]): function to map item to
|
184
|
+
initial message to process
|
185
|
+
output_map (Callable[[ChatDocument|str], Any]): function to map result
|
186
|
+
to final result
|
187
|
+
sequential (bool): whether to run sequentially
|
188
|
+
(e.g. some APIs such as ooba don't support concurrent requests)
|
189
|
+
Returns:
|
190
|
+
List[Any]: list of final results
|
191
|
+
"""
|
192
|
+
# Check if the method is async
|
193
|
+
method_name = method.__name__
|
194
|
+
if not inspect.iscoroutinefunction(method):
|
195
|
+
raise ValueError(f"The method {method_name} is not async.")
|
196
|
+
|
197
|
+
inputs = [input_map(item) for item in items]
|
198
|
+
agent_cfg = copy.deepcopy(agent.config)
|
199
|
+
assert agent_cfg.llm is not None, "agent must have llm config"
|
200
|
+
agent_cfg.llm.stream = False
|
201
|
+
agent_cfg.show_stats = False
|
202
|
+
agent_cls = type(agent)
|
203
|
+
agent_name = agent_cfg.name
|
204
|
+
|
205
|
+
async def _do_task(input: str | ChatDocument, i: int) -> Any:
|
206
|
+
agent_cfg.name = f"{agent_cfg.name}-{i}"
|
207
|
+
agent_i = agent_cls(agent_cfg)
|
208
|
+
method_i = getattr(agent_i, method_name, None)
|
209
|
+
if method_i is None:
|
210
|
+
raise ValueError(f"Agent {agent_name} has no method {method_name}")
|
211
|
+
result = await method_i(input)
|
212
|
+
return output_map(result)
|
213
|
+
|
214
|
+
async def _do_all() -> List[Any]:
|
215
|
+
if sequential:
|
216
|
+
results = []
|
217
|
+
for i, input in enumerate(inputs):
|
218
|
+
result = await _do_task(input, i)
|
219
|
+
results.append(result)
|
220
|
+
return results
|
221
|
+
with quiet_mode(), SuppressLoggerWarnings():
|
222
|
+
return await asyncio.gather(
|
223
|
+
*(_do_task(input, i) for i, input in enumerate(inputs))
|
224
|
+
)
|
225
|
+
|
226
|
+
n = len(items)
|
227
|
+
with status(f"[bold green]Running {n} copies of {agent_name}..."):
|
228
|
+
results = asyncio.run(_do_all())
|
229
|
+
|
230
|
+
return results
|
231
|
+
|
232
|
+
|
233
|
+
def llm_response_batch(
|
234
|
+
agent: Agent,
|
235
|
+
items: List[Any],
|
236
|
+
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
237
|
+
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
238
|
+
sequential: bool = True,
|
239
|
+
) -> List[Any]:
|
240
|
+
return run_batch_agent_method(
|
241
|
+
agent,
|
242
|
+
agent.llm_response_async,
|
243
|
+
items,
|
244
|
+
input_map=input_map,
|
245
|
+
output_map=output_map,
|
246
|
+
sequential=sequential,
|
247
|
+
)
|
248
|
+
|
249
|
+
|
250
|
+
def agent_response_batch(
|
251
|
+
agent: Agent,
|
252
|
+
items: List[Any],
|
253
|
+
input_map: Callable[[Any], str | ChatDocument] = lambda x: str(x),
|
254
|
+
output_map: Callable[[ChatDocument | None], Any] = lambda x: x,
|
255
|
+
sequential: bool = True,
|
256
|
+
) -> List[Any]:
|
257
|
+
return run_batch_agent_method(
|
258
|
+
agent,
|
259
|
+
agent.agent_response_async,
|
260
|
+
items,
|
261
|
+
input_map=input_map,
|
262
|
+
output_map=output_map,
|
263
|
+
sequential=sequential,
|
264
|
+
)
|