a7d6d88f6f
CI / changes (push) Has been cancelled
CI / cd libs/checkpoint (push) Has been cancelled
CI / cd libs/checkpoint-conformance (push) Has been cancelled
CI / cd libs/checkpoint-postgres (push) Has been cancelled
CI / cd libs/checkpoint-sqlite (push) Has been cancelled
CI / cd libs/cli (push) Has been cancelled
CI / cd libs/prebuilt (push) Has been cancelled
CI / cd libs/sdk-py (push) Has been cancelled
CI / cd libs/langgraph (push) Has been cancelled
CI / Check SDK methods matching (push) Has been cancelled
CI / Check CLI schema hasn't changed #3.13 (push) Has been cancelled
CI / CLI integration test (push) Has been cancelled
CI / sdk-py integration test (push) Has been cancelled
CI / CI Success (push) Has been cancelled
baseline / benchmark (push) Has been cancelled
Deploy Redirects to GitHub Pages / deploy (push) Has been cancelled
158 lines
5.5 KiB
Python
158 lines
5.5 KiB
Python
import re
|
|
from collections.abc import AsyncIterator, Iterator
|
|
from typing import Any, cast
|
|
|
|
from langchain_core.callbacks import (
|
|
AsyncCallbackManagerForLLMRun,
|
|
CallbackManagerForLLMRun,
|
|
)
|
|
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
|
|
from langchain_core.messages import AIMessage, AIMessageChunk, BaseMessage
|
|
from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult
|
|
|
|
|
|
class FakeChatModel(GenericFakeChatModel):
|
|
messages: list[BaseMessage]
|
|
|
|
i: int = 0
|
|
|
|
def bind_tools(self, functions: list):
|
|
return self
|
|
|
|
def _generate(
|
|
self,
|
|
messages: list[BaseMessage],
|
|
stop: list[str] | None = None,
|
|
run_manager: CallbackManagerForLLMRun | None = None,
|
|
**kwargs: Any,
|
|
) -> ChatResult:
|
|
"""Top Level call"""
|
|
if self.i >= len(self.messages):
|
|
self.i = 0
|
|
message = self.messages[self.i]
|
|
self.i += 1
|
|
if isinstance(message, str):
|
|
message_ = AIMessage(content=message)
|
|
else:
|
|
if hasattr(message, "model_copy"):
|
|
message_ = message.model_copy()
|
|
else:
|
|
message_ = message.copy()
|
|
generation = ChatGeneration(message=message_)
|
|
return ChatResult(generations=[generation])
|
|
|
|
def _stream(
|
|
self,
|
|
messages: list[BaseMessage],
|
|
stop: list[str] | None = None,
|
|
run_manager: CallbackManagerForLLMRun | None = None,
|
|
**kwargs: Any,
|
|
) -> Iterator[ChatGenerationChunk]:
|
|
"""Stream the output of the model."""
|
|
chat_result = self._generate(
|
|
messages, stop=stop, run_manager=run_manager, **kwargs
|
|
)
|
|
if not isinstance(chat_result, ChatResult):
|
|
raise ValueError(
|
|
f"Expected generate to return a ChatResult, "
|
|
f"but got {type(chat_result)} instead."
|
|
)
|
|
|
|
message = chat_result.generations[0].message
|
|
|
|
if not isinstance(message, AIMessage):
|
|
raise ValueError(
|
|
f"Expected invoke to return an AIMessage, "
|
|
f"but got {type(message)} instead."
|
|
)
|
|
|
|
content = message.content
|
|
|
|
if content:
|
|
# Use a regular expression to split on whitespace with a capture group
|
|
# so that we can preserve the whitespace in the output.
|
|
assert isinstance(content, str)
|
|
content_chunks = cast(list[str], re.split(r"(\s)", content))
|
|
|
|
for i, token in enumerate(content_chunks):
|
|
if i == len(content_chunks) - 1:
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(
|
|
content=token, id=message.id, chunk_position="last"
|
|
)
|
|
)
|
|
else:
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(content=token, id=message.id)
|
|
)
|
|
if run_manager:
|
|
run_manager.on_llm_new_token(token, chunk=chunk)
|
|
yield chunk
|
|
else:
|
|
args = message.__dict__
|
|
args.pop("type")
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(**args, chunk_position="last")
|
|
)
|
|
if run_manager:
|
|
run_manager.on_llm_new_token("", chunk=chunk)
|
|
yield chunk
|
|
|
|
async def _astream(
|
|
self,
|
|
messages: list[BaseMessage],
|
|
stop: list[str] | None = None,
|
|
run_manager: AsyncCallbackManagerForLLMRun | None = None,
|
|
**kwargs: Any,
|
|
) -> AsyncIterator[ChatGenerationChunk]:
|
|
"""Stream the output of the model."""
|
|
chat_result = self._generate(
|
|
messages, stop=stop, run_manager=run_manager, **kwargs
|
|
)
|
|
if not isinstance(chat_result, ChatResult):
|
|
raise ValueError(
|
|
f"Expected generate to return a ChatResult, "
|
|
f"but got {type(chat_result)} instead."
|
|
)
|
|
|
|
message = chat_result.generations[0].message
|
|
|
|
if not isinstance(message, AIMessage):
|
|
raise ValueError(
|
|
f"Expected invoke to return an AIMessage, "
|
|
f"but got {type(message)} instead."
|
|
)
|
|
|
|
content = message.content
|
|
|
|
if content:
|
|
# Use a regular expression to split on whitespace with a capture group
|
|
# so that we can preserve the whitespace in the output.
|
|
assert isinstance(content, str)
|
|
content_chunks = cast(list[str], re.split(r"(\s)", content))
|
|
|
|
for i, token in enumerate(content_chunks):
|
|
if i == len(content_chunks) - 1:
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(
|
|
content=token, id=message.id, chunk_position="last"
|
|
)
|
|
)
|
|
else:
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(content=token, id=message.id)
|
|
)
|
|
|
|
if run_manager:
|
|
run_manager.on_llm_new_token(token, chunk=chunk)
|
|
yield chunk
|
|
else:
|
|
args = message.__dict__
|
|
args.pop("type")
|
|
chunk = ChatGenerationChunk(
|
|
message=AIMessageChunk(**args, chunk_position="last")
|
|
)
|
|
if run_manager:
|
|
await run_manager.on_llm_new_token("", chunk=chunk)
|
|
yield chunk
|