Skip to content

Commit

Permalink
Merge branch 'master' into bagatur/tool_description_optional
Browse files Browse the repository at this point in the history
  • Loading branch information
baskaryan authored Oct 31, 2024
2 parents 58e5b7b + 6691202 commit d72cb36
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 191 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ jobs:
packages-dir: ${{ inputs.working-directory }}/dist/
verbose: true
print-hash: true
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
attestations: false

mark-release:
needs:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/_test_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,5 @@ jobs:
# This is *only for CI use* and is *extremely dangerous* otherwise!
# https://github.com/pypa/gh-action-pypi-publish#tolerating-release-package-file-duplicates
skip-existing: true
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
attestations: false
1 change: 1 addition & 0 deletions libs/community/extended_testing_deps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ oracledb>=2.2.0,<3
pandas>=2.0.1,<3
pdfminer-six>=20221105,<20240706
pgvector>=0.1.6,<0.2
playwright>=1.48.0,<2
praw>=7.7.1,<8
premai>=0.3.25,<0.4
psychicapi>=0.8.0,<0.9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
)


class CurrentWebPageToolInput(BaseModel):
"""Explicit no-args input for CurrentWebPageTool."""


class CurrentWebPageTool(BaseBrowserTool): # type: ignore[override, override]
"""Tool for getting the URL of the current webpage."""

name: str = "current_webpage"
description: str = "Returns the URL of the current page"
args_schema: Type[BaseModel] = BaseModel
args_schema: Type[BaseModel] = CurrentWebPageToolInput

def _run(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
)


class ExtractTextToolInput(BaseModel):
"""Explicit no-args input for ExtractTextTool."""


class ExtractTextTool(BaseBrowserTool): # type: ignore[override, override]
"""Tool for extracting all the text on the current webpage."""

name: str = "extract_text"
description: str = "Extract all the text on the current webpage"
args_schema: Type[BaseModel] = BaseModel
args_schema: Type[BaseModel] = ExtractTextToolInput

@model_validator(mode="before")
@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
)


class NavigateBackToolInput(BaseModel):
"""Explicit no-args input for NavigateBackTool."""


class NavigateBackTool(BaseBrowserTool): # type: ignore[override, override]
"""Navigate back to the previous page in the browser history."""

name: str = "previous_webpage"
description: str = "Navigate back to the previous page in the browser history"
args_schema: Type[BaseModel] = BaseModel
args_schema: Type[BaseModel] = NavigateBackToolInput

def _run(self, run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
"""Use the tool."""
Expand Down
Empty file.
26 changes: 26 additions & 0 deletions libs/community/tests/unit_tests/tools/playwright/test_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""Test Playwright's Tools."""

from unittest.mock import Mock

import pytest

from langchain_community.agent_toolkits import PlayWrightBrowserToolkit


@pytest.mark.requires("playwright")
@pytest.mark.requires("bs4")
def test_playwright_tools_schemas() -> None:
"""Test calling 'tool_call_schema' for every tool to check to init issues."""

from playwright.sync_api import Browser

sync_browser = Mock(spec=Browser)
tools = PlayWrightBrowserToolkit.from_browser(sync_browser=sync_browser).get_tools()

for tool in tools:
try:
tool.tool_call_schema
except Exception as e:
raise AssertionError(
f"Error for '{tool.name}' tool: {type(e).__name__}: {e}"
) from e
8 changes: 4 additions & 4 deletions libs/core/langchain_core/tools/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ def args(self) -> dict:
def tool_call_schema(self) -> type[BaseModel]:
full_schema = self.get_input_schema()
fields = []
for name, type_ in _get_all_basemodel_annotations(full_schema).items():
for name, type_ in get_all_basemodel_annotations(full_schema).items():
if not _is_injected_arg_type(type_):
fields.append(name)
return _create_subset_model(
Expand Down Expand Up @@ -962,7 +962,7 @@ def _is_injected_arg_type(type_: type) -> bool:
)


def _get_all_basemodel_annotations(
def get_all_basemodel_annotations(
cls: Union[TypeBaseModel, Any], *, default_to_bound: bool = True
) -> dict[str, type]:
# cls has no subscript: cls = FooBar
Expand All @@ -980,7 +980,7 @@ def _get_all_basemodel_annotations(
orig_bases: tuple = getattr(cls, "__orig_bases__", ())
# cls has subscript: cls = FooBar[int]
else:
annotations = _get_all_basemodel_annotations(
annotations = get_all_basemodel_annotations(
get_origin(cls), default_to_bound=False
)
orig_bases = (cls,)
Expand All @@ -994,7 +994,7 @@ def _get_all_basemodel_annotations(
# if class = FooBar inherits from Baz, parent = Baz
if isinstance(parent, type) and is_pydantic_v1_subclass(parent):
annotations.update(
_get_all_basemodel_annotations(parent, default_to_bound=False)
get_all_basemodel_annotations(parent, default_to_bound=False)
)
continue

Expand Down
8 changes: 1 addition & 7 deletions libs/core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "langchain-core"
version = "0.3.13"
version = "0.3.14"
description = "Building applications with LLMs through composability"
authors = []
license = "MIT"
Expand Down Expand Up @@ -84,20 +84,17 @@ classmethod-decorators = [ "classmethod", "langchain_core.utils.pydantic.pre_ini
[tool.poetry.group.lint.dependencies]
ruff = "^0.5"


[tool.poetry.group.typing.dependencies]
mypy = ">=1.10,<1.11"
types-pyyaml = "^6.0.12.2"
types-requests = "^2.28.11.5"
types-jinja2 = "^2.11.9"


[tool.poetry.group.dev.dependencies]
jupyter = "^1.0.0"
setuptools = "^67.6.1"
grandalf = "^0.8"


[tool.poetry.group.test.dependencies]
pytest = "^8"
freezegun = "^1.2.2"
Expand All @@ -116,15 +113,12 @@ python = "<3.12"
version = "^1.26.0"
python = ">=3.12"


[tool.poetry.group.test_integration.dependencies]


[tool.poetry.group.typing.dependencies.langchain-text-splitters]
path = "../text-splitters"
develop = true


[tool.poetry.group.test.dependencies.langchain-standard-tests]
path = "../standard-tests"
develop = true
7 changes: 7 additions & 0 deletions libs/core/tests/unit_tests/runnables/test_runnable.py
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,13 @@ async def test_prompt_with_chat_model_async(
)


@pytest.mark.skipif(
condition=sys.version_info[1] == 13,
reason=(
"temporary, py3.13 exposes some invalid assumptions about order of batch async "
"executions."
),
)
@freeze_time("2023-01-01")
async def test_prompt_with_llm(
mocker: MockerFixture, snapshot: SnapshotAssertion
Expand Down
26 changes: 13 additions & 13 deletions libs/core/tests/unit_tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
from langchain_core.tools.base import (
InjectedToolArg,
SchemaAnnotationError,
_get_all_basemodel_annotations,
_is_message_content_block,
_is_message_content_type,
get_all_basemodel_annotations,
)
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_core.utils.pydantic import PYDANTIC_MAJOR_VERSION, _create_subset_model
Expand Down Expand Up @@ -1912,19 +1912,19 @@ class ModelC(Mixin, ModelB):
c: dict

expected = {"a": str, "b": Annotated[ModelA[dict[str, Any]], "foo"], "c": dict}
actual = _get_all_basemodel_annotations(ModelC)
actual = get_all_basemodel_annotations(ModelC)
assert actual == expected

expected = {"a": str, "b": Annotated[ModelA[dict[str, Any]], "foo"]}
actual = _get_all_basemodel_annotations(ModelB)
actual = get_all_basemodel_annotations(ModelB)
assert actual == expected

expected = {"a": Any}
actual = _get_all_basemodel_annotations(ModelA)
actual = get_all_basemodel_annotations(ModelA)
assert actual == expected

expected = {"a": int}
actual = _get_all_basemodel_annotations(ModelA[int])
actual = get_all_basemodel_annotations(ModelA[int])
assert actual == expected

D = TypeVar("D", bound=Union[str, int])
Expand All @@ -1938,7 +1938,7 @@ class ModelD(ModelC, Generic[D]):
"c": dict,
"d": Union[str, int, None],
}
actual = _get_all_basemodel_annotations(ModelD)
actual = get_all_basemodel_annotations(ModelD)
assert actual == expected

expected = {
Expand All @@ -1947,7 +1947,7 @@ class ModelD(ModelC, Generic[D]):
"c": dict,
"d": Union[int, None],
}
actual = _get_all_basemodel_annotations(ModelD[int])
actual = get_all_basemodel_annotations(ModelD[int])
assert actual == expected


Expand All @@ -1969,19 +1969,19 @@ class ModelC(Mixin, ModelB):
c: dict

expected = {"a": str, "b": Annotated[ModelA[dict[str, Any]], "foo"], "c": dict}
actual = _get_all_basemodel_annotations(ModelC)
actual = get_all_basemodel_annotations(ModelC)
assert actual == expected

expected = {"a": str, "b": Annotated[ModelA[dict[str, Any]], "foo"]}
actual = _get_all_basemodel_annotations(ModelB)
actual = get_all_basemodel_annotations(ModelB)
assert actual == expected

expected = {"a": Any}
actual = _get_all_basemodel_annotations(ModelA)
actual = get_all_basemodel_annotations(ModelA)
assert actual == expected

expected = {"a": int}
actual = _get_all_basemodel_annotations(ModelA[int])
actual = get_all_basemodel_annotations(ModelA[int])
assert actual == expected

D = TypeVar("D", bound=Union[str, int])
Expand All @@ -1995,7 +1995,7 @@ class ModelD(ModelC, Generic[D]):
"c": dict,
"d": Union[str, int, None],
}
actual = _get_all_basemodel_annotations(ModelD)
actual = get_all_basemodel_annotations(ModelD)
assert actual == expected

expected = {
Expand All @@ -2004,7 +2004,7 @@ class ModelD(ModelC, Generic[D]):
"c": dict,
"d": Union[int, None],
}
actual = _get_all_basemodel_annotations(ModelD[int])
actual = get_all_basemodel_annotations(ModelD[int])
assert actual == expected


Expand Down
Loading

0 comments on commit d72cb36

Please sign in to comment.