langroid 0.17.1__py3-none-any.whl → 0.18.1__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 +1 -1
- langroid/agent/callbacks/chainlit.py +4 -1
- langroid/agent/special/doc_chat_agent.py +15 -6
- langroid/agent/tools/orchestration.py +3 -2
- langroid/language_models/base.py +13 -0
- langroid/language_models/openai_gpt.py +15 -16
- langroid/parsing/document_parser.py +20 -7
- {langroid-0.17.1.dist-info → langroid-0.18.1.dist-info}/METADATA +4 -2
- {langroid-0.17.1.dist-info → langroid-0.18.1.dist-info}/RECORD +12 -12
- pyproject.toml +1 -1
- {langroid-0.17.1.dist-info → langroid-0.18.1.dist-info}/LICENSE +0 -0
- {langroid-0.17.1.dist-info → langroid-0.18.1.dist-info}/WHEEL +0 -0
langroid/agent/base.py
CHANGED
@@ -1316,7 +1316,7 @@ class Agent(ABC):
|
|
1316
1316
|
"""
|
1317
1317
|
Convert result of a responder (agent_response or llm_response, or task.run()),
|
1318
1318
|
or tool handler, or handle_message_fallback,
|
1319
|
-
to a ChatDocument, to
|
1319
|
+
to a ChatDocument, to enable handling by other
|
1320
1320
|
responders/tasks in a task loop possibly involving multiple agents.
|
1321
1321
|
|
1322
1322
|
Args:
|
@@ -244,8 +244,11 @@ class ChainlitAgentCallbacks:
|
|
244
244
|
agent.callbacks.show_error_message = self.show_error_message
|
245
245
|
agent.callbacks.show_start_response = self.show_start_response
|
246
246
|
self.config = config
|
247
|
-
|
248
247
|
self.agent: lr.Agent = agent
|
248
|
+
if self.agent.llm is not None:
|
249
|
+
# We don't want to suppress LLM output in async + streaming,
|
250
|
+
# since we often use chainlit async callbacks to display LLM output
|
251
|
+
self.agent.llm.config.async_stream_quiet = False
|
249
252
|
if msg is not None:
|
250
253
|
self.show_first_user_message(msg)
|
251
254
|
|
@@ -248,12 +248,6 @@ class DocChatAgent(ChatAgent):
|
|
248
248
|
def ingest(self) -> None:
|
249
249
|
"""
|
250
250
|
Chunk + embed + store docs specified by self.config.doc_paths
|
251
|
-
|
252
|
-
Returns:
|
253
|
-
dict with keys:
|
254
|
-
n_splits: number of splits
|
255
|
-
urls: list of urls
|
256
|
-
paths: list of file paths
|
257
251
|
"""
|
258
252
|
if len(self.config.doc_paths) == 0:
|
259
253
|
# we must be using a previously defined collection
|
@@ -1110,6 +1104,14 @@ class DocChatAgent(ChatAgent):
|
|
1110
1104
|
Returns:
|
1111
1105
|
|
1112
1106
|
"""
|
1107
|
+
|
1108
|
+
if (
|
1109
|
+
self.vecdb is None
|
1110
|
+
or self.vecdb.config.collection_name
|
1111
|
+
not in self.vecdb.list_collections(empty=False)
|
1112
|
+
):
|
1113
|
+
return []
|
1114
|
+
|
1113
1115
|
# if we are using cross-encoder reranking or reciprocal rank fusion (RRF),
|
1114
1116
|
# we can retrieve more docs during retrieval, and leave it to the cross-encoder
|
1115
1117
|
# or RRF reranking to whittle down to self.config.parsing.n_similar_docs
|
@@ -1275,6 +1277,13 @@ class DocChatAgent(ChatAgent):
|
|
1275
1277
|
List[Document]: list of relevant extracts
|
1276
1278
|
|
1277
1279
|
"""
|
1280
|
+
if (
|
1281
|
+
self.vecdb is None
|
1282
|
+
or self.vecdb.config.collection_name
|
1283
|
+
not in self.vecdb.list_collections(empty=False)
|
1284
|
+
):
|
1285
|
+
return query, []
|
1286
|
+
|
1278
1287
|
if len(self.dialog) > 0 and not self.config.assistant_mode:
|
1279
1288
|
# Regardless of whether we are in conversation mode or not,
|
1280
1289
|
# for relevant doc/chunk extraction, we must convert the query
|
@@ -200,12 +200,13 @@ class DonePassTool(PassTool):
|
|
200
200
|
|
201
201
|
|
202
202
|
class ForwardTool(PassTool):
|
203
|
-
"""Tool for forwarding the received msg (ChatDocument) to another agent.
|
203
|
+
"""Tool for forwarding the received msg (ChatDocument) to another agent or entity.
|
204
204
|
Similar to PassTool, but with a specified recipient agent.
|
205
205
|
"""
|
206
206
|
|
207
207
|
purpose: str = """
|
208
|
-
To forward the current message to an <agent
|
208
|
+
To forward the current message to an <agent>, where <agent>
|
209
|
+
could be the name of an agent, or an entity such as "user", "llm".
|
209
210
|
"""
|
210
211
|
request: str = "forward_tool"
|
211
212
|
agent: str
|
langroid/language_models/base.py
CHANGED
@@ -39,6 +39,10 @@ ToolTypes = Literal["function"]
|
|
39
39
|
|
40
40
|
|
41
41
|
class LLMConfig(BaseSettings):
|
42
|
+
"""
|
43
|
+
Common configuration for all language models.
|
44
|
+
"""
|
45
|
+
|
42
46
|
type: str = "openai"
|
43
47
|
streamer: Optional[Callable[[Any], None]] = noop_fn
|
44
48
|
api_base: str | None = None
|
@@ -48,6 +52,7 @@ class LLMConfig(BaseSettings):
|
|
48
52
|
completion_model: str = ""
|
49
53
|
temperature: float = 0.0
|
50
54
|
chat_context_length: int = 8000
|
55
|
+
async_stream_quiet: bool = True # suppress streaming output in async mode?
|
51
56
|
completion_context_length: int = 8000
|
52
57
|
max_output_tokens: int = 1024 # generate at most this many tokens
|
53
58
|
# if input length + max_output_tokens > context length of model,
|
@@ -149,6 +154,10 @@ class OpenAIToolSpec(BaseModel):
|
|
149
154
|
|
150
155
|
|
151
156
|
class LLMTokenUsage(BaseModel):
|
157
|
+
"""
|
158
|
+
Usage of tokens by an LLM.
|
159
|
+
"""
|
160
|
+
|
152
161
|
prompt_tokens: int = 0
|
153
162
|
completion_tokens: int = 0
|
154
163
|
cost: float = 0.0
|
@@ -173,6 +182,10 @@ class LLMTokenUsage(BaseModel):
|
|
173
182
|
|
174
183
|
|
175
184
|
class Role(str, Enum):
|
185
|
+
"""
|
186
|
+
Possible roles for a message in a chat.
|
187
|
+
"""
|
188
|
+
|
176
189
|
USER = "user"
|
177
190
|
SYSTEM = "system"
|
178
191
|
ASSISTANT = "assistant"
|
@@ -708,7 +708,7 @@ class OpenAIGPT(LanguageModel):
|
|
708
708
|
event_args = ""
|
709
709
|
event_fn_name = ""
|
710
710
|
event_tool_deltas: Optional[List[Dict[str, Any]]] = None
|
711
|
-
|
711
|
+
silent = is_async and self.config.async_stream_quiet
|
712
712
|
# The first two events in the stream of Azure OpenAI is useless.
|
713
713
|
# In the 1st: choices list is empty, in the 2nd: the dict delta has null content
|
714
714
|
if chat:
|
@@ -727,42 +727,40 @@ class OpenAIGPT(LanguageModel):
|
|
727
727
|
event_text = choices[0]["text"]
|
728
728
|
if event_text:
|
729
729
|
completion += event_text
|
730
|
-
if not
|
730
|
+
if not silent:
|
731
731
|
sys.stdout.write(Colors().GREEN + event_text)
|
732
732
|
sys.stdout.flush()
|
733
733
|
self.config.streamer(event_text)
|
734
734
|
if event_fn_name:
|
735
735
|
function_name = event_fn_name
|
736
736
|
has_function = True
|
737
|
-
if not
|
737
|
+
if not silent:
|
738
738
|
sys.stdout.write(Colors().GREEN + "FUNC: " + event_fn_name + ": ")
|
739
739
|
sys.stdout.flush()
|
740
740
|
self.config.streamer(event_fn_name)
|
741
741
|
|
742
742
|
if event_args:
|
743
743
|
function_args += event_args
|
744
|
-
if not
|
744
|
+
if not silent:
|
745
745
|
sys.stdout.write(Colors().GREEN + event_args)
|
746
746
|
sys.stdout.flush()
|
747
747
|
self.config.streamer(event_args)
|
748
748
|
|
749
|
-
if event_tool_deltas is not None:
|
750
|
-
# print out streaming tool calls
|
749
|
+
if event_tool_deltas is not None and not silent:
|
750
|
+
# print out streaming tool calls, if not async
|
751
751
|
for td in event_tool_deltas:
|
752
752
|
if td["function"]["name"] is not None:
|
753
753
|
tool_fn_name = td["function"]["name"]
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
self.config.streamer(tool_fn_name)
|
754
|
+
sys.stdout.write(
|
755
|
+
Colors().GREEN + "OAI-TOOL: " + tool_fn_name + ": "
|
756
|
+
)
|
757
|
+
sys.stdout.flush()
|
758
|
+
self.config.streamer(tool_fn_name)
|
760
759
|
if td["function"]["arguments"] != "":
|
761
760
|
tool_fn_args = td["function"]["arguments"]
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
self.config.streamer(tool_fn_args)
|
761
|
+
sys.stdout.write(Colors().GREEN + tool_fn_args)
|
762
|
+
sys.stdout.flush()
|
763
|
+
self.config.streamer(tool_fn_args)
|
766
764
|
|
767
765
|
# show this delta in the stream
|
768
766
|
if choices[0].get("finish_reason", "") in [
|
@@ -872,6 +870,7 @@ class OpenAIGPT(LanguageModel):
|
|
872
870
|
completion=completion,
|
873
871
|
function_args=function_args,
|
874
872
|
function_name=function_name,
|
873
|
+
is_async=True,
|
875
874
|
)
|
876
875
|
if is_break:
|
877
876
|
break
|
@@ -81,13 +81,25 @@ def is_plain_text(path_or_bytes: str | bytes) -> bool:
|
|
81
81
|
else:
|
82
82
|
content = path_or_bytes[:1024]
|
83
83
|
try:
|
84
|
+
# Use magic to detect the MIME type
|
85
|
+
import magic
|
86
|
+
|
87
|
+
mime_type = magic.from_buffer(content, mime=True)
|
88
|
+
|
89
|
+
# Check if the MIME type is not a text type
|
90
|
+
if not mime_type.startswith("text/"):
|
91
|
+
return False
|
92
|
+
|
84
93
|
# Attempt to decode the content as UTF-8
|
85
94
|
content = content[: find_last_full_char(content)]
|
86
95
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
96
|
+
try:
|
97
|
+
_ = content.decode("utf-8")
|
98
|
+
# Additional checks can go here, e.g., to verify that the content
|
99
|
+
# doesn't contain too many unusual characters for it to be considered text
|
100
|
+
return True
|
101
|
+
except UnicodeDecodeError:
|
102
|
+
return False
|
91
103
|
except UnicodeDecodeError:
|
92
104
|
# If decoding fails, it's likely not plain text (or not encoded in UTF-8)
|
93
105
|
return False
|
@@ -123,7 +135,8 @@ class DocumentParser(Parser):
|
|
123
135
|
Returns:
|
124
136
|
DocumentParser: An instance of a DocumentParser subclass.
|
125
137
|
"""
|
126
|
-
|
138
|
+
inferred_doc_type = DocumentParser._document_type(source, doc_type)
|
139
|
+
if inferred_doc_type == DocumentType.PDF:
|
127
140
|
if config.pdf.library == "fitz":
|
128
141
|
return FitzPDFParser(source, config)
|
129
142
|
elif config.pdf.library == "pypdf":
|
@@ -138,7 +151,7 @@ class DocumentParser(Parser):
|
|
138
151
|
raise ValueError(
|
139
152
|
f"Unsupported PDF library specified: {config.pdf.library}"
|
140
153
|
)
|
141
|
-
elif
|
154
|
+
elif inferred_doc_type == DocumentType.DOCX:
|
142
155
|
if config.docx.library == "unstructured":
|
143
156
|
return UnstructuredDocxParser(source, config)
|
144
157
|
elif config.docx.library == "python-docx":
|
@@ -147,7 +160,7 @@ class DocumentParser(Parser):
|
|
147
160
|
raise ValueError(
|
148
161
|
f"Unsupported DOCX library specified: {config.docx.library}"
|
149
162
|
)
|
150
|
-
elif
|
163
|
+
elif inferred_doc_type == DocumentType.DOC:
|
151
164
|
return UnstructuredDocParser(source, config)
|
152
165
|
else:
|
153
166
|
source_name = source if isinstance(source, str) else "bytes"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: langroid
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.18.1
|
4
4
|
Summary: Harness LLMs with Multi-Agent Programming
|
5
5
|
License: MIT
|
6
6
|
Author: Prasad Chalasani
|
@@ -244,7 +244,9 @@ teacher_task.run()
|
|
244
244
|
<summary> <b>Click to expand</b></summary>
|
245
245
|
|
246
246
|
- **Oct 2024:**
|
247
|
-
- **[0.
|
247
|
+
- **[0.18.0]** [LLMConfig.async_stream_quiet](https://langroid.github.io/langroid/notes/async-streaming/) flag to
|
248
|
+
turn off LLM output in async + stream mode.
|
249
|
+
- **[0.17.0]** XML-based tools, see [docs](https://langroid.github.io/langroid/notes/xml-tools/).
|
248
250
|
- **Sep 2024:**
|
249
251
|
- **[0.16.0](https://github.com/langroid/langroid/releases/tag/0.16.0)** Support for OpenAI `o1-mini` and `o1-preview` models.
|
250
252
|
- **[0.15.0](https://github.com/langroid/langroid/releases/tag/0.15.0)** Cerebras API support -- run llama-3.1 models hosted on Cerebras Cloud (very fast inference).
|
@@ -1,16 +1,16 @@
|
|
1
1
|
langroid/__init__.py,sha256=z_fCOLQJPOw3LLRPBlFB5-2HyCjpPgQa4m4iY5Fvb8Y,1800
|
2
2
|
langroid/agent/__init__.py,sha256=ll0Cubd2DZ-fsCMl7e10hf9ZjFGKzphfBco396IKITY,786
|
3
|
-
langroid/agent/base.py,sha256=
|
3
|
+
langroid/agent/base.py,sha256=yFR9yrUWbuIOufgVDPOSjFDIP28JvGJWqvEu0HXEMX8,64045
|
4
4
|
langroid/agent/batch.py,sha256=QZdlt1563hx4l3AXrCaGovE-PNG93M3DsvQAbDzdiS8,13705
|
5
5
|
langroid/agent/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
langroid/agent/callbacks/chainlit.py,sha256=
|
6
|
+
langroid/agent/callbacks/chainlit.py,sha256=oiZYfPyfkUfFqhVFBiobN3hAJEaYn0FBSglvNE7t17Q,22302
|
7
7
|
langroid/agent/chat_agent.py,sha256=m1fs-XsBzusRicwBETId3dpTQG8qEaS0yym_o4mfAI0,49931
|
8
8
|
langroid/agent/chat_document.py,sha256=FZ_PkeKU5OVp1IUlMvspfqxIXzlyd7J_F32DSYrxQ7E,17651
|
9
9
|
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=2rjCZw45ysNBEGNzQM4uf0bTC4KkatGYAWcVcW4xcek,34337
|
12
12
|
langroid/agent/special/__init__.py,sha256=gik_Xtm_zV7U9s30Mn8UX3Gyuy4jTjQe9zjiE3HWmEo,1273
|
13
|
-
langroid/agent/special/doc_chat_agent.py,sha256=
|
13
|
+
langroid/agent/special/doc_chat_agent.py,sha256=xIqBOyLax_jMU0UevxqXf_aQUrRkW6MQUKpKnKvaqkQ,59281
|
14
14
|
langroid/agent/special/lance_doc_chat_agent.py,sha256=s8xoRs0gGaFtDYFUSIRchsgDVbS5Q3C2b2mr3V1Fd-Q,10419
|
15
15
|
langroid/agent/special/lance_rag/__init__.py,sha256=QTbs0IVE2ZgDg8JJy1zN97rUUg4uEPH7SLGctFNumk4,174
|
16
16
|
langroid/agent/special/lance_rag/critic_agent.py,sha256=OtFuHthKQLkdVkvuZ2m0GNq1qOYLqHkm1pfLRFnSg5c,9548
|
@@ -40,7 +40,7 @@ langroid/agent/tools/duckduckgo_search_tool.py,sha256=NhsCaGZkdv28nja7yveAhSK_w6
|
|
40
40
|
langroid/agent/tools/file_tools.py,sha256=GjPB5YDILucYapElnvvoYpGJuZQ25ecLs2REv7edPEo,7292
|
41
41
|
langroid/agent/tools/google_search_tool.py,sha256=y7b-3FtgXf0lfF4AYxrZ3K5pH2dhidvibUOAGBE--WI,1456
|
42
42
|
langroid/agent/tools/metaphor_search_tool.py,sha256=qj4gt453cLEX3EGW7nVzVu6X7LCdrwjSlcNY0qJW104,2489
|
43
|
-
langroid/agent/tools/orchestration.py,sha256=
|
43
|
+
langroid/agent/tools/orchestration.py,sha256=u_iQDwD5L9JgE39pCemmIRG3MxyrBsw6KpQYf7pH-Ek,10881
|
44
44
|
langroid/agent/tools/recipient_tool.py,sha256=0m2kQhYKTeGujAxhSPqH5z6hSAhVB_Dqour6uul2U30,9427
|
45
45
|
langroid/agent/tools/retrieval_tool.py,sha256=2q2pfoYbZNfbWQ0McxrtmfF0ekGglIgRl-6uF26pa-E,871
|
46
46
|
langroid/agent/tools/rewind_tool.py,sha256=XAXL3BpNhCmBGYq_qi_sZfHJuIw7NY2jp4wnojJ7WRs,5606
|
@@ -67,10 +67,10 @@ langroid/language_models/.chainlit/config.toml,sha256=1t5lHORGzc2E6dkaO9P15jYHu2
|
|
67
67
|
langroid/language_models/.chainlit/translations/en-US.json,sha256=DAFz2HjOFFfboCStrUfKFg2BpplJPK_OOtixwF_GivY,9931
|
68
68
|
langroid/language_models/__init__.py,sha256=1sUGobooTqq77XC7LxKsvME0RgSd5GGmeyrPo9SMh4U,940
|
69
69
|
langroid/language_models/azure_openai.py,sha256=G4le3j4YLHV7IwgB2C37hO3MKijZ1KjynbYlEvpIF7Y,6214
|
70
|
-
langroid/language_models/base.py,sha256=
|
70
|
+
langroid/language_models/base.py,sha256=L02ToM7o1y5OlM23xYX8QbriRMVUodgwbnHodl3US28,22542
|
71
71
|
langroid/language_models/config.py,sha256=9Q8wk5a7RQr8LGMT_0WkpjY8S4ywK06SalVRjXlfCiI,378
|
72
72
|
langroid/language_models/mock_lm.py,sha256=HuiAvjHiCfffYF5xjFJUq945HVTW0QPbeUUctOnNCzQ,3868
|
73
|
-
langroid/language_models/openai_gpt.py,sha256=
|
73
|
+
langroid/language_models/openai_gpt.py,sha256=AlHg-jbf7PBFcS1iqb5z--upokDcWS7RJ4qpAmovsVw,64822
|
74
74
|
langroid/language_models/prompt_formatter/__init__.py,sha256=2-5cdE24XoFDhifOLl8yiscohil1ogbP1ECkYdBlBsk,372
|
75
75
|
langroid/language_models/prompt_formatter/base.py,sha256=eDS1sgRNZVnoajwV_ZIha6cba5Dt8xjgzdRbPITwx3Q,1221
|
76
76
|
langroid/language_models/prompt_formatter/hf_formatter.py,sha256=PVJppmjRvD-2DF-XNC6mE05vTZ9wbu37SmXwZBQhad0,5055
|
@@ -82,7 +82,7 @@ langroid/parsing/agent_chats.py,sha256=sbZRV9ujdM5QXvvuHVjIi2ysYSYlap-uqfMMUKulr
|
|
82
82
|
langroid/parsing/code-parsing.md,sha256=--cyyNiSZSDlIwcjAV4-shKrSiRe2ytF3AdSoS_hD2g,3294
|
83
83
|
langroid/parsing/code_parser.py,sha256=AOxb3xbYpTBPP3goOm5dKfJdh5hS_2BhLVCEkifWZN8,3796
|
84
84
|
langroid/parsing/config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
|
-
langroid/parsing/document_parser.py,sha256=
|
85
|
+
langroid/parsing/document_parser.py,sha256=ZGxgG4ytnCIah4HWk3ZrK3EGAMXDjAzI9KaPEXCbMm0,24589
|
86
86
|
langroid/parsing/image_text.py,sha256=sbLIQ5nHe2UnYUksBaQsmZGaX-X0qgEpPd7CEzi_z5M,910
|
87
87
|
langroid/parsing/para_sentence_split.py,sha256=AJBzZojP3zpB-_IMiiHismhqcvkrVBQ3ZINoQyx_bE4,2000
|
88
88
|
langroid/parsing/parse_json.py,sha256=aADo38bAHQhC8on4aWZZzVzSDy-dK35vRLZsFI2ewh8,4756
|
@@ -137,8 +137,8 @@ langroid/vector_store/meilisearch.py,sha256=6frB7GFWeWmeKzRfLZIvzRjllniZ1cYj3Hmh
|
|
137
137
|
langroid/vector_store/momento.py,sha256=qR-zBF1RKVHQZPZQYW_7g-XpTwr46p8HJuYPCkfJbM4,10534
|
138
138
|
langroid/vector_store/qdrant_cloud.py,sha256=3im4Mip0QXLkR6wiqVsjV1QvhSElfxdFSuDKddBDQ-4,188
|
139
139
|
langroid/vector_store/qdrantdb.py,sha256=v88lqFkepADvlN6lByUj9I4NEKa9X9lWH16uTPPbYrE,17457
|
140
|
-
pyproject.toml,sha256=
|
141
|
-
langroid-0.
|
142
|
-
langroid-0.
|
143
|
-
langroid-0.
|
144
|
-
langroid-0.
|
140
|
+
pyproject.toml,sha256=4WsW43aYs4SPCgfi1cEPVqaOQIHDZRuyUz-S8Ka9oAY,7179
|
141
|
+
langroid-0.18.1.dist-info/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
|
142
|
+
langroid-0.18.1.dist-info/METADATA,sha256=wamviAoQosjm8zl2aLANeU22nc0fsiosnPt8weJNsvs,56486
|
143
|
+
langroid-0.18.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
144
|
+
langroid-0.18.1.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|