mirror of
https://github.com/hwchase17/langchain.git
synced 2026-03-18 11:07:36 +00:00
chore(langchain): remove generic from FakeToolCallingModel (#34572)
* Making `FakeToolCallingModel` generic on its `structured_response` doesn't help anywhere in typing. * There are more than 120 references of `FakeToolCallingModel` in the code where you get ` error: Need type annotation for "model" [var-annotated]` because mypy can't resolve the generic type (we don't see them atm because they are in files temporarily excluded from mypy checking). We would need to explicitly type them to `FakeToolCallingModel[Any]` Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
committed by
GitHub
parent
bb5bd1181f
commit
bfe0a26547
@@ -3,9 +3,7 @@ from collections.abc import Callable, Sequence
|
||||
from dataclasses import asdict, is_dataclass
|
||||
from typing import (
|
||||
Any,
|
||||
Generic,
|
||||
Literal,
|
||||
TypeVar,
|
||||
)
|
||||
|
||||
from langchain_core.callbacks import CallbackManagerForLLMRun
|
||||
@@ -19,13 +17,12 @@ from langchain_core.outputs import ChatGeneration, ChatResult
|
||||
from langchain_core.runnables import Runnable
|
||||
from langchain_core.tools import BaseTool
|
||||
from pydantic import BaseModel
|
||||
|
||||
StructuredResponseT = TypeVar("StructuredResponseT")
|
||||
from typing_extensions import override
|
||||
|
||||
|
||||
class FakeToolCallingModel(BaseChatModel, Generic[StructuredResponseT]):
|
||||
tool_calls: list[list[ToolCall]] | list[list[dict]] | None = None
|
||||
structured_response: StructuredResponseT | None = None
|
||||
class FakeToolCallingModel(BaseChatModel):
|
||||
tool_calls: list[list[ToolCall]] | list[list[dict[str, Any]]] | None = None
|
||||
structured_response: Any | None = None
|
||||
index: int = 0
|
||||
tool_style: Literal["openai", "anthropic"] = "openai"
|
||||
|
||||
@@ -52,7 +49,9 @@ class FakeToolCallingModel(BaseChatModel, Generic[StructuredResponseT]):
|
||||
if is_native and not tool_calls:
|
||||
if isinstance(self.structured_response, BaseModel):
|
||||
content_obj = self.structured_response.model_dump()
|
||||
elif is_dataclass(self.structured_response):
|
||||
elif is_dataclass(self.structured_response) and not isinstance(
|
||||
self.structured_response, type
|
||||
):
|
||||
content_obj = asdict(self.structured_response)
|
||||
elif isinstance(self.structured_response, dict):
|
||||
content_obj = self.structured_response
|
||||
@@ -71,11 +70,14 @@ class FakeToolCallingModel(BaseChatModel, Generic[StructuredResponseT]):
|
||||
def _llm_type(self) -> str:
|
||||
return "fake-tool-call-model"
|
||||
|
||||
@override
|
||||
def bind_tools(
|
||||
self,
|
||||
tools: Sequence[dict[str, Any] | type[BaseModel] | Callable | BaseTool],
|
||||
tools: Sequence[dict[str, Any] | type | Callable[..., Any] | BaseTool],
|
||||
*,
|
||||
tool_choice: str | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Runnable[LanguageModelInput, BaseMessage]:
|
||||
) -> Runnable[LanguageModelInput, AIMessage]:
|
||||
if len(tools) == 0:
|
||||
msg = "Must provide at least one tool"
|
||||
raise ValueError(msg)
|
||||
|
||||
@@ -362,7 +362,7 @@
|
||||
# return "The weather is sunny and 75°F."
|
||||
|
||||
# expected_structured_response = WeatherResponse(temperature=75)
|
||||
# model = FakeToolCallingModel[WeatherResponse](
|
||||
# model = FakeToolCallingModel(
|
||||
# tool_calls=tool_calls, structured_response=expected_structured_response
|
||||
# )
|
||||
# agent = create_agent(
|
||||
|
||||
@@ -343,7 +343,7 @@ class TestResponseFormatAsToolStrategy:
|
||||
],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[WeatherBaseModel | LocationResponse](tool_calls=tool_calls)
|
||||
model = FakeToolCallingModel(tool_calls=tool_calls)
|
||||
|
||||
agent = create_agent(
|
||||
model,
|
||||
@@ -655,7 +655,7 @@ class TestResponseFormatAsProviderStrategy:
|
||||
[{"args": {}, "id": "1", "name": "get_weather"}],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[WeatherBaseModel](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls, structured_response=EXPECTED_WEATHER_PYDANTIC
|
||||
)
|
||||
|
||||
@@ -678,7 +678,7 @@ class TestResponseFormatAsProviderStrategy:
|
||||
]
|
||||
|
||||
# But we're using WeatherBaseModel which has different field requirements
|
||||
model = FakeToolCallingModel[dict](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls,
|
||||
structured_response={"invalid": "data"}, # Wrong structure
|
||||
)
|
||||
@@ -699,7 +699,7 @@ class TestResponseFormatAsProviderStrategy:
|
||||
[{"args": {}, "id": "1", "name": "get_weather"}],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[WeatherDataclass](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls, structured_response=EXPECTED_WEATHER_DATACLASS
|
||||
)
|
||||
|
||||
@@ -719,7 +719,7 @@ class TestResponseFormatAsProviderStrategy:
|
||||
[{"args": {}, "id": "1", "name": "get_weather"}],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[WeatherTypedDict](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls, structured_response=EXPECTED_WEATHER_DICT
|
||||
)
|
||||
|
||||
@@ -737,7 +737,7 @@ class TestResponseFormatAsProviderStrategy:
|
||||
[{"args": {}, "id": "1", "name": "get_weather"}],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[dict](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls, structured_response=EXPECTED_WEATHER_DICT
|
||||
)
|
||||
|
||||
@@ -858,7 +858,7 @@ def test_union_of_types() -> None:
|
||||
],
|
||||
]
|
||||
|
||||
model = FakeToolCallingModel[WeatherBaseModel | LocationResponse](
|
||||
model = FakeToolCallingModel(
|
||||
tool_calls=tool_calls, structured_response=EXPECTED_WEATHER_PYDANTIC
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user