mirror of
https://github.com/hwchase17/langchain.git
synced 2026-04-16 18:02:57 +00:00
Compare commits
9 Commits
langchain-
...
jacob/trac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03241dc80c | ||
|
|
9c4de86bca | ||
|
|
92a6e57d60 | ||
|
|
1749eb8601 | ||
|
|
58c4e5bbdd | ||
|
|
c289bf10e9 | ||
|
|
bc0e99d045 | ||
|
|
91b1ef049c | ||
|
|
c993ba06bb |
@@ -2,6 +2,7 @@ import re
|
||||
from collections.abc import Sequence
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Literal,
|
||||
TypedDict,
|
||||
TypeVar,
|
||||
@@ -14,6 +15,21 @@ from langchain_core.messages.content import (
|
||||
)
|
||||
|
||||
|
||||
def _filter_invocation_params_for_tracing(params: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Filter out large/inappropriate fields from invocation params for tracing.
|
||||
|
||||
Removes fields like tools, functions, messages, response_format that can be large.
|
||||
|
||||
Args:
|
||||
params: The invocation parameters to filter.
|
||||
|
||||
Returns:
|
||||
The filtered parameters with large fields removed.
|
||||
"""
|
||||
excluded_keys = {"tools", "functions", "messages", "response_format"}
|
||||
return {k: v for k, v in params.items() if k not in excluded_keys}
|
||||
|
||||
|
||||
def is_openai_data_block(
|
||||
block: dict, filter_: Literal["image", "audio", "file"] | None = None
|
||||
) -> bool:
|
||||
|
||||
@@ -25,6 +25,7 @@ from langchain_core.callbacks import (
|
||||
)
|
||||
from langchain_core.globals import get_llm_cache
|
||||
from langchain_core.language_models._utils import (
|
||||
_filter_invocation_params_for_tracing,
|
||||
_normalize_messages,
|
||||
_update_message_content_to_blocks,
|
||||
)
|
||||
@@ -567,6 +568,9 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
(run_manager,) = callback_manager.on_chat_model_start(
|
||||
self._serialized,
|
||||
@@ -695,6 +699,9 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
(run_manager,) = await callback_manager.on_chat_model_start(
|
||||
self._serialized,
|
||||
@@ -972,6 +979,9 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
messages_to_trace = [
|
||||
_format_for_tracing(message_list) for message_list in messages
|
||||
@@ -1095,6 +1105,9 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
|
||||
messages_to_trace = [
|
||||
|
||||
@@ -42,6 +42,7 @@ from langchain_core.callbacks import (
|
||||
Callbacks,
|
||||
)
|
||||
from langchain_core.globals import get_llm_cache
|
||||
from langchain_core.language_models._utils import _filter_invocation_params_for_tracing
|
||||
from langchain_core.language_models.base import (
|
||||
BaseLanguageModel,
|
||||
LangSmithParams,
|
||||
@@ -537,6 +538,9 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
(run_manager,) = callback_manager.on_llm_start(
|
||||
self._serialized,
|
||||
@@ -607,6 +611,9 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
inheritable_metadata,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
(run_manager,) = await callback_manager.on_llm_start(
|
||||
self._serialized,
|
||||
@@ -950,6 +957,8 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
run_name_list = run_name or cast(
|
||||
"list[str | None]", ([None] * len(prompts))
|
||||
)
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
callback_managers = [
|
||||
CallbackManager.configure(
|
||||
callback,
|
||||
@@ -959,6 +968,9 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
meta,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
for callback, tag, meta in zip(
|
||||
callbacks, tags_list, metadata_list, strict=False
|
||||
@@ -966,6 +978,8 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
]
|
||||
else:
|
||||
# We've received a single callbacks arg to apply to all inputs
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
callback_managers = [
|
||||
CallbackManager.configure(
|
||||
cast("Callbacks", callbacks),
|
||||
@@ -975,12 +989,13 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
cast("dict[str, Any]", metadata),
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
] * len(prompts)
|
||||
run_name_list = [cast("str | None", run_name)] * len(prompts)
|
||||
run_ids_list = self._get_run_ids_list(run_id, prompts)
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
options = {"stop": stop}
|
||||
(
|
||||
existing_prompts,
|
||||
@@ -1214,6 +1229,8 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
run_name_list = run_name or cast(
|
||||
"list[str | None]", ([None] * len(prompts))
|
||||
)
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
callback_managers = [
|
||||
AsyncCallbackManager.configure(
|
||||
callback,
|
||||
@@ -1223,6 +1240,9 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
meta,
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
for callback, tag, meta in zip(
|
||||
callbacks, tags_list, metadata_list, strict=False
|
||||
@@ -1230,6 +1250,8 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
]
|
||||
else:
|
||||
# We've received a single callbacks arg to apply to all inputs
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
callback_managers = [
|
||||
AsyncCallbackManager.configure(
|
||||
cast("Callbacks", callbacks),
|
||||
@@ -1239,12 +1261,13 @@ class BaseLLM(BaseLanguageModel[str], ABC):
|
||||
self.tags,
|
||||
cast("dict[str, Any]", metadata),
|
||||
self.metadata,
|
||||
langsmith_inheritable_metadata=_filter_invocation_params_for_tracing(
|
||||
params
|
||||
),
|
||||
)
|
||||
] * len(prompts)
|
||||
run_name_list = [cast("str | None", run_name)] * len(prompts)
|
||||
run_ids_list = self._get_run_ids_list(run_id, prompts)
|
||||
params = self.dict()
|
||||
params["stop"] = stop
|
||||
options = {"stop": stop}
|
||||
(
|
||||
existing_prompts,
|
||||
|
||||
@@ -17,8 +17,14 @@ from langchain_core.language_models import (
|
||||
FakeListChatModel,
|
||||
ParrotFakeChatModel,
|
||||
)
|
||||
from langchain_core.language_models._utils import _normalize_messages
|
||||
from langchain_core.language_models.chat_models import _generate_response_from_error
|
||||
from langchain_core.language_models._utils import (
|
||||
_filter_invocation_params_for_tracing,
|
||||
_normalize_messages,
|
||||
)
|
||||
from langchain_core.language_models.chat_models import (
|
||||
SimpleChatModel,
|
||||
_generate_response_from_error,
|
||||
)
|
||||
from langchain_core.language_models.fake_chat_models import (
|
||||
FakeListChatModelError,
|
||||
GenericFakeChatModel,
|
||||
@@ -1390,3 +1396,86 @@ def test_generate_response_from_error_handles_streaming_response_failure() -> No
|
||||
assert metadata["body"] is None
|
||||
assert metadata["headers"] == {"content-type": "application/json"}
|
||||
assert metadata["status_code"] == 400
|
||||
|
||||
|
||||
def test_filter_invocation_params_for_tracing() -> None:
|
||||
"""Test that large fields are filtered from invocation params for tracing."""
|
||||
params = {
|
||||
"temperature": 0.7,
|
||||
"tools": [{"name": "test_tool"}],
|
||||
"functions": [{"name": "test_function"}],
|
||||
"messages": [{"role": "system", "content": "test"}],
|
||||
"response_format": {"type": "json_object"},
|
||||
}
|
||||
filtered = _filter_invocation_params_for_tracing(params)
|
||||
|
||||
# Should include temperature
|
||||
assert "temperature" in filtered
|
||||
assert filtered["temperature"] == 0.7
|
||||
|
||||
# Should exclude these large fields
|
||||
assert "tools" not in filtered
|
||||
assert "functions" not in filtered
|
||||
assert "messages" not in filtered
|
||||
assert "response_format" not in filtered
|
||||
|
||||
|
||||
class FakeChatModelWithInvocationParams(SimpleChatModel):
|
||||
"""Fake chat model with invocation params for testing tracing."""
|
||||
|
||||
temperature: float = 0.7
|
||||
|
||||
@property
|
||||
@override
|
||||
def _llm_type(self) -> str:
|
||||
return "fake-chat-model-with-invocation-params"
|
||||
|
||||
@property
|
||||
@override
|
||||
def _identifying_params(self) -> dict[str, Any]:
|
||||
return {
|
||||
"temperature": self.temperature,
|
||||
"tools": [{"name": "test_tool"}],
|
||||
"functions": [{"name": "test_function"}],
|
||||
"messages": [{"role": "system", "content": "test"}],
|
||||
"response_format": {"type": "json_object"},
|
||||
}
|
||||
|
||||
@override
|
||||
def _call(
|
||||
self,
|
||||
messages: list[BaseMessage],
|
||||
stop: list[str] | None = None,
|
||||
run_manager: CallbackManagerForLLMRun | None = None,
|
||||
**kwargs: Any,
|
||||
) -> str:
|
||||
return "test response"
|
||||
|
||||
|
||||
def test_invocation_params_passed_to_tracer_metadata() -> None:
|
||||
"""Test that invocation params are passed to tracer metadata."""
|
||||
llm = FakeChatModelWithInvocationParams()
|
||||
with collect_runs() as cb:
|
||||
llm.invoke([HumanMessage(content="Hello")], config={"callbacks": [cb]})
|
||||
assert len(cb.traced_runs) == 1
|
||||
run = cb.traced_runs[0]
|
||||
# The invocation params should be in the run's extra
|
||||
assert run.extra == {
|
||||
"batch_size": 1,
|
||||
"invocation_params": {
|
||||
"_type": "fake-chat-model-with-invocation-params",
|
||||
"functions": [{"name": "test_function"}],
|
||||
"messages": [{"content": "test", "role": "system"}],
|
||||
"response_format": {"type": "json_object"},
|
||||
"stop": None,
|
||||
"temperature": 0.7,
|
||||
"tools": [{"name": "test_tool"}],
|
||||
},
|
||||
"metadata": {
|
||||
"ls_integration": "langchain_chat_model",
|
||||
"ls_model_type": "chat",
|
||||
"ls_provider": "fakechatmodelwithinvocationparams",
|
||||
"ls_temperature": 0.7,
|
||||
},
|
||||
"options": {"stop": None},
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ from langchain_core.language_models import (
|
||||
BaseLLM,
|
||||
FakeListLLM,
|
||||
)
|
||||
from langchain_core.language_models._utils import _filter_invocation_params_for_tracing
|
||||
from langchain_core.outputs import Generation, GenerationChunk, LLMResult
|
||||
from langchain_core.tracers.context import collect_runs
|
||||
from tests.unit_tests.fake.callbacks import (
|
||||
@@ -284,3 +285,94 @@ def test_get_ls_params() -> None:
|
||||
|
||||
ls_params = llm._get_ls_params(stop=["stop"])
|
||||
assert ls_params["ls_stop"] == ["stop"]
|
||||
|
||||
|
||||
def test_filter_invocation_params_for_tracing() -> None:
|
||||
"""Test that large fields are filtered from invocation params for tracing."""
|
||||
params = {
|
||||
"temperature": 0.7,
|
||||
"tools": [{"name": "test_tool"}],
|
||||
"functions": [{"name": "test_function"}],
|
||||
"messages": [{"role": "system", "content": "test"}],
|
||||
"response_format": {"type": "json_object"},
|
||||
}
|
||||
filtered = _filter_invocation_params_for_tracing(params)
|
||||
|
||||
# Should include temperature
|
||||
assert "temperature" in filtered
|
||||
assert filtered["temperature"] == 0.7
|
||||
|
||||
# Should exclude these large fields
|
||||
assert "tools" not in filtered
|
||||
assert "functions" not in filtered
|
||||
assert "messages" not in filtered
|
||||
assert "response_format" not in filtered
|
||||
|
||||
|
||||
class FakeLLMWithInvocationParams(BaseLLM):
|
||||
"""Fake LLM with invocation params for testing tracing."""
|
||||
|
||||
temperature: float = 0.7
|
||||
|
||||
@property
|
||||
@override
|
||||
def _llm_type(self) -> str:
|
||||
return "fake-llm-with-invocation-params"
|
||||
|
||||
@property
|
||||
@override
|
||||
def _identifying_params(self) -> dict[str, Any]:
|
||||
return {
|
||||
"temperature": self.temperature,
|
||||
"tools": [{"name": "test_tool"}],
|
||||
"functions": [{"name": "test_function"}],
|
||||
"messages": [{"role": "system", "content": "test"}],
|
||||
"response_format": {"type": "json_object"},
|
||||
}
|
||||
|
||||
@override
|
||||
def _generate(
|
||||
self,
|
||||
prompts: list[str],
|
||||
stop: list[str] | None = None,
|
||||
run_manager: CallbackManagerForLLMRun | None = None,
|
||||
**kwargs: Any,
|
||||
) -> LLMResult:
|
||||
generations = [[Generation(text="test response")]]
|
||||
return LLMResult(generations=generations)
|
||||
|
||||
@override
|
||||
async def _agenerate(
|
||||
self,
|
||||
prompts: list[str],
|
||||
stop: list[str] | None = None,
|
||||
run_manager: AsyncCallbackManagerForLLMRun | None = None,
|
||||
**kwargs: Any,
|
||||
) -> LLMResult:
|
||||
generations = [[Generation(text="test response")]]
|
||||
return LLMResult(generations=generations)
|
||||
|
||||
|
||||
async def test_llm_invocation_params_filtered_in_stream() -> None:
|
||||
"""Test that invocation params are filtered when streaming."""
|
||||
|
||||
# Create a custom LLM that supports streaming
|
||||
class FakeStreamingLLM(FakeLLMWithInvocationParams):
|
||||
@override
|
||||
def _stream(
|
||||
self,
|
||||
prompt: str,
|
||||
stop: list[str] | None = None,
|
||||
run_manager: CallbackManagerForLLMRun | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Iterator[GenerationChunk]:
|
||||
yield GenerationChunk(text="test ")
|
||||
|
||||
streaming_llm = FakeStreamingLLM()
|
||||
|
||||
with collect_runs() as cb:
|
||||
list(streaming_llm.stream("Hello", config={"callbacks": [cb]}))
|
||||
assert len(cb.traced_runs) == 1
|
||||
run = cb.traced_runs[0]
|
||||
# Verify the run was traced
|
||||
assert run.extra is not None
|
||||
|
||||
@@ -83,6 +83,14 @@ def _openapi_params_to_json_schema(params: list[Parameter], spec: OpenAPISpec) -
|
||||
return {"type": "object", "properties": properties, "required": required}
|
||||
|
||||
|
||||
@deprecated(
|
||||
since="1.0.4",
|
||||
message=(
|
||||
"This function is deprecated and will be removed in a future version. "
|
||||
"Use LLM tool calling features directly with an HTTP client instead."
|
||||
),
|
||||
removal="2.0",
|
||||
)
|
||||
def openapi_spec_to_openai_fn(
|
||||
spec: OpenAPISpec,
|
||||
) -> tuple[list[dict[str, Any]], Callable]:
|
||||
@@ -198,6 +206,14 @@ def openapi_spec_to_openai_fn(
|
||||
return functions, default_call_api
|
||||
|
||||
|
||||
@deprecated(
|
||||
since="1.0.4",
|
||||
message=(
|
||||
"This class is deprecated and will be removed in a future version. "
|
||||
"Use LLM tool calling features directly with an HTTP client instead."
|
||||
),
|
||||
removal="2.0",
|
||||
)
|
||||
class SimpleRequestChain(Chain):
|
||||
"""Chain for making a simple request to an API endpoint."""
|
||||
|
||||
@@ -252,11 +268,10 @@ class SimpleRequestChain(Chain):
|
||||
@deprecated(
|
||||
since="0.2.13",
|
||||
message=(
|
||||
"This function is deprecated and will be removed in langchain 1.0. "
|
||||
"See API reference for replacement: "
|
||||
"https://api.python.langchain.com/en/latest/chains/langchain.chains.openai_functions.openapi.get_openapi_chain.html"
|
||||
"This function is deprecated and will be removed in a future version. "
|
||||
"Use LLM tool calling features directly with an HTTP client instead."
|
||||
),
|
||||
removal="1.0",
|
||||
removal="2.0",
|
||||
)
|
||||
def get_openapi_chain(
|
||||
spec: OpenAPISpec | str,
|
||||
@@ -271,82 +286,9 @@ def get_openapi_chain(
|
||||
) -> SequentialChain:
|
||||
r"""Create a chain for querying an API from a OpenAPI spec.
|
||||
|
||||
Note: this class is deprecated. See below for a replacement implementation.
|
||||
The benefits of this implementation are:
|
||||
|
||||
- Uses LLM tool calling features to encourage properly-formatted API requests;
|
||||
- Includes async support.
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
from langchain_classic.chains.openai_functions.openapi import openapi_spec_to_openai_fn
|
||||
from langchain_community.utilities.openapi import OpenAPISpec
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
# Define API spec. Can be JSON or YAML
|
||||
api_spec = \"\"\"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "JSONPlaceholder API",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://jsonplaceholder.typicode.com"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/posts": {
|
||||
"get": {
|
||||
"summary": "Get posts",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "_limit",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"example": 2
|
||||
},
|
||||
"description": "Limit the number of results"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\"\"\"
|
||||
|
||||
parsed_spec = OpenAPISpec.from_text(api_spec)
|
||||
openai_fns, call_api_fn = openapi_spec_to_openai_fn(parsed_spec)
|
||||
tools = [
|
||||
{"type": "function", "function": fn}
|
||||
for fn in openai_fns
|
||||
]
|
||||
|
||||
prompt = ChatPromptTemplate.from_template(
|
||||
"Use the provided APIs to respond to this user query:\\n\\n{query}"
|
||||
)
|
||||
model = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind_tools(tools)
|
||||
|
||||
def _execute_tool(message) -> Any:
|
||||
if tool_calls := message.tool_calls:
|
||||
tool_call = message.tool_calls[0]
|
||||
response = call_api_fn(name=tool_call["name"], fn_args=tool_call["args"])
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
else:
|
||||
return message.content
|
||||
|
||||
chain = prompt | model | _execute_tool
|
||||
```
|
||||
|
||||
```python
|
||||
response = chain.invoke({"query": "Get me top two posts."})
|
||||
```
|
||||
!!! warning "Deprecated"
|
||||
This function and all related utilities in this module are deprecated.
|
||||
Use LLM tool calling features directly with an HTTP client instead.
|
||||
|
||||
Args:
|
||||
spec: OpenAPISpec or url/file/text string corresponding to one.
|
||||
@@ -360,7 +302,7 @@ def get_openapi_chain(
|
||||
llm_chain_kwargs: LLM chain additional keyword arguments.
|
||||
**kwargs: Additional keyword arguments to pass to the chain.
|
||||
|
||||
""" # noqa: E501
|
||||
"""
|
||||
try:
|
||||
from langchain_community.utilities.openapi import OpenAPISpec
|
||||
except ImportError as e:
|
||||
|
||||
@@ -20,11 +20,11 @@ classifiers = [
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
requires-python = ">=3.10.0,<4.0.0"
|
||||
dependencies = [
|
||||
"langchain-core>=1.2.19,<2.0.0",
|
||||
"langchain-text-splitters>=1.1.1,<2.0.0",
|
||||
"langchain-core>=1.2.31,<2.0.0",
|
||||
"langchain-text-splitters>=1.1.2,<2.0.0",
|
||||
"langsmith>=0.1.17,<1.0.0",
|
||||
"pydantic>=2.7.4,<3.0.0",
|
||||
"SQLAlchemy>=1.4.0,<3.0.0",
|
||||
|
||||
8
libs/langchain/uv.lock
generated
8
libs/langchain/uv.lock
generated
@@ -1,5 +1,5 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
revision = 2
|
||||
requires-python = ">=3.10.0, <4.0.0"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.14' and platform_python_implementation == 'PyPy'",
|
||||
@@ -2391,7 +2391,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-classic"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "async-timeout", marker = "python_full_version < '3.11'" },
|
||||
@@ -2784,7 +2784,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-openai"
|
||||
version = "1.1.13"
|
||||
version = "1.1.14"
|
||||
source = { editable = "../partners/openai" }
|
||||
dependencies = [
|
||||
{ name = "langchain-core" },
|
||||
@@ -2891,7 +2891,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-text-splitters"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = { editable = "../text-splitters" }
|
||||
dependencies = [
|
||||
{ name = "langchain-core" },
|
||||
|
||||
@@ -15,8 +15,7 @@ from typing import (
|
||||
cast,
|
||||
)
|
||||
|
||||
import requests
|
||||
from langchain_core._api import beta
|
||||
from langchain_core._api import beta, deprecated
|
||||
from langchain_core.documents import BaseDocumentTransformer, Document
|
||||
from typing_extensions import override
|
||||
|
||||
@@ -186,8 +185,19 @@ class HTMLHeaderTextSplitter:
|
||||
"""
|
||||
return self.split_text_from_file(StringIO(text))
|
||||
|
||||
@deprecated(
|
||||
since="1.1.2",
|
||||
removal="2.0.0",
|
||||
message=(
|
||||
"Please fetch the HTML content from the URL yourself and pass it "
|
||||
"to split_text."
|
||||
),
|
||||
)
|
||||
def split_text_from_url(
|
||||
self, url: str, timeout: int = 10, **kwargs: Any
|
||||
self,
|
||||
url: str,
|
||||
timeout: int = 10,
|
||||
**kwargs: Any, # noqa: ARG002
|
||||
) -> list[Document]:
|
||||
"""Fetch text content from a URL and split it into documents.
|
||||
|
||||
@@ -205,14 +215,14 @@ class HTMLHeaderTextSplitter:
|
||||
Raises:
|
||||
requests.RequestException: If the HTTP request fails.
|
||||
"""
|
||||
from langchain_core._security._ssrf_protection import ( # noqa: PLC0415
|
||||
validate_safe_url,
|
||||
from langchain_core._security._transport import ( # noqa: PLC0415
|
||||
ssrf_safe_client,
|
||||
)
|
||||
|
||||
validate_safe_url(url, allow_private=False, allow_http=True)
|
||||
response = requests.get(url, timeout=timeout, **kwargs)
|
||||
response.raise_for_status()
|
||||
return self.split_text(response.text)
|
||||
with ssrf_safe_client() as client:
|
||||
response = client.get(url, timeout=timeout)
|
||||
response.raise_for_status()
|
||||
return self.split_text(response.text)
|
||||
|
||||
def split_text_from_file(self, file: str | IO[str]) -> list[Document]:
|
||||
"""Split HTML content from a file into a list of `Document` objects.
|
||||
|
||||
@@ -22,10 +22,10 @@ classifiers = [
|
||||
"Topic :: Text Processing",
|
||||
]
|
||||
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
requires-python = ">=3.10.0,<4.0.0"
|
||||
dependencies = [
|
||||
"langchain-core>=1.2.13,<2.0.0",
|
||||
"langchain-core>=1.2.31,<2.0.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
||||
4
libs/text-splitters/uv.lock
generated
4
libs/text-splitters/uv.lock
generated
@@ -1,5 +1,5 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
revision = 2
|
||||
requires-python = ">=3.10.0, <4.0.0"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.14'",
|
||||
@@ -1246,7 +1246,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-text-splitters"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "langchain-core" },
|
||||
|
||||
Reference in New Issue
Block a user