langchain 0.3.26__py3-none-any.whl → 0.3.27__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.

Potentially problematic release.


This version of langchain might be problematic. Click here for more details.

Files changed (580) hide show
  1. langchain/__init__.py +110 -96
  2. langchain/_api/__init__.py +2 -2
  3. langchain/_api/deprecation.py +3 -3
  4. langchain/_api/module_import.py +51 -46
  5. langchain/_api/path.py +1 -1
  6. langchain/adapters/openai.py +8 -8
  7. langchain/agents/__init__.py +15 -12
  8. langchain/agents/agent.py +160 -133
  9. langchain/agents/agent_iterator.py +31 -14
  10. langchain/agents/agent_toolkits/__init__.py +7 -6
  11. langchain/agents/agent_toolkits/ainetwork/toolkit.py +1 -1
  12. langchain/agents/agent_toolkits/amadeus/toolkit.py +1 -1
  13. langchain/agents/agent_toolkits/azure_cognitive_services.py +1 -1
  14. langchain/agents/agent_toolkits/clickup/toolkit.py +1 -1
  15. langchain/agents/agent_toolkits/conversational_retrieval/openai_functions.py +6 -4
  16. langchain/agents/agent_toolkits/csv/__init__.py +4 -2
  17. langchain/agents/agent_toolkits/file_management/__init__.py +1 -1
  18. langchain/agents/agent_toolkits/file_management/toolkit.py +1 -1
  19. langchain/agents/agent_toolkits/github/toolkit.py +9 -9
  20. langchain/agents/agent_toolkits/gitlab/toolkit.py +1 -1
  21. langchain/agents/agent_toolkits/json/base.py +1 -1
  22. langchain/agents/agent_toolkits/multion/toolkit.py +1 -1
  23. langchain/agents/agent_toolkits/office365/toolkit.py +1 -1
  24. langchain/agents/agent_toolkits/openapi/base.py +1 -1
  25. langchain/agents/agent_toolkits/openapi/planner.py +2 -2
  26. langchain/agents/agent_toolkits/openapi/planner_prompt.py +10 -10
  27. langchain/agents/agent_toolkits/openapi/prompt.py +1 -1
  28. langchain/agents/agent_toolkits/openapi/toolkit.py +1 -1
  29. langchain/agents/agent_toolkits/pandas/__init__.py +4 -2
  30. langchain/agents/agent_toolkits/playwright/__init__.py +1 -1
  31. langchain/agents/agent_toolkits/playwright/toolkit.py +1 -1
  32. langchain/agents/agent_toolkits/powerbi/base.py +1 -1
  33. langchain/agents/agent_toolkits/powerbi/chat_base.py +1 -1
  34. langchain/agents/agent_toolkits/powerbi/prompt.py +2 -2
  35. langchain/agents/agent_toolkits/powerbi/toolkit.py +1 -1
  36. langchain/agents/agent_toolkits/python/__init__.py +4 -2
  37. langchain/agents/agent_toolkits/spark/__init__.py +4 -2
  38. langchain/agents/agent_toolkits/spark_sql/base.py +1 -1
  39. langchain/agents/agent_toolkits/spark_sql/toolkit.py +1 -1
  40. langchain/agents/agent_toolkits/sql/prompt.py +1 -1
  41. langchain/agents/agent_toolkits/sql/toolkit.py +1 -1
  42. langchain/agents/agent_toolkits/vectorstore/base.py +2 -2
  43. langchain/agents/agent_toolkits/vectorstore/prompt.py +2 -4
  44. langchain/agents/agent_toolkits/vectorstore/toolkit.py +12 -11
  45. langchain/agents/agent_toolkits/xorbits/__init__.py +4 -2
  46. langchain/agents/agent_toolkits/zapier/toolkit.py +1 -1
  47. langchain/agents/agent_types.py +6 -6
  48. langchain/agents/chat/base.py +6 -12
  49. langchain/agents/chat/output_parser.py +9 -6
  50. langchain/agents/chat/prompt.py +3 -4
  51. langchain/agents/conversational/base.py +9 -5
  52. langchain/agents/conversational/output_parser.py +4 -2
  53. langchain/agents/conversational/prompt.py +2 -3
  54. langchain/agents/conversational_chat/base.py +7 -5
  55. langchain/agents/conversational_chat/output_parser.py +9 -11
  56. langchain/agents/conversational_chat/prompt.py +5 -6
  57. langchain/agents/format_scratchpad/__init__.py +3 -3
  58. langchain/agents/format_scratchpad/log_to_messages.py +1 -1
  59. langchain/agents/format_scratchpad/openai_functions.py +8 -6
  60. langchain/agents/format_scratchpad/tools.py +5 -3
  61. langchain/agents/format_scratchpad/xml.py +33 -2
  62. langchain/agents/initialize.py +16 -8
  63. langchain/agents/json_chat/base.py +18 -18
  64. langchain/agents/json_chat/prompt.py +2 -3
  65. langchain/agents/load_tools.py +2 -1
  66. langchain/agents/loading.py +28 -18
  67. langchain/agents/mrkl/base.py +9 -4
  68. langchain/agents/mrkl/output_parser.py +17 -13
  69. langchain/agents/mrkl/prompt.py +1 -2
  70. langchain/agents/openai_assistant/base.py +80 -70
  71. langchain/agents/openai_functions_agent/base.py +46 -37
  72. langchain/agents/openai_functions_multi_agent/base.py +39 -26
  73. langchain/agents/openai_tools/base.py +8 -8
  74. langchain/agents/output_parsers/__init__.py +3 -3
  75. langchain/agents/output_parsers/json.py +6 -6
  76. langchain/agents/output_parsers/openai_functions.py +15 -7
  77. langchain/agents/output_parsers/openai_tools.py +9 -4
  78. langchain/agents/output_parsers/react_json_single_input.py +10 -5
  79. langchain/agents/output_parsers/react_single_input.py +15 -11
  80. langchain/agents/output_parsers/self_ask.py +3 -2
  81. langchain/agents/output_parsers/tools.py +18 -13
  82. langchain/agents/output_parsers/xml.py +99 -28
  83. langchain/agents/react/agent.py +4 -4
  84. langchain/agents/react/base.py +22 -17
  85. langchain/agents/react/output_parser.py +5 -6
  86. langchain/agents/react/textworld_prompt.py +0 -1
  87. langchain/agents/react/wiki_prompt.py +14 -15
  88. langchain/agents/schema.py +3 -2
  89. langchain/agents/self_ask_with_search/base.py +19 -15
  90. langchain/agents/self_ask_with_search/prompt.py +0 -1
  91. langchain/agents/structured_chat/base.py +14 -11
  92. langchain/agents/structured_chat/output_parser.py +16 -18
  93. langchain/agents/structured_chat/prompt.py +3 -4
  94. langchain/agents/tool_calling_agent/base.py +7 -6
  95. langchain/agents/tools.py +2 -2
  96. langchain/agents/utils.py +2 -3
  97. langchain/agents/xml/base.py +5 -5
  98. langchain/agents/xml/prompt.py +1 -2
  99. langchain/cache.py +12 -12
  100. langchain/callbacks/__init__.py +11 -11
  101. langchain/callbacks/aim_callback.py +2 -2
  102. langchain/callbacks/argilla_callback.py +1 -1
  103. langchain/callbacks/arize_callback.py +1 -1
  104. langchain/callbacks/arthur_callback.py +1 -1
  105. langchain/callbacks/base.py +7 -7
  106. langchain/callbacks/clearml_callback.py +1 -1
  107. langchain/callbacks/comet_ml_callback.py +1 -1
  108. langchain/callbacks/confident_callback.py +1 -1
  109. langchain/callbacks/context_callback.py +1 -1
  110. langchain/callbacks/flyte_callback.py +1 -1
  111. langchain/callbacks/human.py +2 -2
  112. langchain/callbacks/infino_callback.py +1 -1
  113. langchain/callbacks/labelstudio_callback.py +1 -1
  114. langchain/callbacks/llmonitor_callback.py +1 -1
  115. langchain/callbacks/manager.py +5 -5
  116. langchain/callbacks/mlflow_callback.py +2 -2
  117. langchain/callbacks/openai_info.py +1 -1
  118. langchain/callbacks/promptlayer_callback.py +1 -1
  119. langchain/callbacks/sagemaker_callback.py +1 -1
  120. langchain/callbacks/streaming_aiter.py +4 -1
  121. langchain/callbacks/streaming_aiter_final_only.py +5 -3
  122. langchain/callbacks/streaming_stdout_final_only.py +5 -3
  123. langchain/callbacks/streamlit/__init__.py +3 -2
  124. langchain/callbacks/streamlit/mutable_expander.py +1 -1
  125. langchain/callbacks/streamlit/streamlit_callback_handler.py +3 -3
  126. langchain/callbacks/tracers/__init__.py +1 -1
  127. langchain/callbacks/tracers/comet.py +1 -1
  128. langchain/callbacks/tracers/evaluation.py +1 -1
  129. langchain/callbacks/tracers/log_stream.py +1 -1
  130. langchain/callbacks/tracers/logging.py +1 -1
  131. langchain/callbacks/tracers/stdout.py +1 -1
  132. langchain/callbacks/trubrics_callback.py +1 -1
  133. langchain/callbacks/utils.py +4 -4
  134. langchain/callbacks/wandb_callback.py +1 -1
  135. langchain/callbacks/whylabs_callback.py +1 -1
  136. langchain/chains/api/base.py +36 -22
  137. langchain/chains/api/news_docs.py +1 -2
  138. langchain/chains/api/open_meteo_docs.py +1 -2
  139. langchain/chains/api/openapi/requests_chain.py +1 -1
  140. langchain/chains/api/openapi/response_chain.py +1 -1
  141. langchain/chains/api/podcast_docs.py +1 -2
  142. langchain/chains/api/prompt.py +1 -2
  143. langchain/chains/api/tmdb_docs.py +1 -2
  144. langchain/chains/base.py +88 -54
  145. langchain/chains/chat_vector_db/prompts.py +2 -3
  146. langchain/chains/combine_documents/__init__.py +1 -1
  147. langchain/chains/combine_documents/base.py +23 -10
  148. langchain/chains/combine_documents/map_reduce.py +38 -30
  149. langchain/chains/combine_documents/map_rerank.py +33 -20
  150. langchain/chains/combine_documents/reduce.py +47 -26
  151. langchain/chains/combine_documents/refine.py +26 -17
  152. langchain/chains/combine_documents/stuff.py +19 -12
  153. langchain/chains/constitutional_ai/base.py +4 -4
  154. langchain/chains/constitutional_ai/principles.py +22 -25
  155. langchain/chains/constitutional_ai/prompts.py +25 -28
  156. langchain/chains/conversation/base.py +5 -3
  157. langchain/chains/conversation/memory.py +5 -5
  158. langchain/chains/conversation/prompt.py +5 -5
  159. langchain/chains/conversational_retrieval/base.py +41 -20
  160. langchain/chains/conversational_retrieval/prompts.py +2 -3
  161. langchain/chains/elasticsearch_database/base.py +8 -9
  162. langchain/chains/elasticsearch_database/prompts.py +2 -3
  163. langchain/chains/ernie_functions/__init__.py +2 -2
  164. langchain/chains/example_generator.py +3 -1
  165. langchain/chains/flare/base.py +26 -12
  166. langchain/chains/graph_qa/cypher.py +2 -2
  167. langchain/chains/graph_qa/falkordb.py +1 -1
  168. langchain/chains/graph_qa/gremlin.py +1 -1
  169. langchain/chains/graph_qa/neptune_sparql.py +1 -1
  170. langchain/chains/graph_qa/prompts.py +2 -2
  171. langchain/chains/history_aware_retriever.py +2 -1
  172. langchain/chains/hyde/base.py +6 -5
  173. langchain/chains/hyde/prompts.py +5 -6
  174. langchain/chains/llm.py +77 -61
  175. langchain/chains/llm_bash/__init__.py +2 -1
  176. langchain/chains/llm_checker/base.py +7 -5
  177. langchain/chains/llm_checker/prompt.py +3 -4
  178. langchain/chains/llm_math/base.py +16 -9
  179. langchain/chains/llm_math/prompt.py +1 -2
  180. langchain/chains/llm_summarization_checker/base.py +9 -6
  181. langchain/chains/llm_symbolic_math/__init__.py +2 -1
  182. langchain/chains/loading.py +151 -95
  183. langchain/chains/mapreduce.py +4 -3
  184. langchain/chains/moderation.py +8 -9
  185. langchain/chains/natbot/base.py +8 -8
  186. langchain/chains/natbot/crawler.py +73 -76
  187. langchain/chains/natbot/prompt.py +2 -3
  188. langchain/chains/openai_functions/__init__.py +7 -7
  189. langchain/chains/openai_functions/base.py +13 -10
  190. langchain/chains/openai_functions/citation_fuzzy_match.py +12 -11
  191. langchain/chains/openai_functions/extraction.py +19 -19
  192. langchain/chains/openai_functions/openapi.py +35 -35
  193. langchain/chains/openai_functions/qa_with_structure.py +19 -12
  194. langchain/chains/openai_functions/tagging.py +2 -4
  195. langchain/chains/openai_tools/extraction.py +7 -8
  196. langchain/chains/qa_generation/base.py +4 -3
  197. langchain/chains/qa_generation/prompt.py +5 -5
  198. langchain/chains/qa_with_sources/base.py +14 -6
  199. langchain/chains/qa_with_sources/loading.py +16 -8
  200. langchain/chains/qa_with_sources/map_reduce_prompt.py +8 -9
  201. langchain/chains/qa_with_sources/refine_prompts.py +0 -1
  202. langchain/chains/qa_with_sources/retrieval.py +14 -5
  203. langchain/chains/qa_with_sources/stuff_prompt.py +6 -7
  204. langchain/chains/qa_with_sources/vector_db.py +17 -6
  205. langchain/chains/query_constructor/base.py +34 -33
  206. langchain/chains/query_constructor/ir.py +4 -4
  207. langchain/chains/query_constructor/parser.py +37 -32
  208. langchain/chains/query_constructor/prompt.py +5 -6
  209. langchain/chains/question_answering/chain.py +21 -10
  210. langchain/chains/question_answering/map_reduce_prompt.py +14 -14
  211. langchain/chains/question_answering/map_rerank_prompt.py +3 -3
  212. langchain/chains/question_answering/refine_prompts.py +2 -5
  213. langchain/chains/question_answering/stuff_prompt.py +5 -5
  214. langchain/chains/retrieval.py +1 -3
  215. langchain/chains/retrieval_qa/base.py +34 -27
  216. langchain/chains/retrieval_qa/prompt.py +1 -2
  217. langchain/chains/router/__init__.py +3 -3
  218. langchain/chains/router/base.py +24 -20
  219. langchain/chains/router/embedding_router.py +12 -8
  220. langchain/chains/router/llm_router.py +17 -16
  221. langchain/chains/router/multi_prompt.py +2 -2
  222. langchain/chains/router/multi_retrieval_qa.py +10 -5
  223. langchain/chains/sequential.py +30 -18
  224. langchain/chains/sql_database/prompt.py +14 -16
  225. langchain/chains/sql_database/query.py +6 -5
  226. langchain/chains/structured_output/__init__.py +1 -1
  227. langchain/chains/structured_output/base.py +75 -67
  228. langchain/chains/summarize/chain.py +11 -5
  229. langchain/chains/summarize/map_reduce_prompt.py +0 -1
  230. langchain/chains/summarize/stuff_prompt.py +0 -1
  231. langchain/chains/transform.py +5 -6
  232. langchain/chat_loaders/facebook_messenger.py +1 -1
  233. langchain/chat_loaders/langsmith.py +1 -1
  234. langchain/chat_loaders/utils.py +3 -3
  235. langchain/chat_models/__init__.py +20 -19
  236. langchain/chat_models/anthropic.py +1 -1
  237. langchain/chat_models/azureml_endpoint.py +1 -1
  238. langchain/chat_models/baidu_qianfan_endpoint.py +1 -1
  239. langchain/chat_models/base.py +160 -123
  240. langchain/chat_models/bedrock.py +1 -1
  241. langchain/chat_models/fake.py +1 -1
  242. langchain/chat_models/meta.py +1 -1
  243. langchain/chat_models/pai_eas_endpoint.py +1 -1
  244. langchain/chat_models/promptlayer_openai.py +1 -1
  245. langchain/chat_models/volcengine_maas.py +1 -1
  246. langchain/docstore/base.py +1 -1
  247. langchain/document_loaders/__init__.py +9 -9
  248. langchain/document_loaders/airbyte.py +3 -3
  249. langchain/document_loaders/assemblyai.py +1 -1
  250. langchain/document_loaders/azure_blob_storage_container.py +1 -1
  251. langchain/document_loaders/azure_blob_storage_file.py +1 -1
  252. langchain/document_loaders/baiducloud_bos_file.py +1 -1
  253. langchain/document_loaders/base.py +1 -1
  254. langchain/document_loaders/blob_loaders/__init__.py +1 -1
  255. langchain/document_loaders/blockchain.py +1 -1
  256. langchain/document_loaders/chatgpt.py +1 -1
  257. langchain/document_loaders/college_confidential.py +1 -1
  258. langchain/document_loaders/confluence.py +1 -1
  259. langchain/document_loaders/email.py +1 -1
  260. langchain/document_loaders/facebook_chat.py +1 -1
  261. langchain/document_loaders/markdown.py +1 -1
  262. langchain/document_loaders/notebook.py +1 -1
  263. langchain/document_loaders/org_mode.py +1 -1
  264. langchain/document_loaders/parsers/__init__.py +1 -1
  265. langchain/document_loaders/parsers/docai.py +1 -1
  266. langchain/document_loaders/parsers/generic.py +1 -1
  267. langchain/document_loaders/parsers/html/__init__.py +1 -1
  268. langchain/document_loaders/parsers/html/bs4.py +1 -1
  269. langchain/document_loaders/parsers/language/cobol.py +1 -1
  270. langchain/document_loaders/parsers/language/python.py +1 -1
  271. langchain/document_loaders/parsers/msword.py +1 -1
  272. langchain/document_loaders/parsers/pdf.py +5 -5
  273. langchain/document_loaders/parsers/registry.py +1 -1
  274. langchain/document_loaders/pdf.py +8 -8
  275. langchain/document_loaders/powerpoint.py +1 -1
  276. langchain/document_loaders/pyspark_dataframe.py +1 -1
  277. langchain/document_loaders/telegram.py +2 -2
  278. langchain/document_loaders/tencent_cos_directory.py +1 -1
  279. langchain/document_loaders/unstructured.py +5 -5
  280. langchain/document_loaders/url_playwright.py +1 -1
  281. langchain/document_loaders/whatsapp_chat.py +1 -1
  282. langchain/document_loaders/youtube.py +2 -2
  283. langchain/document_transformers/__init__.py +3 -3
  284. langchain/document_transformers/beautiful_soup_transformer.py +1 -1
  285. langchain/document_transformers/doctran_text_extract.py +1 -1
  286. langchain/document_transformers/doctran_text_qa.py +1 -1
  287. langchain/document_transformers/doctran_text_translate.py +1 -1
  288. langchain/document_transformers/embeddings_redundant_filter.py +3 -3
  289. langchain/document_transformers/google_translate.py +1 -1
  290. langchain/document_transformers/html2text.py +1 -1
  291. langchain/document_transformers/nuclia_text_transform.py +1 -1
  292. langchain/embeddings/__init__.py +5 -5
  293. langchain/embeddings/base.py +33 -24
  294. langchain/embeddings/cache.py +36 -31
  295. langchain/embeddings/fake.py +1 -1
  296. langchain/embeddings/huggingface.py +2 -2
  297. langchain/evaluation/__init__.py +22 -22
  298. langchain/evaluation/agents/trajectory_eval_chain.py +23 -23
  299. langchain/evaluation/agents/trajectory_eval_prompt.py +6 -9
  300. langchain/evaluation/comparison/__init__.py +1 -1
  301. langchain/evaluation/comparison/eval_chain.py +20 -13
  302. langchain/evaluation/comparison/prompt.py +1 -2
  303. langchain/evaluation/criteria/__init__.py +1 -1
  304. langchain/evaluation/criteria/eval_chain.py +20 -11
  305. langchain/evaluation/criteria/prompt.py +2 -3
  306. langchain/evaluation/embedding_distance/base.py +23 -20
  307. langchain/evaluation/loading.py +15 -11
  308. langchain/evaluation/parsing/base.py +4 -1
  309. langchain/evaluation/parsing/json_distance.py +5 -2
  310. langchain/evaluation/parsing/json_schema.py +12 -8
  311. langchain/evaluation/qa/__init__.py +1 -1
  312. langchain/evaluation/qa/eval_chain.py +12 -5
  313. langchain/evaluation/qa/eval_prompt.py +7 -8
  314. langchain/evaluation/qa/generate_chain.py +2 -1
  315. langchain/evaluation/qa/generate_prompt.py +2 -4
  316. langchain/evaluation/schema.py +38 -30
  317. langchain/evaluation/scoring/__init__.py +1 -1
  318. langchain/evaluation/scoring/eval_chain.py +22 -15
  319. langchain/evaluation/scoring/prompt.py +0 -1
  320. langchain/evaluation/string_distance/base.py +14 -9
  321. langchain/globals.py +12 -11
  322. langchain/graphs/__init__.py +6 -6
  323. langchain/graphs/graph_document.py +1 -1
  324. langchain/graphs/networkx_graph.py +2 -2
  325. langchain/hub.py +9 -11
  326. langchain/indexes/__init__.py +3 -3
  327. langchain/indexes/_sql_record_manager.py +63 -46
  328. langchain/indexes/prompts/entity_extraction.py +1 -2
  329. langchain/indexes/prompts/entity_summarization.py +1 -2
  330. langchain/indexes/prompts/knowledge_triplet_extraction.py +1 -3
  331. langchain/indexes/vectorstore.py +35 -19
  332. langchain/llms/__init__.py +13 -13
  333. langchain/llms/ai21.py +1 -1
  334. langchain/llms/azureml_endpoint.py +4 -4
  335. langchain/llms/base.py +15 -7
  336. langchain/llms/bedrock.py +1 -1
  337. langchain/llms/cloudflare_workersai.py +1 -1
  338. langchain/llms/gradient_ai.py +1 -1
  339. langchain/llms/loading.py +1 -1
  340. langchain/llms/openai.py +1 -1
  341. langchain/llms/sagemaker_endpoint.py +1 -1
  342. langchain/load/dump.py +1 -1
  343. langchain/load/load.py +1 -1
  344. langchain/load/serializable.py +3 -3
  345. langchain/memory/__init__.py +3 -3
  346. langchain/memory/buffer.py +9 -7
  347. langchain/memory/chat_memory.py +14 -8
  348. langchain/memory/chat_message_histories/__init__.py +1 -1
  349. langchain/memory/chat_message_histories/astradb.py +1 -1
  350. langchain/memory/chat_message_histories/cassandra.py +1 -1
  351. langchain/memory/chat_message_histories/cosmos_db.py +1 -1
  352. langchain/memory/chat_message_histories/dynamodb.py +1 -1
  353. langchain/memory/chat_message_histories/elasticsearch.py +1 -1
  354. langchain/memory/chat_message_histories/file.py +1 -1
  355. langchain/memory/chat_message_histories/firestore.py +1 -1
  356. langchain/memory/chat_message_histories/momento.py +1 -1
  357. langchain/memory/chat_message_histories/mongodb.py +1 -1
  358. langchain/memory/chat_message_histories/neo4j.py +1 -1
  359. langchain/memory/chat_message_histories/postgres.py +1 -1
  360. langchain/memory/chat_message_histories/redis.py +1 -1
  361. langchain/memory/chat_message_histories/rocksetdb.py +1 -1
  362. langchain/memory/chat_message_histories/singlestoredb.py +1 -1
  363. langchain/memory/chat_message_histories/streamlit.py +1 -1
  364. langchain/memory/chat_message_histories/upstash_redis.py +1 -1
  365. langchain/memory/chat_message_histories/xata.py +1 -1
  366. langchain/memory/chat_message_histories/zep.py +1 -1
  367. langchain/memory/combined.py +13 -12
  368. langchain/memory/entity.py +84 -61
  369. langchain/memory/prompt.py +10 -11
  370. langchain/memory/readonly.py +0 -2
  371. langchain/memory/simple.py +1 -3
  372. langchain/memory/summary.py +13 -11
  373. langchain/memory/summary_buffer.py +17 -8
  374. langchain/memory/utils.py +3 -2
  375. langchain/memory/vectorstore.py +12 -5
  376. langchain/memory/vectorstore_token_buffer_memory.py +5 -5
  377. langchain/model_laboratory.py +12 -11
  378. langchain/output_parsers/__init__.py +4 -4
  379. langchain/output_parsers/boolean.py +7 -4
  380. langchain/output_parsers/combining.py +10 -5
  381. langchain/output_parsers/datetime.py +32 -31
  382. langchain/output_parsers/enum.py +5 -3
  383. langchain/output_parsers/fix.py +52 -52
  384. langchain/output_parsers/format_instructions.py +6 -8
  385. langchain/output_parsers/json.py +2 -2
  386. langchain/output_parsers/list.py +2 -2
  387. langchain/output_parsers/loading.py +9 -9
  388. langchain/output_parsers/openai_functions.py +3 -3
  389. langchain/output_parsers/openai_tools.py +1 -1
  390. langchain/output_parsers/pandas_dataframe.py +43 -47
  391. langchain/output_parsers/prompts.py +1 -2
  392. langchain/output_parsers/rail_parser.py +1 -1
  393. langchain/output_parsers/regex.py +7 -8
  394. langchain/output_parsers/regex_dict.py +7 -10
  395. langchain/output_parsers/retry.py +77 -78
  396. langchain/output_parsers/structured.py +11 -6
  397. langchain/output_parsers/yaml.py +15 -11
  398. langchain/prompts/__init__.py +5 -3
  399. langchain/prompts/base.py +5 -5
  400. langchain/prompts/chat.py +8 -8
  401. langchain/prompts/example_selector/__init__.py +3 -1
  402. langchain/prompts/example_selector/semantic_similarity.py +2 -2
  403. langchain/prompts/few_shot.py +1 -1
  404. langchain/prompts/loading.py +3 -3
  405. langchain/prompts/prompt.py +1 -1
  406. langchain/retrievers/__init__.py +5 -5
  407. langchain/retrievers/bedrock.py +2 -2
  408. langchain/retrievers/bm25.py +1 -1
  409. langchain/retrievers/contextual_compression.py +14 -8
  410. langchain/retrievers/docarray.py +1 -1
  411. langchain/retrievers/document_compressors/__init__.py +5 -4
  412. langchain/retrievers/document_compressors/base.py +12 -6
  413. langchain/retrievers/document_compressors/chain_extract.py +2 -2
  414. langchain/retrievers/document_compressors/chain_extract_prompt.py +2 -3
  415. langchain/retrievers/document_compressors/chain_filter.py +9 -9
  416. langchain/retrievers/document_compressors/chain_filter_prompt.py +1 -2
  417. langchain/retrievers/document_compressors/cohere_rerank.py +15 -15
  418. langchain/retrievers/document_compressors/embeddings_filter.py +21 -17
  419. langchain/retrievers/document_compressors/flashrank_rerank.py +1 -1
  420. langchain/retrievers/document_compressors/listwise_rerank.py +7 -5
  421. langchain/retrievers/ensemble.py +28 -25
  422. langchain/retrievers/google_cloud_documentai_warehouse.py +1 -1
  423. langchain/retrievers/google_vertex_ai_search.py +2 -2
  424. langchain/retrievers/kendra.py +10 -10
  425. langchain/retrievers/llama_index.py +1 -1
  426. langchain/retrievers/merger_retriever.py +11 -11
  427. langchain/retrievers/milvus.py +1 -1
  428. langchain/retrievers/multi_query.py +32 -26
  429. langchain/retrievers/multi_vector.py +20 -8
  430. langchain/retrievers/parent_document_retriever.py +18 -9
  431. langchain/retrievers/re_phraser.py +6 -5
  432. langchain/retrievers/self_query/base.py +138 -127
  433. langchain/retrievers/time_weighted_retriever.py +18 -7
  434. langchain/retrievers/zilliz.py +1 -1
  435. langchain/runnables/openai_functions.py +6 -2
  436. langchain/schema/__init__.py +23 -23
  437. langchain/schema/cache.py +1 -1
  438. langchain/schema/callbacks/base.py +7 -7
  439. langchain/schema/callbacks/manager.py +19 -19
  440. langchain/schema/callbacks/tracers/base.py +1 -1
  441. langchain/schema/callbacks/tracers/evaluation.py +1 -1
  442. langchain/schema/callbacks/tracers/langchain.py +1 -1
  443. langchain/schema/callbacks/tracers/langchain_v1.py +1 -1
  444. langchain/schema/callbacks/tracers/log_stream.py +1 -1
  445. langchain/schema/callbacks/tracers/schemas.py +8 -8
  446. langchain/schema/callbacks/tracers/stdout.py +3 -3
  447. langchain/schema/document.py +1 -1
  448. langchain/schema/language_model.py +2 -2
  449. langchain/schema/messages.py +12 -12
  450. langchain/schema/output.py +3 -3
  451. langchain/schema/output_parser.py +3 -3
  452. langchain/schema/runnable/__init__.py +3 -3
  453. langchain/schema/runnable/base.py +9 -9
  454. langchain/schema/runnable/config.py +5 -5
  455. langchain/schema/runnable/configurable.py +1 -1
  456. langchain/schema/runnable/history.py +1 -1
  457. langchain/schema/runnable/passthrough.py +1 -1
  458. langchain/schema/runnable/utils.py +16 -16
  459. langchain/schema/vectorstore.py +1 -1
  460. langchain/smith/__init__.py +1 -1
  461. langchain/smith/evaluation/__init__.py +2 -2
  462. langchain/smith/evaluation/config.py +10 -7
  463. langchain/smith/evaluation/name_generation.py +3 -3
  464. langchain/smith/evaluation/progress.py +11 -2
  465. langchain/smith/evaluation/runner_utils.py +179 -127
  466. langchain/smith/evaluation/string_run_evaluator.py +75 -68
  467. langchain/storage/__init__.py +2 -2
  468. langchain/storage/_lc_store.py +4 -2
  469. langchain/storage/encoder_backed.py +6 -2
  470. langchain/storage/file_system.py +19 -16
  471. langchain/storage/in_memory.py +1 -1
  472. langchain/storage/upstash_redis.py +1 -1
  473. langchain/text_splitter.py +15 -15
  474. langchain/tools/__init__.py +28 -26
  475. langchain/tools/ainetwork/app.py +1 -1
  476. langchain/tools/ainetwork/base.py +1 -1
  477. langchain/tools/ainetwork/owner.py +1 -1
  478. langchain/tools/ainetwork/rule.py +1 -1
  479. langchain/tools/ainetwork/transfer.py +1 -1
  480. langchain/tools/ainetwork/value.py +1 -1
  481. langchain/tools/amadeus/closest_airport.py +1 -1
  482. langchain/tools/amadeus/flight_search.py +1 -1
  483. langchain/tools/azure_cognitive_services/__init__.py +1 -1
  484. langchain/tools/base.py +4 -4
  485. langchain/tools/bearly/tool.py +1 -1
  486. langchain/tools/bing_search/__init__.py +1 -1
  487. langchain/tools/bing_search/tool.py +1 -1
  488. langchain/tools/dataforseo_api_search/__init__.py +1 -1
  489. langchain/tools/dataforseo_api_search/tool.py +1 -1
  490. langchain/tools/ddg_search/tool.py +1 -1
  491. langchain/tools/e2b_data_analysis/tool.py +2 -2
  492. langchain/tools/edenai/__init__.py +1 -1
  493. langchain/tools/file_management/__init__.py +1 -1
  494. langchain/tools/file_management/copy.py +1 -1
  495. langchain/tools/file_management/delete.py +1 -1
  496. langchain/tools/gmail/__init__.py +2 -2
  497. langchain/tools/gmail/get_message.py +1 -1
  498. langchain/tools/gmail/search.py +1 -1
  499. langchain/tools/gmail/send_message.py +1 -1
  500. langchain/tools/google_finance/__init__.py +1 -1
  501. langchain/tools/google_finance/tool.py +1 -1
  502. langchain/tools/google_scholar/__init__.py +1 -1
  503. langchain/tools/google_scholar/tool.py +1 -1
  504. langchain/tools/google_search/__init__.py +1 -1
  505. langchain/tools/google_search/tool.py +1 -1
  506. langchain/tools/google_serper/__init__.py +1 -1
  507. langchain/tools/google_serper/tool.py +1 -1
  508. langchain/tools/google_trends/__init__.py +1 -1
  509. langchain/tools/google_trends/tool.py +1 -1
  510. langchain/tools/jira/tool.py +20 -1
  511. langchain/tools/json/tool.py +25 -3
  512. langchain/tools/memorize/tool.py +1 -1
  513. langchain/tools/multion/__init__.py +1 -1
  514. langchain/tools/multion/update_session.py +1 -1
  515. langchain/tools/office365/__init__.py +2 -2
  516. langchain/tools/office365/events_search.py +1 -1
  517. langchain/tools/office365/messages_search.py +1 -1
  518. langchain/tools/office365/send_event.py +1 -1
  519. langchain/tools/office365/send_message.py +1 -1
  520. langchain/tools/openapi/utils/api_models.py +6 -6
  521. langchain/tools/playwright/__init__.py +5 -5
  522. langchain/tools/playwright/click.py +1 -1
  523. langchain/tools/playwright/extract_hyperlinks.py +1 -1
  524. langchain/tools/playwright/get_elements.py +1 -1
  525. langchain/tools/playwright/navigate.py +1 -1
  526. langchain/tools/plugin.py +2 -2
  527. langchain/tools/powerbi/tool.py +1 -1
  528. langchain/tools/python/__init__.py +2 -1
  529. langchain/tools/reddit_search/tool.py +1 -1
  530. langchain/tools/render.py +2 -2
  531. langchain/tools/requests/tool.py +2 -2
  532. langchain/tools/searchapi/tool.py +1 -1
  533. langchain/tools/searx_search/tool.py +1 -1
  534. langchain/tools/slack/get_message.py +1 -1
  535. langchain/tools/spark_sql/tool.py +1 -1
  536. langchain/tools/sql_database/tool.py +1 -1
  537. langchain/tools/tavily_search/__init__.py +1 -1
  538. langchain/tools/tavily_search/tool.py +1 -1
  539. langchain/tools/zapier/__init__.py +1 -1
  540. langchain/tools/zapier/tool.py +24 -2
  541. langchain/utilities/__init__.py +4 -4
  542. langchain/utilities/arcee.py +4 -4
  543. langchain/utilities/clickup.py +4 -4
  544. langchain/utilities/dalle_image_generator.py +1 -1
  545. langchain/utilities/dataforseo_api_search.py +1 -1
  546. langchain/utilities/opaqueprompts.py +1 -1
  547. langchain/utilities/reddit_search.py +1 -1
  548. langchain/utilities/sql_database.py +1 -1
  549. langchain/utilities/tavily_search.py +1 -1
  550. langchain/utilities/vertexai.py +2 -2
  551. langchain/utils/__init__.py +1 -1
  552. langchain/utils/aiter.py +1 -1
  553. langchain/utils/html.py +3 -3
  554. langchain/utils/input.py +1 -1
  555. langchain/utils/iter.py +1 -1
  556. langchain/utils/json_schema.py +1 -3
  557. langchain/utils/strings.py +1 -1
  558. langchain/utils/utils.py +6 -6
  559. langchain/vectorstores/__init__.py +5 -5
  560. langchain/vectorstores/alibabacloud_opensearch.py +1 -1
  561. langchain/vectorstores/azure_cosmos_db.py +1 -1
  562. langchain/vectorstores/clickhouse.py +1 -1
  563. langchain/vectorstores/elastic_vector_search.py +1 -1
  564. langchain/vectorstores/elasticsearch.py +2 -2
  565. langchain/vectorstores/myscale.py +1 -1
  566. langchain/vectorstores/neo4j_vector.py +1 -1
  567. langchain/vectorstores/pgembedding.py +1 -1
  568. langchain/vectorstores/qdrant.py +1 -1
  569. langchain/vectorstores/redis/__init__.py +1 -1
  570. langchain/vectorstores/redis/base.py +1 -1
  571. langchain/vectorstores/redis/filters.py +4 -4
  572. langchain/vectorstores/redis/schema.py +6 -6
  573. langchain/vectorstores/sklearn.py +2 -2
  574. langchain/vectorstores/starrocks.py +1 -1
  575. langchain/vectorstores/utils.py +1 -1
  576. {langchain-0.3.26.dist-info → langchain-0.3.27.dist-info}/METADATA +4 -4
  577. {langchain-0.3.26.dist-info → langchain-0.3.27.dist-info}/RECORD +580 -580
  578. {langchain-0.3.26.dist-info → langchain-0.3.27.dist-info}/WHEEL +1 -1
  579. {langchain-0.3.26.dist-info → langchain-0.3.27.dist-info}/entry_points.txt +0 -0
  580. {langchain-0.3.26.dist-info → langchain-0.3.27.dist-info}/licenses/LICENSE +0 -0
@@ -38,26 +38,29 @@ _FunctionsAgentAction = AgentActionMessageLog
38
38
  def _parse_ai_message(message: BaseMessage) -> Union[list[AgentAction], AgentFinish]:
39
39
  """Parse an AI message."""
40
40
  if not isinstance(message, AIMessage):
41
- raise TypeError(f"Expected an AI message got {type(message)}")
41
+ msg = f"Expected an AI message got {type(message)}"
42
+ raise TypeError(msg)
42
43
 
43
44
  function_call = message.additional_kwargs.get("function_call", {})
44
45
 
45
46
  if function_call:
46
47
  try:
47
48
  arguments = json.loads(function_call["arguments"], strict=False)
48
- except JSONDecodeError:
49
- raise OutputParserException(
49
+ except JSONDecodeError as e:
50
+ msg = (
50
51
  f"Could not parse tool input: {function_call} because "
51
52
  f"the `arguments` is not valid JSON."
52
53
  )
54
+ raise OutputParserException(msg) from e
53
55
 
54
56
  try:
55
57
  tools = arguments["actions"]
56
- except (TypeError, KeyError):
57
- raise OutputParserException(
58
+ except (TypeError, KeyError) as e:
59
+ msg = (
58
60
  f"Could not parse tool input: {function_call} because "
59
61
  f"the `arguments` JSON does not contain `actions` key."
60
62
  )
63
+ raise OutputParserException(msg) from e
61
64
 
62
65
  final_tools: list[AgentAction] = []
63
66
  for tool_schema in tools:
@@ -92,10 +95,14 @@ def _parse_ai_message(message: BaseMessage) -> Union[list[AgentAction], AgentFin
92
95
  return final_tools
93
96
 
94
97
  return AgentFinish(
95
- return_values={"output": message.content}, log=str(message.content)
98
+ return_values={"output": message.content},
99
+ log=str(message.content),
96
100
  )
97
101
 
98
102
 
103
+ _NOT_SET = object()
104
+
105
+
99
106
  @deprecated("0.1.0", alternative="create_openai_tools_agent", removal="1.0")
100
107
  class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
101
108
  """Agent driven by OpenAIs function powered API.
@@ -121,10 +128,11 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
121
128
  def validate_prompt(self) -> Self:
122
129
  prompt: BasePromptTemplate = self.prompt
123
130
  if "agent_scratchpad" not in prompt.input_variables:
124
- raise ValueError(
131
+ msg = (
125
132
  "`agent_scratchpad` should be one of the variables in the prompt, "
126
133
  f"got {prompt.input_variables}"
127
134
  )
135
+ raise ValueError(msg)
128
136
  return self
129
137
 
130
138
  @property
@@ -186,7 +194,7 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
186
194
  },
187
195
  "required": ["action_name", "action"],
188
196
  },
189
- }
197
+ },
190
198
  },
191
199
  "required": ["actions"],
192
200
  },
@@ -218,10 +226,11 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
218
226
  prompt = self.prompt.format_prompt(**full_inputs)
219
227
  messages = prompt.to_messages()
220
228
  predicted_message = self.llm.predict_messages(
221
- messages, functions=self.functions, callbacks=callbacks
229
+ messages,
230
+ functions=self.functions,
231
+ callbacks=callbacks,
222
232
  )
223
- agent_decision = _parse_ai_message(predicted_message)
224
- return agent_decision
233
+ return _parse_ai_message(predicted_message)
225
234
 
226
235
  async def aplan(
227
236
  self,
@@ -248,17 +257,16 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
248
257
  prompt = self.prompt.format_prompt(**full_inputs)
249
258
  messages = prompt.to_messages()
250
259
  predicted_message = await self.llm.apredict_messages(
251
- messages, functions=self.functions, callbacks=callbacks
260
+ messages,
261
+ functions=self.functions,
262
+ callbacks=callbacks,
252
263
  )
253
- agent_decision = _parse_ai_message(predicted_message)
254
- return agent_decision
264
+ return _parse_ai_message(predicted_message)
255
265
 
256
266
  @classmethod
257
267
  def create_prompt(
258
268
  cls,
259
- system_message: Optional[SystemMessage] = SystemMessage(
260
- content="You are a helpful AI assistant."
261
- ),
269
+ system_message: Optional[SystemMessage] = _NOT_SET, # type: ignore[assignment]
262
270
  extra_prompt_messages: Optional[list[BaseMessagePromptTemplate]] = None,
263
271
  ) -> BasePromptTemplate:
264
272
  """Create prompt for this agent.
@@ -273,18 +281,20 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
273
281
  A prompt template to pass into this agent.
274
282
  """
275
283
  _prompts = extra_prompt_messages or []
284
+ system_message_ = (
285
+ system_message
286
+ if system_message is not _NOT_SET
287
+ else SystemMessage(content="You are a helpful AI assistant.")
288
+ )
276
289
  messages: list[Union[BaseMessagePromptTemplate, BaseMessage]]
277
- if system_message:
278
- messages = [system_message]
279
- else:
280
- messages = []
290
+ messages = [system_message_] if system_message_ else []
281
291
 
282
292
  messages.extend(
283
293
  [
284
294
  *_prompts,
285
295
  HumanMessagePromptTemplate.from_template("{input}"),
286
296
  MessagesPlaceholder(variable_name="agent_scratchpad"),
287
- ]
297
+ ],
288
298
  )
289
299
  return ChatPromptTemplate(messages=messages)
290
300
 
@@ -295,9 +305,7 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
295
305
  tools: Sequence[BaseTool],
296
306
  callback_manager: Optional[BaseCallbackManager] = None,
297
307
  extra_prompt_messages: Optional[list[BaseMessagePromptTemplate]] = None,
298
- system_message: Optional[SystemMessage] = SystemMessage(
299
- content="You are a helpful AI assistant."
300
- ),
308
+ system_message: Optional[SystemMessage] = _NOT_SET, # type: ignore[assignment]
301
309
  **kwargs: Any,
302
310
  ) -> BaseMultiActionAgent:
303
311
  """Construct an agent from an LLM and tools.
@@ -311,9 +319,14 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
311
319
  Default is a default system message.
312
320
  kwargs: Additional arguments.
313
321
  """
322
+ system_message_ = (
323
+ system_message
324
+ if system_message is not _NOT_SET
325
+ else SystemMessage(content="You are a helpful AI assistant.")
326
+ )
314
327
  prompt = cls.create_prompt(
315
328
  extra_prompt_messages=extra_prompt_messages,
316
- system_message=system_message,
329
+ system_message=system_message_,
317
330
  )
318
331
  return cls( # type: ignore[call-arg]
319
332
  llm=llm,
@@ -17,7 +17,7 @@ def create_openai_tools_agent(
17
17
  llm: BaseLanguageModel,
18
18
  tools: Sequence[BaseTool],
19
19
  prompt: ChatPromptTemplate,
20
- strict: Optional[bool] = None,
20
+ strict: Optional[bool] = None, # noqa: FBT001
21
21
  ) -> Runnable:
22
22
  """Create an agent that uses OpenAI tools.
23
23
 
@@ -86,23 +86,23 @@ def create_openai_tools_agent(
86
86
  )
87
87
  """
88
88
  missing_vars = {"agent_scratchpad"}.difference(
89
- prompt.input_variables + list(prompt.partial_variables)
89
+ prompt.input_variables + list(prompt.partial_variables),
90
90
  )
91
91
  if missing_vars:
92
- raise ValueError(f"Prompt missing required variables: {missing_vars}")
92
+ msg = f"Prompt missing required variables: {missing_vars}"
93
+ raise ValueError(msg)
93
94
 
94
95
  llm_with_tools = llm.bind(
95
- tools=[convert_to_openai_tool(tool, strict=strict) for tool in tools]
96
+ tools=[convert_to_openai_tool(tool, strict=strict) for tool in tools],
96
97
  )
97
98
 
98
- agent = (
99
+ return (
99
100
  RunnablePassthrough.assign(
100
101
  agent_scratchpad=lambda x: format_to_openai_tool_messages(
101
- x["intermediate_steps"]
102
- )
102
+ x["intermediate_steps"],
103
+ ),
103
104
  )
104
105
  | prompt
105
106
  | llm_with_tools
106
107
  | OpenAIToolsAgentOutputParser()
107
108
  )
108
- return agent
@@ -25,11 +25,11 @@ from langchain.agents.output_parsers.tools import ToolsAgentOutputParser
25
25
  from langchain.agents.output_parsers.xml import XMLAgentOutputParser
26
26
 
27
27
  __all__ = [
28
+ "JSONAgentOutputParser",
29
+ "OpenAIFunctionsAgentOutputParser",
30
+ "ReActJsonSingleInputOutputParser",
28
31
  "ReActSingleInputOutputParser",
29
32
  "SelfAskOutputParser",
30
33
  "ToolsAgentOutputParser",
31
- "ReActJsonSingleInputOutputParser",
32
- "OpenAIFunctionsAgentOutputParser",
33
34
  "XMLAgentOutputParser",
34
- "JSONAgentOutputParser",
35
35
  ]
@@ -49,13 +49,13 @@ class JSONAgentOutputParser(AgentOutputParser):
49
49
  response = response[0]
50
50
  if response["action"] == "Final Answer":
51
51
  return AgentFinish({"output": response["action_input"]}, text)
52
- else:
53
- action_input = response.get("action_input", {})
54
- if action_input is None:
55
- action_input = {}
56
- return AgentAction(response["action"], action_input, text)
52
+ action_input = response.get("action_input", {})
53
+ if action_input is None:
54
+ action_input = {}
55
+ return AgentAction(response["action"], action_input, text)
57
56
  except Exception as e:
58
- raise OutputParserException(f"Could not parse LLM output: {text}") from e
57
+ msg = f"Could not parse LLM output: {text}"
58
+ raise OutputParserException(msg) from e
59
59
 
60
60
  @property
61
61
  def _type(self) -> str:
@@ -33,7 +33,8 @@ class OpenAIFunctionsAgentOutputParser(AgentOutputParser):
33
33
  def _parse_ai_message(message: BaseMessage) -> Union[AgentAction, AgentFinish]:
34
34
  """Parse an AI message."""
35
35
  if not isinstance(message, AIMessage):
36
- raise TypeError(f"Expected an AI message got {type(message)}")
36
+ msg = f"Expected an AI message got {type(message)}"
37
+ raise TypeError(msg)
37
38
 
38
39
  function_call = message.additional_kwargs.get("function_call", {})
39
40
 
@@ -46,11 +47,12 @@ class OpenAIFunctionsAgentOutputParser(AgentOutputParser):
46
47
  else:
47
48
  # otherwise it returns a json object
48
49
  _tool_input = json.loads(function_call["arguments"], strict=False)
49
- except JSONDecodeError:
50
- raise OutputParserException(
50
+ except JSONDecodeError as e:
51
+ msg = (
51
52
  f"Could not parse tool input: {function_call} because "
52
53
  f"the `arguments` is not valid JSON."
53
54
  )
55
+ raise OutputParserException(msg) from e
54
56
 
55
57
  # HACK HACK HACK:
56
58
  # The code that encodes tool input into Open AI uses a special variable
@@ -73,16 +75,22 @@ class OpenAIFunctionsAgentOutputParser(AgentOutputParser):
73
75
  )
74
76
 
75
77
  return AgentFinish(
76
- return_values={"output": message.content}, log=str(message.content)
78
+ return_values={"output": message.content},
79
+ log=str(message.content),
77
80
  )
78
81
 
79
82
  def parse_result(
80
- self, result: list[Generation], *, partial: bool = False
83
+ self,
84
+ result: list[Generation],
85
+ *,
86
+ partial: bool = False,
81
87
  ) -> Union[AgentAction, AgentFinish]:
82
88
  if not isinstance(result[0], ChatGeneration):
83
- raise ValueError("This output parser only works on ChatGeneration output")
89
+ msg = "This output parser only works on ChatGeneration output"
90
+ raise ValueError(msg) # noqa: TRY004
84
91
  message = result[0].message
85
92
  return self._parse_ai_message(message)
86
93
 
87
94
  def parse(self, text: str) -> Union[AgentAction, AgentFinish]:
88
- raise ValueError("Can only parse messages")
95
+ msg = "Can only parse messages"
96
+ raise ValueError(msg)
@@ -30,7 +30,7 @@ def parse_ai_message_to_openai_tool_action(
30
30
  log=action.log,
31
31
  message_log=action.message_log,
32
32
  tool_call_id=action.tool_call_id,
33
- )
33
+ ),
34
34
  )
35
35
  else:
36
36
  final_actions.append(action)
@@ -54,12 +54,17 @@ class OpenAIToolsAgentOutputParser(MultiActionAgentOutputParser):
54
54
  return "openai-tools-agent-output-parser"
55
55
 
56
56
  def parse_result(
57
- self, result: list[Generation], *, partial: bool = False
57
+ self,
58
+ result: list[Generation],
59
+ *,
60
+ partial: bool = False,
58
61
  ) -> Union[list[AgentAction], AgentFinish]:
59
62
  if not isinstance(result[0], ChatGeneration):
60
- raise ValueError("This output parser only works on ChatGeneration output")
63
+ msg = "This output parser only works on ChatGeneration output"
64
+ raise ValueError(msg) # noqa: TRY004
61
65
  message = result[0].message
62
66
  return parse_ai_message_to_openai_tool_action(message)
63
67
 
64
68
  def parse(self, text: str) -> Union[list[AgentAction], AgentFinish]:
65
- raise ValueError("Can only parse messages")
69
+ msg = "Can only parse messages"
70
+ raise ValueError(msg)
@@ -55,22 +55,27 @@ class ReActJsonSingleInputOutputParser(AgentOutputParser):
55
55
  found = self.pattern.search(text)
56
56
  if not found:
57
57
  # Fast fail to parse Final Answer.
58
- raise ValueError("action not found")
58
+ msg = "action not found"
59
+ raise ValueError(msg)
59
60
  action = found.group(1)
60
61
  response = json.loads(action.strip())
61
62
  includes_action = "action" in response
62
63
  if includes_answer and includes_action:
63
- raise OutputParserException(
64
+ msg = (
64
65
  "Parsing LLM output produced a final answer "
65
66
  f"and a parse-able action: {text}"
66
67
  )
68
+ raise OutputParserException(msg)
67
69
  return AgentAction(
68
- response["action"], response.get("action_input", {}), text
70
+ response["action"],
71
+ response.get("action_input", {}),
72
+ text,
69
73
  )
70
74
 
71
- except Exception:
75
+ except Exception as e:
72
76
  if not includes_answer:
73
- raise OutputParserException(f"Could not parse LLM output: {text}")
77
+ msg = f"Could not parse LLM output: {text}"
78
+ raise OutputParserException(msg) from e
74
79
  output = text.split(FINAL_ANSWER_ACTION)[-1].strip()
75
80
  return AgentFinish({"output": output}, text)
76
81
 
@@ -56,9 +56,8 @@ class ReActSingleInputOutputParser(AgentOutputParser):
56
56
  action_match = re.search(regex, text, re.DOTALL)
57
57
  if action_match:
58
58
  if includes_answer:
59
- raise OutputParserException(
60
- f"{FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE}: {text}"
61
- )
59
+ msg = f"{FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE}: {text}"
60
+ raise OutputParserException(msg)
62
61
  action = action_match.group(1).strip()
63
62
  action_input = action_match.group(2)
64
63
  tool_input = action_input.strip(" ")
@@ -66,29 +65,34 @@ class ReActSingleInputOutputParser(AgentOutputParser):
66
65
 
67
66
  return AgentAction(action, tool_input, text)
68
67
 
69
- elif includes_answer:
68
+ if includes_answer:
70
69
  return AgentFinish(
71
- {"output": text.split(FINAL_ANSWER_ACTION)[-1].strip()}, text
70
+ {"output": text.split(FINAL_ANSWER_ACTION)[-1].strip()},
71
+ text,
72
72
  )
73
73
 
74
74
  if not re.search(r"Action\s*\d*\s*:[\s]*(.*?)", text, re.DOTALL):
75
+ msg = f"Could not parse LLM output: `{text}`"
75
76
  raise OutputParserException(
76
- f"Could not parse LLM output: `{text}`",
77
+ msg,
77
78
  observation=MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE,
78
79
  llm_output=text,
79
80
  send_to_llm=True,
80
81
  )
81
- elif not re.search(
82
- r"[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)", text, re.DOTALL
82
+ if not re.search(
83
+ r"[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)",
84
+ text,
85
+ re.DOTALL,
83
86
  ):
87
+ msg = f"Could not parse LLM output: `{text}`"
84
88
  raise OutputParserException(
85
- f"Could not parse LLM output: `{text}`",
89
+ msg,
86
90
  observation=MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE,
87
91
  llm_output=text,
88
92
  send_to_llm=True,
89
93
  )
90
- else:
91
- raise OutputParserException(f"Could not parse LLM output: `{text}`")
94
+ msg = f"Could not parse LLM output: `{text}`"
95
+ raise OutputParserException(msg)
92
96
 
93
97
  @property
94
98
  def _type(self) -> str:
@@ -37,9 +37,10 @@ class SelfAskOutputParser(AgentOutputParser):
37
37
 
38
38
  def parse(self, text: str) -> Union[AgentAction, AgentFinish]:
39
39
  last_line = text.split("\n")[-1]
40
- if not any([follow in last_line for follow in self.followups]):
40
+ if not any(follow in last_line for follow in self.followups):
41
41
  if self.finish_string not in last_line:
42
- raise OutputParserException(f"Could not parse output: {text}")
42
+ msg = f"Could not parse output: {text}"
43
+ raise OutputParserException(msg)
43
44
  return AgentFinish({"output": last_line[len(self.finish_string) :]}, text)
44
45
 
45
46
  after_colon = text.split(":")[-1].strip()
@@ -24,7 +24,8 @@ def parse_ai_message_to_tool_action(
24
24
  ) -> Union[list[AgentAction], AgentFinish]:
25
25
  """Parse an AI message potentially containing tool_calls."""
26
26
  if not isinstance(message, AIMessage):
27
- raise TypeError(f"Expected an AI message got {type(message)}")
27
+ msg = f"Expected an AI message got {type(message)}"
28
+ raise TypeError(msg)
28
29
 
29
30
  actions: list = []
30
31
  if message.tool_calls:
@@ -32,7 +33,8 @@ def parse_ai_message_to_tool_action(
32
33
  else:
33
34
  if not message.additional_kwargs.get("tool_calls"):
34
35
  return AgentFinish(
35
- return_values={"output": message.content}, log=str(message.content)
36
+ return_values={"output": message.content},
37
+ log=str(message.content),
36
38
  )
37
39
  # Best-effort parsing
38
40
  tool_calls = []
@@ -42,13 +44,14 @@ def parse_ai_message_to_tool_action(
42
44
  try:
43
45
  args = json.loads(function["arguments"] or "{}")
44
46
  tool_calls.append(
45
- ToolCall(name=function_name, args=args, id=tool_call["id"])
47
+ ToolCall(name=function_name, args=args, id=tool_call["id"]),
46
48
  )
47
- except JSONDecodeError:
48
- raise OutputParserException(
49
+ except JSONDecodeError as e:
50
+ msg = (
49
51
  f"Could not parse tool input: {function} because "
50
52
  f"the `arguments` is not valid JSON."
51
53
  )
54
+ raise OutputParserException(msg) from e
52
55
  for tool_call in tool_calls:
53
56
  # HACK HACK HACK:
54
57
  # The code that encodes tool input into Open AI uses a special variable
@@ -58,10 +61,7 @@ def parse_ai_message_to_tool_action(
58
61
  # Open AI does not support passing in a JSON array as an argument.
59
62
  function_name = tool_call["name"]
60
63
  _tool_input = tool_call["args"]
61
- if "__arg1" in _tool_input:
62
- tool_input = _tool_input["__arg1"]
63
- else:
64
- tool_input = _tool_input
64
+ tool_input = _tool_input.get("__arg1", _tool_input)
65
65
 
66
66
  content_msg = f"responded: {message.content}\n" if message.content else "\n"
67
67
  log = f"\nInvoking: `{function_name}` with `{tool_input}`\n{content_msg}\n"
@@ -72,7 +72,7 @@ def parse_ai_message_to_tool_action(
72
72
  log=log,
73
73
  message_log=[message],
74
74
  tool_call_id=tool_call["id"],
75
- )
75
+ ),
76
76
  )
77
77
  return actions
78
78
 
@@ -91,12 +91,17 @@ class ToolsAgentOutputParser(MultiActionAgentOutputParser):
91
91
  return "tools-agent-output-parser"
92
92
 
93
93
  def parse_result(
94
- self, result: list[Generation], *, partial: bool = False
94
+ self,
95
+ result: list[Generation],
96
+ *,
97
+ partial: bool = False,
95
98
  ) -> Union[list[AgentAction], AgentFinish]:
96
99
  if not isinstance(result[0], ChatGeneration):
97
- raise ValueError("This output parser only works on ChatGeneration output")
100
+ msg = "This output parser only works on ChatGeneration output"
101
+ raise ValueError(msg) # noqa: TRY004
98
102
  message = result[0].message
99
103
  return parse_ai_message_to_tool_action(message)
100
104
 
101
105
  def parse(self, text: str) -> Union[list[AgentAction], AgentFinish]:
102
- raise ValueError("Can only parse messages")
106
+ msg = "Can only parse messages"
107
+ raise ValueError(msg)
@@ -1,48 +1,119 @@
1
- from typing import Union
1
+ import re
2
+ from typing import Literal, Optional, Union
2
3
 
3
4
  from langchain_core.agents import AgentAction, AgentFinish
5
+ from pydantic import Field
4
6
 
5
7
  from langchain.agents import AgentOutputParser
6
8
 
7
9
 
10
+ def _unescape(text: str) -> str:
11
+ """Convert custom tag delimiters back into XML tags."""
12
+ replacements = {
13
+ "[[tool]]": "<tool>",
14
+ "[[/tool]]": "</tool>",
15
+ "[[tool_input]]": "<tool_input>",
16
+ "[[/tool_input]]": "</tool_input>",
17
+ "[[observation]]": "<observation>",
18
+ "[[/observation]]": "</observation>",
19
+ }
20
+ for repl, orig in replacements.items():
21
+ text = text.replace(repl, orig)
22
+ return text
23
+
24
+
8
25
  class XMLAgentOutputParser(AgentOutputParser):
9
- """Parses tool invocations and final answers in XML format.
26
+ """Parses tool invocations and final answers from XML-formatted agent output.
27
+
28
+ This parser extracts structured information from XML tags to determine whether
29
+ an agent should perform a tool action or provide a final answer. It includes
30
+ built-in escaping support to safely handle tool names and inputs
31
+ containing XML special characters.
32
+
33
+ Args:
34
+ escape_format: The escaping format to use when parsing XML content.
35
+ Supports 'minimal' which uses custom delimiters like [[tool]] to replace
36
+ XML tags within content, preventing parsing conflicts.
37
+ Use 'minimal' if using a corresponding encoding format that uses
38
+ the _escape function when formatting the output (e.g., with format_xml).
39
+
40
+ Expected formats:
41
+ Tool invocation (returns AgentAction):
42
+ <tool>search</tool>
43
+ <tool_input>what is 2 + 2</tool_input>
10
44
 
11
- Expects output to be in one of two formats.
45
+ Final answer (returns AgentFinish):
46
+ <final_answer>The answer is 4</final_answer>
12
47
 
13
- If the output signals that an action should be taken,
14
- should be in the below format. This will result in an AgentAction
15
- being returned.
48
+ Note:
49
+ Minimal escaping allows tool names containing XML tags to be safely
50
+ represented. For example, a tool named "search<tool>nested</tool>" would be
51
+ escaped as "search[[tool]]nested[[/tool]]" in the XML and automatically
52
+ unescaped during parsing.
16
53
 
17
- ```
18
- <tool>search</tool>
19
- <tool_input>what is 2 + 2</tool_input>
20
- ```
54
+ Raises:
55
+ ValueError: If the input doesn't match either expected XML format or
56
+ contains malformed XML structure.
57
+ """
58
+
59
+ escape_format: Optional[Literal["minimal"]] = Field(default="minimal")
60
+ """The format to use for escaping XML characters.
21
61
 
22
- If the output signals that a final answer should be given,
23
- should be in the below format. This will result in an AgentFinish
24
- being returned.
62
+ minimal - uses custom delimiters to replace XML tags within content,
63
+ preventing parsing conflicts. This is the only supported format currently.
25
64
 
26
- ```
27
- <final_answer>Foo</final_answer>
28
- ```
65
+ None - no escaping is applied, which may lead to parsing conflicts.
29
66
  """
30
67
 
31
68
  def parse(self, text: str) -> Union[AgentAction, AgentFinish]:
32
- if "</tool>" in text:
33
- tool, tool_input = text.split("</tool>")
34
- _tool = tool.split("<tool>")[1]
35
- _tool_input = tool_input.split("<tool_input>")[1]
36
- if "</tool_input>" in _tool_input:
37
- _tool_input = _tool_input.split("</tool_input>")[0]
69
+ # Check for tool invocation first
70
+ tool_matches = re.findall(r"<tool>(.*?)</tool>", text, re.DOTALL)
71
+ if tool_matches:
72
+ if len(tool_matches) != 1:
73
+ msg = (
74
+ f"Malformed tool invocation: expected exactly one <tool> block, "
75
+ f"but found {len(tool_matches)}."
76
+ )
77
+ raise ValueError(msg)
78
+ _tool = tool_matches[0]
79
+
80
+ # Match optional tool input
81
+ input_matches = re.findall(
82
+ r"<tool_input>(.*?)</tool_input>", text, re.DOTALL
83
+ )
84
+ if len(input_matches) > 1:
85
+ msg = (
86
+ f"Malformed tool invocation: expected at most one <tool_input> "
87
+ f"block, but found {len(input_matches)}."
88
+ )
89
+ raise ValueError(msg)
90
+ _tool_input = input_matches[0] if input_matches else ""
91
+
92
+ # Unescape if minimal escape format is used
93
+ if self.escape_format == "minimal":
94
+ _tool = _unescape(_tool)
95
+ _tool_input = _unescape(_tool_input)
96
+
38
97
  return AgentAction(tool=_tool, tool_input=_tool_input, log=text)
39
- elif "<final_answer>" in text:
40
- _, answer = text.split("<final_answer>")
41
- if "</final_answer>" in answer:
42
- answer = answer.split("</final_answer>")[0]
98
+ # Check for final answer
99
+ if "<final_answer>" in text and "</final_answer>" in text:
100
+ matches = re.findall(r"<final_answer>(.*?)</final_answer>", text, re.DOTALL)
101
+ if len(matches) != 1:
102
+ msg = (
103
+ "Malformed output: expected exactly one "
104
+ "<final_answer>...</final_answer> block."
105
+ )
106
+ raise ValueError(msg)
107
+ answer = matches[0]
108
+ # Unescape custom delimiters in final answer
109
+ if self.escape_format == "minimal":
110
+ answer = _unescape(answer)
43
111
  return AgentFinish(return_values={"output": answer}, log=text)
44
- else:
45
- raise ValueError
112
+ msg = (
113
+ "Malformed output: expected either a tool invocation "
114
+ "or a final answer in XML format."
115
+ )
116
+ raise ValueError(msg)
46
117
 
47
118
  def get_format_instructions(self) -> str:
48
119
  raise NotImplementedError