Skip to content

Commit

Permalink
Merge branch 'langchain-ai:master' into openllm-async-client-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
charlod committed Apr 4, 2024
2 parents 28502c8 + f97de4e commit 672e66d
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 58 deletions.
32 changes: 18 additions & 14 deletions libs/core/langchain_core/_api/beta_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:
_name = _name or obj.__name__
old_doc = obj.__doc__

def finalize(_: Any, new_doc: str) -> T:
def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
"""Finalize the annotation of a class."""
try:
obj.__doc__ = new_doc
Expand Down Expand Up @@ -153,30 +153,36 @@ def warn_if_direct_instance(
_name = _name or obj.fget.__name__
old_doc = obj.__doc__

class _beta_property(type(obj)): # type: ignore
class _beta_property(property):
"""A beta property."""

def __get__(self, instance, owner=None): # type: ignore
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
super().__init__(fget, fset, fdel, doc)
self.__orig_fget = fget
self.__orig_fset = fset
self.__orig_fdel = fdel

def __get__(self, instance, owner=None):
if instance is not None or owner is not None:
emit_warning()
return super().__get__(instance, owner)
return self.fget(instance)

def __set__(self, instance, value): # type: ignore
def __set__(self, instance, value):
if instance is not None:
emit_warning()
return super().__set__(instance, value)
return self.fset(instance, value)

def __delete__(self, instance): # type: ignore
def __delete__(self, instance):
if instance is not None:
emit_warning()
return super().__delete__(instance)
return self.fdel(instance)

def __set_name__(self, owner, set_name): # type: ignore
def __set_name__(self, owner, set_name):
nonlocal _name
if _name == "<lambda>":
_name = set_name

def finalize(_: Any, new_doc: str) -> Any: # type: ignore
def finalize(wrapper: Callable[..., Any], new_doc: str) -> Any:
"""Finalize the property."""
return _beta_property(
fget=obj.fget, fset=obj.fset, fdel=obj.fdel, doc=new_doc
Expand All @@ -186,12 +192,10 @@ def finalize(_: Any, new_doc: str) -> Any: # type: ignore
if not _obj_type:
_obj_type = "function"
wrapped = obj
_name = _name or obj.__name__ # type: ignore
_name = _name or obj.__name__
old_doc = wrapped.__doc__

def finalize( # type: ignore
wrapper: Callable[..., Any], new_doc: str
) -> T:
def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
"""Wrap the wrapped function using the wrapper and update the docstring.
Args:
Expand Down
32 changes: 18 additions & 14 deletions libs/core/langchain_core/_api/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any:
)
old_doc = obj.__doc__

def finalize(_: Any, new_doc: str) -> T:
def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
"""Finalize the deprecation of a class."""
try:
obj.__doc__ = new_doc
Expand Down Expand Up @@ -191,30 +191,36 @@ def warn_if_direct_instance(
_name = _name or obj.fget.__name__
old_doc = obj.__doc__

class _deprecated_property(type(obj)): # type: ignore
class _deprecated_property(property):
"""A deprecated property."""

def __get__(self, instance, owner=None): # type: ignore
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
super().__init__(fget, fset, fdel, doc)
self.__orig_fget = fget
self.__orig_fset = fset
self.__orig_fdel = fdel

def __get__(self, instance, owner=None):
if instance is not None or owner is not None:
emit_warning()
return super().__get__(instance, owner)
return self.fget(instance)

def __set__(self, instance, value): # type: ignore
def __set__(self, instance, value):
if instance is not None:
emit_warning()
return super().__set__(instance, value)
return self.fset(instance, value)

def __delete__(self, instance): # type: ignore
def __delete__(self, instance):
if instance is not None:
emit_warning()
return super().__delete__(instance)
return self.fdel(instance)

def __set_name__(self, owner, set_name): # type: ignore
def __set_name__(self, owner, set_name):
nonlocal _name
if _name == "<lambda>":
_name = set_name

def finalize(_: Any, new_doc: str) -> Any: # type: ignore
def finalize(wrapper: Callable[..., Any], new_doc: str) -> Any:
"""Finalize the property."""
return _deprecated_property(
fget=obj.fget, fset=obj.fset, fdel=obj.fdel, doc=new_doc
Expand All @@ -224,12 +230,10 @@ def finalize(_: Any, new_doc: str) -> Any: # type: ignore
if not _obj_type:
_obj_type = "function"
wrapped = obj
_name = _name or obj.__name__ # type: ignore
_name = _name or obj.__name__
old_doc = wrapped.__doc__

def finalize( # type: ignore
wrapper: Callable[..., Any], new_doc: str
) -> T:
def finalize(wrapper: Callable[..., Any], new_doc: str) -> T:
"""Wrap the wrapped function using the wrapper and update the docstring.
Args:
Expand Down
17 changes: 17 additions & 0 deletions libs/core/langchain_core/prompts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,23 @@ def format(self, **kwargs: Any) -> FormatOutputType:
prompt.format(variable1="foo")
"""

async def aformat(self, **kwargs: Any) -> FormatOutputType:
"""Format the prompt with the inputs.
Args:
kwargs: Any arguments to be passed to the prompt template.
Returns:
A formatted string.
Example:
.. code-block:: python
await prompt.aformat(variable1="foo")
"""
return self.format(**kwargs)

@property
def _prompt_type(self) -> str:
"""Return the prompt type key."""
Expand Down
36 changes: 22 additions & 14 deletions libs/core/langchain_core/prompts/few_shot.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,6 @@ class Config:
arbitrary_types_allowed = True

def format(self, **kwargs: Any) -> str:
"""Format the prompt with the inputs.
Args:
**kwargs: Any arguments to be passed to the prompt template.
Returns:
A formatted string.
Example:
.. code-block:: python
prompt.format(variable1="foo")
"""
kwargs = self._merge_partial_and_user_variables(**kwargs)
# Get the examples to use.
examples = self._get_examples(**kwargs)
Expand All @@ -178,6 +164,24 @@ def format(self, **kwargs: Any) -> str:
# Format the template with the input variables.
return DEFAULT_FORMATTER_MAPPING[self.template_format](template, **kwargs)

async def aformat(self, **kwargs: Any) -> str:
kwargs = self._merge_partial_and_user_variables(**kwargs)
# Get the examples to use.
examples = await self._aget_examples(**kwargs)
examples = [
{k: e[k] for k in self.example_prompt.input_variables} for e in examples
]
# Format the examples.
example_strings = [
await self.example_prompt.aformat(**example) for example in examples
]
# Create the overall template.
pieces = [self.prefix, *example_strings, self.suffix]
template = self.example_separator.join([piece for piece in pieces if piece])

# Format the template with the input variables.
return DEFAULT_FORMATTER_MAPPING[self.template_format](template, **kwargs)

@property
def _prompt_type(self) -> str:
"""Return the prompt type key."""
Expand Down Expand Up @@ -383,5 +387,9 @@ def format(self, **kwargs: Any) -> str:
messages = self.format_messages(**kwargs)
return get_buffer_string(messages)

async def aformat(self, **kwargs: Any) -> str:
messages = await self.aformat_messages(**kwargs)
return get_buffer_string(messages)

def pretty_repr(self, html: bool = False) -> str:
raise NotImplementedError()
4 changes: 4 additions & 0 deletions libs/core/langchain_core/prompts/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from langchain_core.prompt_values import ImagePromptValue, ImageURL, PromptValue
from langchain_core.prompts.base import BasePromptTemplate
from langchain_core.pydantic_v1 import Field
from langchain_core.runnables import run_in_executor
from langchain_core.utils import image as image_utils


Expand Down Expand Up @@ -80,5 +81,8 @@ def format(
output["detail"] = detail # type: ignore[typeddict-item]
return output

async def aformat(self, **kwargs: Any) -> ImageURL:
return await run_in_executor(None, self.format, **kwargs)

def pretty_repr(self, html: bool = False) -> str:
raise NotImplementedError()
14 changes: 0 additions & 14 deletions libs/core/langchain_core/prompts/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,6 @@ def _prompt_type(self) -> str:
return "prompt"

def format(self, **kwargs: Any) -> str:
"""Format the prompt with the inputs.
Args:
kwargs: Any arguments to be passed to the prompt template.
Returns:
A formatted string.
Example:
.. code-block:: python
prompt.format(variable1="foo")
"""
kwargs = self._merge_partial_and_user_variables(**kwargs)
return DEFAULT_FORMATTER_MAPPING[self.template_format](self.template, **kwargs)

Expand Down
42 changes: 40 additions & 2 deletions libs/core/tests/unit_tests/prompts/test_few_shot.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_prompt_missing_input_variables() -> None:
).input_variables == ["foo"]


def test_few_shot_functionality() -> None:
async def test_few_shot_functionality() -> None:
"""Test that few shot works with examples."""
prefix = "This is a test about {content}."
suffix = "Now you try to talk about {new_content}."
Expand All @@ -112,13 +112,15 @@ def test_few_shot_functionality() -> None:
example_prompt=EXAMPLE_PROMPT,
example_separator="\n",
)
output = prompt.format(content="animals", new_content="party")
expected_output = (
"This is a test about animals.\n"
"foo: bar\n"
"baz: foo\n"
"Now you try to talk about party."
)
output = prompt.format(content="animals", new_content="party")
assert output == expected_output
output = await prompt.aformat(content="animals", new_content="party")
assert output == expected_output


Expand Down Expand Up @@ -365,6 +367,24 @@ def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
return list(self.examples)


def test_few_shot_prompt_template_with_selector() -> None:
"""Tests for few shot chat message template with an example selector."""
examples = [
{"question": "foo", "answer": "bar"},
{"question": "baz", "answer": "foo"},
]
example_selector = AsIsSelector(examples)

few_shot_prompt = FewShotPromptTemplate(
input_variables=["foo"],
suffix="This is a {foo} test.",
example_prompt=EXAMPLE_PROMPT,
example_selector=example_selector,
)
messages = few_shot_prompt.format(foo="bar")
assert messages == "foo: bar\n\nbaz: foo\n\nThis is a bar test."


def test_few_shot_chat_message_prompt_template_with_selector() -> None:
"""Tests for few shot chat message template with an example selector."""
examples = [
Expand Down Expand Up @@ -421,6 +441,24 @@ async def aselect_examples(self, input_variables: Dict[str, str]) -> List[dict]:
return list(self.examples)


async def test_few_shot_prompt_template_with_selector_async() -> None:
"""Tests for few shot chat message template with an example selector."""
examples = [
{"question": "foo", "answer": "bar"},
{"question": "baz", "answer": "foo"},
]
example_selector = AsyncAsIsSelector(examples)

few_shot_prompt = FewShotPromptTemplate(
input_variables=["foo"],
suffix="This is a {foo} test.",
example_prompt=EXAMPLE_PROMPT,
example_selector=example_selector,
)
messages = await few_shot_prompt.aformat(foo="bar")
assert messages == "foo: bar\n\nbaz: foo\n\nThis is a bar test."


async def test_few_shot_chat_message_prompt_template_with_selector_async() -> None:
"""Tests for few shot chat message template with an async example selector."""
examples = [
Expand Down

0 comments on commit 672e66d

Please sign in to comment.