langroid 0.1.230__py3-none-any.whl → 0.1.233__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/batch.py +13 -1
- langroid/agent/special/doc_chat_agent.py +10 -3
- langroid/agent/task.py +36 -1
- langroid/language_models/base.py +12 -0
- {langroid-0.1.230.dist-info → langroid-0.1.233.dist-info}/METADATA +1 -1
- {langroid-0.1.230.dist-info → langroid-0.1.233.dist-info}/RECORD +8 -8
- {langroid-0.1.230.dist-info → langroid-0.1.233.dist-info}/LICENSE +0 -0
- {langroid-0.1.230.dist-info → langroid-0.1.233.dist-info}/WHEEL +0 -0
langroid/agent/batch.py
CHANGED
@@ -31,6 +31,8 @@ def run_batch_task_gen(
|
|
31
31
|
turns: int = -1,
|
32
32
|
message: Optional[str] = None,
|
33
33
|
handle_exceptions: bool = False,
|
34
|
+
max_cost: float = 0.0,
|
35
|
+
max_tokens: int = 0,
|
34
36
|
) -> list[U]:
|
35
37
|
"""
|
36
38
|
Generate and run copies of a task async/concurrently one per item in `items` list.
|
@@ -50,6 +52,8 @@ def run_batch_task_gen(
|
|
50
52
|
turns (int): number of turns to run, -1 for infinite
|
51
53
|
message (Optional[str]): optionally overrides the console status messages
|
52
54
|
handle_exceptions: bool: Whether to replace exceptions with outputs of None
|
55
|
+
max_cost: float: maximum cost to run the task (default 0.0 for unlimited)
|
56
|
+
|
53
57
|
|
54
58
|
Returns:
|
55
59
|
list[Any]: list of final results
|
@@ -62,7 +66,9 @@ def run_batch_task_gen(
|
|
62
66
|
task_i.agent.llm.set_stream(False)
|
63
67
|
task_i.agent.config.show_stats = False
|
64
68
|
|
65
|
-
result = await task_i.run_async(
|
69
|
+
result = await task_i.run_async(
|
70
|
+
input, turns=turns, max_cost=max_cost, max_tokens=max_tokens
|
71
|
+
)
|
66
72
|
return result
|
67
73
|
|
68
74
|
async def _do_all(
|
@@ -120,6 +126,8 @@ def run_batch_tasks(
|
|
120
126
|
sequential: bool = True,
|
121
127
|
batch_size: Optional[int] = None,
|
122
128
|
turns: int = -1,
|
129
|
+
max_cost: float = 0.0,
|
130
|
+
max_tokens: int = 0,
|
123
131
|
) -> List[U]:
|
124
132
|
"""
|
125
133
|
Run copies of `task` async/concurrently one per item in `items` list.
|
@@ -137,6 +145,8 @@ def run_batch_tasks(
|
|
137
145
|
batch_size (Optional[int]): The number of tasks to run at a time,
|
138
146
|
if None, unbatched
|
139
147
|
turns (int): number of turns to run, -1 for infinite
|
148
|
+
max_cost: float: maximum cost to run the task (default 0.0 for unlimited)
|
149
|
+
max_tokens: int: maximum token usage (in and out) (default 0 for unlimited)
|
140
150
|
|
141
151
|
Returns:
|
142
152
|
list[Any]: list of final results
|
@@ -151,6 +161,8 @@ def run_batch_tasks(
|
|
151
161
|
batch_size,
|
152
162
|
turns,
|
153
163
|
message,
|
164
|
+
max_cost=max_cost,
|
165
|
+
max_tokens=max_tokens,
|
154
166
|
)
|
155
167
|
|
156
168
|
|
@@ -117,6 +117,7 @@ class DocChatAgentConfig(ChatAgentConfig):
|
|
117
117
|
)
|
118
118
|
rerank_diversity: bool = True # rerank to maximize diversity?
|
119
119
|
rerank_periphery: bool = True # rerank to avoid Lost In the Middle effect?
|
120
|
+
rerank_after_adding_context: bool = True # rerank after adding context window?
|
120
121
|
embed_batch_size: int = 500 # get embedding of at most this many at a time
|
121
122
|
cache: bool = True # cache results
|
122
123
|
debug: bool = False
|
@@ -1110,9 +1111,10 @@ class DocChatAgent(ChatAgent):
|
|
1110
1111
|
if len(passages) == 0:
|
1111
1112
|
return []
|
1112
1113
|
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1114
|
+
if self.config.rerank_after_adding_context:
|
1115
|
+
passages_scores = [(p, 0.0) for p in passages]
|
1116
|
+
passages_scores = self.add_context_window(passages_scores)
|
1117
|
+
passages = [p for p, _ in passages_scores]
|
1116
1118
|
# now passages can potentially have a lot of doc chunks,
|
1117
1119
|
# so we re-rank them using a cross-encoder scoring model,
|
1118
1120
|
# and pick top k where k = config.parsing.n_similar_docs
|
@@ -1129,6 +1131,11 @@ class DocChatAgent(ChatAgent):
|
|
1129
1131
|
# (see Lost In the Middle issue).
|
1130
1132
|
passages = self.rerank_to_periphery(passages)
|
1131
1133
|
|
1134
|
+
if not self.config.rerank_after_adding_context:
|
1135
|
+
passages_scores = [(p, 0.0) for p in passages]
|
1136
|
+
passages_scores = self.add_context_window(passages_scores)
|
1137
|
+
passages = [p for p, _ in passages_scores]
|
1138
|
+
|
1132
1139
|
return passages
|
1133
1140
|
|
1134
1141
|
@no_type_check
|
langroid/agent/task.py
CHANGED
@@ -170,7 +170,8 @@ class Task:
|
|
170
170
|
agent.set_system_message(system_message)
|
171
171
|
if user_message:
|
172
172
|
agent.set_user_message(user_message)
|
173
|
-
|
173
|
+
self.max_cost: float = 0
|
174
|
+
self.max_tokens: int = 0
|
174
175
|
self.logger: None | RichFileLogger = None
|
175
176
|
self.tsv_logger: None | logging.Logger = None
|
176
177
|
self.color_log: bool = False if settings.notebook else True
|
@@ -375,11 +376,15 @@ class Task:
|
|
375
376
|
msg: Optional[str | ChatDocument] = None,
|
376
377
|
turns: int = -1,
|
377
378
|
caller: None | Task = None,
|
379
|
+
max_cost: float = 0,
|
380
|
+
max_tokens: int = 0,
|
378
381
|
) -> Optional[ChatDocument]:
|
379
382
|
"""Synchronous version of `run_async()`.
|
380
383
|
See `run_async()` for details."""
|
381
384
|
self.task_progress = False
|
382
385
|
self.n_stalled_steps = 0
|
386
|
+
self.max_cost = max_cost
|
387
|
+
self.max_tokens = max_tokens
|
383
388
|
assert (
|
384
389
|
msg is None or isinstance(msg, str) or isinstance(msg, ChatDocument)
|
385
390
|
), f"msg arg in Task.run() must be None, str, or ChatDocument, not {type(msg)}"
|
@@ -418,6 +423,8 @@ class Task:
|
|
418
423
|
msg: Optional[str | ChatDocument] = None,
|
419
424
|
turns: int = -1,
|
420
425
|
caller: None | Task = None,
|
426
|
+
max_cost: float = 0,
|
427
|
+
max_tokens: int = 0,
|
421
428
|
) -> Optional[ChatDocument]:
|
422
429
|
"""
|
423
430
|
Loop over `step()` until task is considered done or `turns` is reached.
|
@@ -434,6 +441,8 @@ class Task:
|
|
434
441
|
turns (int): number of turns to run the task for;
|
435
442
|
default is -1, which means run until task is done.
|
436
443
|
caller (Task|None): the calling task, if any
|
444
|
+
max_cost (float): max cost allowed for the task (default 0 -> no limit)
|
445
|
+
max_tokens (int): max tokens allowed for the task (default 0 -> no limit)
|
437
446
|
|
438
447
|
Returns:
|
439
448
|
Optional[ChatDocument]: valid result of the task.
|
@@ -444,6 +453,9 @@ class Task:
|
|
444
453
|
# message can be considered to be from the USER
|
445
454
|
# (from the POV of this agent's LLM).
|
446
455
|
self.task_progress = False
|
456
|
+
self.n_stalled_steps = 0
|
457
|
+
self.max_cost = max_cost
|
458
|
+
self.max_tokens = max_tokens
|
447
459
|
if (
|
448
460
|
isinstance(msg, ChatDocument)
|
449
461
|
and msg.metadata.recipient != ""
|
@@ -819,6 +831,8 @@ class Task:
|
|
819
831
|
self.pending_message,
|
820
832
|
turns=actual_turns,
|
821
833
|
caller=self,
|
834
|
+
max_cost=self.max_cost,
|
835
|
+
max_tokens=self.max_tokens,
|
822
836
|
)
|
823
837
|
result_str = str(ChatDocument.to_LLMMessage(result))
|
824
838
|
maybe_tool = len(extract_top_level_json(result_str)) > 0
|
@@ -894,6 +908,8 @@ class Task:
|
|
894
908
|
self.pending_message,
|
895
909
|
turns=actual_turns,
|
896
910
|
caller=self,
|
911
|
+
max_cost=self.max_cost,
|
912
|
+
max_tokens=self.max_tokens,
|
897
913
|
)
|
898
914
|
result_str = str(ChatDocument.to_LLMMessage(result))
|
899
915
|
maybe_tool = len(extract_top_level_json(result_str)) > 0
|
@@ -1051,6 +1067,25 @@ class Task:
|
|
1051
1067
|
)
|
1052
1068
|
return True
|
1053
1069
|
|
1070
|
+
if self.max_cost > 0 and self.agent.llm is not None:
|
1071
|
+
try:
|
1072
|
+
if self.agent.llm.tot_tokens_cost()[1] > self.max_cost:
|
1073
|
+
logger.warning(
|
1074
|
+
f"Task {self.name} cost exceeded {self.max_cost}; exiting."
|
1075
|
+
)
|
1076
|
+
return True
|
1077
|
+
except Exception:
|
1078
|
+
pass
|
1079
|
+
|
1080
|
+
if self.max_tokens > 0 and self.agent.llm is not None:
|
1081
|
+
try:
|
1082
|
+
if self.agent.llm.tot_tokens_cost()[0] > self.max_tokens:
|
1083
|
+
logger.warning(
|
1084
|
+
f"Task {self.name} uses > {self.max_tokens} tokens; exiting."
|
1085
|
+
)
|
1086
|
+
return True
|
1087
|
+
except Exception:
|
1088
|
+
pass
|
1054
1089
|
return (
|
1055
1090
|
# no valid response from any entity/agent in current turn
|
1056
1091
|
result is None
|
langroid/language_models/base.py
CHANGED
@@ -449,6 +449,18 @@ class LanguageModel(ABC):
|
|
449
449
|
s += f"{model}: {counter}\n"
|
450
450
|
return s
|
451
451
|
|
452
|
+
@classmethod
|
453
|
+
def tot_tokens_cost(cls) -> Tuple[int, float]:
|
454
|
+
"""
|
455
|
+
Return total tokens used and total cost across all models.
|
456
|
+
"""
|
457
|
+
total_tokens = 0
|
458
|
+
total_cost = 0.0
|
459
|
+
for counter in cls.usage_cost_dict.values():
|
460
|
+
total_tokens += counter.total_tokens
|
461
|
+
total_cost += counter.cost
|
462
|
+
return total_tokens, total_cost
|
463
|
+
|
452
464
|
def followup_to_standalone(
|
453
465
|
self, chat_history: List[Tuple[str, str]], question: str
|
454
466
|
) -> str:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
langroid/__init__.py,sha256=qgY-OqzYSWOc6EytQJN9sH2PwDp1UIzP9lXhrYH6aLU,1645
|
2
2
|
langroid/agent/__init__.py,sha256=_D8dxnfdr92ch1CIrUkKjrB5HVvsQdn62b1Fb2kBxV8,785
|
3
3
|
langroid/agent/base.py,sha256=jyGFmojrFuOy81lUkNsJlR6mLIOY6kOD20P9dhEcEuw,35059
|
4
|
-
langroid/agent/batch.py,sha256=
|
4
|
+
langroid/agent/batch.py,sha256=SyvUwKetPH_4JKgTnV0bgXS7eD_qfFl9cq06lnill4o,9956
|
5
5
|
langroid/agent/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
langroid/agent/callbacks/chainlit.py,sha256=aYuJ8M4VDHr5oymoXL2bpThM7p6P9L45fgJf3MLdkWo,20997
|
7
7
|
langroid/agent/chat_agent.py,sha256=X5uVMm9qdw3j-FRf4hbN8k8ByaSdtQCTuU8olKE0sbs,38750
|
@@ -10,7 +10,7 @@ langroid/agent/helpers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
langroid/agent/junk,sha256=LxfuuW7Cijsg0szAzT81OjWWv1PMNI-6w_-DspVIO2s,339
|
11
11
|
langroid/agent/openai_assistant.py,sha256=xWSDR4SyMcZhCUkgaM4-mu77rbEDF_xpt7N8m8CkiA4,32962
|
12
12
|
langroid/agent/special/__init__.py,sha256=XPE076zD-roskxNBn-A1hnh4AHoMiQN9gk1UDjPaBaU,1201
|
13
|
-
langroid/agent/special/doc_chat_agent.py,sha256=
|
13
|
+
langroid/agent/special/doc_chat_agent.py,sha256=LwWNb_1s5n9rOk9OpOFPuuY1VnVX5DjzQmPwBanKRrM,53763
|
14
14
|
langroid/agent/special/lance_doc_chat_agent.py,sha256=USp0U3eTaJzwF_3bdqE7CedSLbaqAi2tm-VzygcyLaA,10175
|
15
15
|
langroid/agent/special/lance_rag/__init__.py,sha256=QTbs0IVE2ZgDg8JJy1zN97rUUg4uEPH7SLGctFNumk4,174
|
16
16
|
langroid/agent/special/lance_rag/critic_agent.py,sha256=pi_9eMBxEycbWTddtq_yz-mOb2V4SgGm3zfsOH1HU-Q,5775
|
@@ -32,7 +32,7 @@ langroid/agent/special/sql/utils/populate_metadata.py,sha256=x2OMKfmIBnJESBG3qKt
|
|
32
32
|
langroid/agent/special/sql/utils/system_message.py,sha256=qKLHkvQWRQodTtPLPxr1GSLUYUFASZU8x-ybV67cB68,1885
|
33
33
|
langroid/agent/special/sql/utils/tools.py,sha256=6uB2424SLtmapui9ggcEr0ZTiB6_dL1-JRGgN8RK9Js,1332
|
34
34
|
langroid/agent/special/table_chat_agent.py,sha256=-Qtqr2FP8VcyYcA-Pzqa9ucSl1-nXudbNsv_qakSSco,9041
|
35
|
-
langroid/agent/task.py,sha256=
|
35
|
+
langroid/agent/task.py,sha256=jUeKRreYvs_6OlOqVxqfYWQHtvDZViUDtx5wl_b9cyY,51160
|
36
36
|
langroid/agent/tool_message.py,sha256=2kPsQUwi3ZzINTUNj10huKnZLjLp5SXmefacTHx8QDc,8304
|
37
37
|
langroid/agent/tools/__init__.py,sha256=q-maq3k2BXhPAU99G0H6-j_ozoRvx15I1RFpPVicQIU,304
|
38
38
|
langroid/agent/tools/duckduckgo_search_tool.py,sha256=mLGhlgs6pwbYZIwrOs9shfh1dMBVT4DtkR29pYL3cCQ,1900
|
@@ -59,7 +59,7 @@ langroid/embedding_models/protoc/embeddings_pb2_grpc.py,sha256=9dYQqkW3JPyBpSEje
|
|
59
59
|
langroid/embedding_models/remote_embeds.py,sha256=6_kjXByVbqhY9cGwl9R83ZcYC2km-nGieNNAo1McHaY,5151
|
60
60
|
langroid/language_models/__init__.py,sha256=5L9ndEEC8iLJHjDJmYFTnv6-2-3xsxWUMHcugR8IeDs,821
|
61
61
|
langroid/language_models/azure_openai.py,sha256=ncRCbKooqLVOY-PWQUIo9C3yTuKEFbAwyngXT_M4P7k,5989
|
62
|
-
langroid/language_models/base.py,sha256=
|
62
|
+
langroid/language_models/base.py,sha256=B6dX43ZR65mIvjD95W4RcfpT-WpmiuEcstR3eMrr56Y,21029
|
63
63
|
langroid/language_models/config.py,sha256=5UF3DzO1a-Dfsc3vghE0XGq7g9t_xDsRCsuRiU4dgBg,366
|
64
64
|
langroid/language_models/openai_assistants.py,sha256=9K-DEAL2aSWHeXj2hwCo2RAlK9_1oCPtqX2u1wISCj8,36
|
65
65
|
langroid/language_models/openai_gpt.py,sha256=hR0ibmumIq1TnOGdb80SW0EN6YZn6DZazd5waFHKqGk,49357
|
@@ -120,7 +120,7 @@ langroid/vector_store/meilisearch.py,sha256=d2huA9P-NoYRuAQ9ZeXJmMKr7ry8u90RUSR2
|
|
120
120
|
langroid/vector_store/momento.py,sha256=9cui31TTrILid2KIzUpBkN2Ey3g_CZWOQVdaFsA4Ors,10045
|
121
121
|
langroid/vector_store/qdrant_cloud.py,sha256=3im4Mip0QXLkR6wiqVsjV1QvhSElfxdFSuDKddBDQ-4,188
|
122
122
|
langroid/vector_store/qdrantdb.py,sha256=foKRxRv0BBony6S4Vt0Vav9Rn9HMxZvcIh1cE7nosFE,13524
|
123
|
-
langroid-0.1.
|
124
|
-
langroid-0.1.
|
125
|
-
langroid-0.1.
|
126
|
-
langroid-0.1.
|
123
|
+
langroid-0.1.233.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
|
124
|
+
langroid-0.1.233.dist-info/METADATA,sha256=vxJscoG8qWCn8tfLfCDhVHiomACst_EJcldbP3PNw_M,47863
|
125
|
+
langroid-0.1.233.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
126
|
+
langroid-0.1.233.dist-info/RECORD,,
|
File without changes
|
File without changes
|