diff --git a/libs/community/langchain_community/chat_models/openai.py b/libs/community/langchain_community/chat_models/openai.py index 8c81d941c..945c9be6b 100644 --- a/libs/community/langchain_community/chat_models/openai.py +++ b/libs/community/langchain_community/chat_models/openai.py @@ -226,6 +226,17 @@ def is_lc_serializable(cls) -> bool: """Return whether this model can be serialized by Langchain.""" return True + def __repr__(self) -> str: + """Mask API key in repr to prevent secret leakage.""" + attrs = { + "model_name": self.model_name, + "temperature": self.temperature, + "openai_api_key": "***" if self.openai_api_key else None, + "openai_proxy": self.openai_proxy, + } + filtered = ", ".join(f"{k}={v!r}" for k, v in attrs.items() if v is not None) + return f"ChatOpenAI({filtered})" + client: Any = Field(default=None, exclude=True) async_client: Any = Field(default=None, exclude=True) model_name: str = Field(default="gpt-3.5-turbo", alias="model") diff --git a/libs/community/langchain_community/document_loaders/csv_loader.py b/libs/community/langchain_community/document_loaders/csv_loader.py index 8f2351602..d58b8c528 100644 --- a/libs/community/langchain_community/document_loaders/csv_loader.py +++ b/libs/community/langchain_community/document_loaders/csv_loader.py @@ -223,4 +223,7 @@ def __init__( def _get_elements(self) -> List: from unstructured.partition.csv import partition_csv - return partition_csv(filename=self.file_path, **self.unstructured_kwargs) + input_encoding = self.unstructured_kwargs.get("encoding") + return partition_csv( + filename=self.file_path, encoding=input_encoding, **self.unstructured_kwargs + ) diff --git a/libs/community/langchain_community/tools/file_management/copy.py b/libs/community/langchain_community/tools/file_management/copy.py index 7679e3c43..d8f1dd578 100644 --- a/libs/community/langchain_community/tools/file_management/copy.py +++ b/libs/community/langchain_community/tools/file_management/copy.py @@ -1,7 +1,10 @@ import shutil from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -50,4 +53,30 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + source_path: str, + destination_path: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + source_path_ = self.get_relative_path(source_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format( + arg_name="source_path", value=source_path + ) + try: + destination_path_ = self.get_relative_path(destination_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format( + arg_name="destination_path", value=destination_path + ) + try: + import asyncio + + await asyncio.to_thread( + shutil.copy2, source_path_, destination_path_, follow_symlinks=False + ) + return f"File copied successfully from {source_path} to {destination_path}." + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/delete.py b/libs/community/langchain_community/tools/file_management/delete.py index 33f4b70b2..ae136a306 100644 --- a/libs/community/langchain_community/tools/file_management/delete.py +++ b/libs/community/langchain_community/tools/file_management/delete.py @@ -1,7 +1,10 @@ import os from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -42,4 +45,21 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + file_path: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + file_path_ = self.get_relative_path(file_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path) + if not file_path_.exists(): + return f"Error: no such file or directory: {file_path}" + try: + import asyncio + + await asyncio.to_thread(os.remove, file_path_) + return f"File deleted successfully: {file_path}." + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/file_search.py b/libs/community/langchain_community/tools/file_management/file_search.py index a00aee40b..efc58383a 100644 --- a/libs/community/langchain_community/tools/file_management/file_search.py +++ b/libs/community/langchain_community/tools/file_management/file_search.py @@ -2,7 +2,10 @@ import os from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -59,4 +62,33 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + pattern: str, + dir_path: str = ".", + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + dir_path_ = self.get_relative_path(dir_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format(arg_name="dir_path", value=dir_path) + matches = [] + try: + import asyncio + + def _walk() -> list[str]: + result = [] + for root, _, filenames in os.walk(dir_path_): + for filename in fnmatch.filter(filenames, pattern): + absolute_path = os.path.join(root, filename) + relative_path = os.path.relpath(absolute_path, dir_path_) + result.append(relative_path) + return result + + matches = await asyncio.to_thread(_walk) + if matches: + return "\n".join(matches) + else: + return f"No files found for pattern {pattern} in directory {dir_path}" + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/list_dir.py b/libs/community/langchain_community/tools/file_management/list_dir.py index a8bfdc8e3..9c4f3f1d1 100644 --- a/libs/community/langchain_community/tools/file_management/list_dir.py +++ b/libs/community/langchain_community/tools/file_management/list_dir.py @@ -1,7 +1,10 @@ import os from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -43,4 +46,22 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + dir_path: str = ".", + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + dir_path_ = self.get_relative_path(dir_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format(arg_name="dir_path", value=dir_path) + try: + import asyncio + + entries = await asyncio.to_thread(os.listdir, dir_path_) + if entries: + return "\n".join(entries) + else: + return f"No files found in directory {dir_path}" + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/move.py b/libs/community/langchain_community/tools/file_management/move.py index 935625172..fa1f7f98f 100644 --- a/libs/community/langchain_community/tools/file_management/move.py +++ b/libs/community/langchain_community/tools/file_management/move.py @@ -1,7 +1,10 @@ import shutil from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -53,4 +56,30 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + source_path: str, + destination_path: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + source_path_ = self.get_relative_path(source_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format( + arg_name="source_path", value=source_path + ) + try: + destination_path_ = self.get_relative_path(destination_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format( + arg_name="destination_path_", value=destination_path_ + ) + if not source_path_.exists(): + return f"Error: no such file or directory {source_path}" + try: + import asyncio + + await asyncio.to_thread(shutil.move, str(source_path_), destination_path_) + return f"File moved successfully from {source_path} to {destination_path}." + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/read.py b/libs/community/langchain_community/tools/file_management/read.py index 9f746ed16..801cf4e1d 100644 --- a/libs/community/langchain_community/tools/file_management/read.py +++ b/libs/community/langchain_community/tools/file_management/read.py @@ -1,6 +1,9 @@ from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -42,4 +45,22 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + file_path: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + read_path = self.get_relative_path(file_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path) + if not read_path.exists(): + return f"Error: no such file or directory: {file_path}" + try: + import aiofiles + + async with aiofiles.open(read_path, "r", encoding="utf-8") as f: + content = await f.read() + return content + except Exception as e: + return "Error: " + str(e) diff --git a/libs/community/langchain_community/tools/file_management/write.py b/libs/community/langchain_community/tools/file_management/write.py index 218f0169d..ccdbef8c5 100644 --- a/libs/community/langchain_community/tools/file_management/write.py +++ b/libs/community/langchain_community/tools/file_management/write.py @@ -1,6 +1,9 @@ from typing import Optional, Type -from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) from langchain_core.tools import BaseTool from pydantic import BaseModel, Field @@ -48,4 +51,24 @@ def _run( except Exception as e: return "Error: " + str(e) - # TODO: Add aiofiles method + async def _arun( + self, + file_path: str, + text: str, + append: bool = False, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + try: + write_path = self.get_relative_path(file_path) + except FileValidationError: + return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path) + try: + import aiofiles + + write_path.parent.mkdir(exist_ok=True, parents=True) + mode = "a" if append else "w" + async with aiofiles.open(write_path, mode, encoding="utf-8") as f: + await f.write(text) + return f"File written successfully to {file_path}." + except Exception as e: + return "Error: " + str(e)