Tony20100/langchain_full huggingface dataset:
"""Expander's label string."""
        return self._label
    @property
    def expanded(self) -> bool:
        """True if the expander was created with `expanded=True`."""
        return self._expanded
[docs]    def clear(self) -> None:
        """Remove the container and its contents entirely. A cleared container can't
        be reused.
        """
        self._container = self._parent_cursor.empty()
        self._child_records.clear()
[docs]    def append_copy(self, other: MutableExpander) -> None:
        """Append a copy of another MutableExpander's children to this
        MutableExpander.
        """
        other_records = other._child_records.copy()
        for record in other_records:
            self._create_child(record.type, record.kwargs)
[docs]    def update(
        self, *, new_label: Optional[str] = None, new_expanded: Optional[bool] = None
    ) -> None:
        """Change the expander's label and expanded state"""
        if new_label is None:
            new_label = self._label
        if new_expanded is None:
            new_expanded = self._expanded
        if self._label == new_label and self._expanded == new_expanded:
            # No change!
            return
        self._label = new_label
        self._expanded = new_expanded
        self._container = self._parent_cursor.expander(new_label, new_expanded)
        prev_records = self._child_records
        self._child_records = []
        # Replay all children into the new container
        for record in prev_records:
            self._create_child(record.type, record.kwargs)
[docs]    def markdown(
        self,
        body: SupportsStr,
[docs]    def markdown(
        self,
        body: SupportsStr,
        unsafe_allow_html: bool = False,
        *,
        help: Optional[str] = None,
        index: Optional[int] = None,
    ) -> int:
        """Add a Markdown element to the container and return its index."""
        kwargs = {"body": body, "unsafe_allow_html": unsafe_allow_html, "help": help}
        new_dg = self._get_dg(index).markdown(**kwargs)
        record = ChildRecord(ChildType.MARKDOWN, kwargs, new_dg)
        return self._add_record(record, index)
[docs]    def exception(
        self, exception: BaseException, *, index: Optional[int] = None
    ) -> int:
        """Add an Exception element to the container and return its index."""
        kwargs = {"exception": exception}
        new_dg = self._get_dg(index).exception(**kwargs)
        record = ChildRecord(ChildType.EXCEPTION, kwargs, new_dg)
        return self._add_record(record, index)
    def _create_child(self, type: ChildType, kwargs: Dict[str, Any]) -> None:
        """Create a new child with the given params"""
        if type == ChildType.MARKDOWN:
            self.markdown(**kwargs)
        elif type == ChildType.EXCEPTION:
            self.exception(**kwargs)
        else:
            raise RuntimeError(f"Unexpected child type {type}")
    def _add_record(self, record: ChildRecord, index: Optional[int]) -> int:
        """Add a ChildRecord to self._children. If `index` is specified, replace
        the existing record at that index. Otherwise, append the record to the
        end of the list.
end of the list.
        Return the index of the added record.
        """
        if index is not None:
            # Replace existing child
            self._child_records[index] = record
            return index
        # Append new child
        self._child_records.append(record)
        return len(self._child_records) - 1
    def _get_dg(self, index: Optional[int]) -> DeltaGenerator:
        if index is not None:
            # Existing index: reuse child's DeltaGenerator
            assert 0 <= index < len(self._child_records), f"Bad index: {index}"
            return self._child_records[index].dg
        # No index: use container's DeltaGenerator
        return self._container
Source code for langchain_community.callbacks.streamlit.streamlit_callback_handler
"""Callback Handler that prints to streamlit."""
from __future__ import annotations
from enum import Enum
from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional
from langchain_core.agents import AgentAction, AgentFinish
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.outputs import LLMResult
from langchain_community.callbacks.streamlit.mutable_expander import MutableExpander
if TYPE_CHECKING:
    from streamlit.delta_generator import DeltaGenerator
def _convert_newlines(text: str) -> str:
    """Convert newline characters to markdown newline sequences
    (space, space, newline).
    """
    return text.replace("\n", "  \n")
CHECKMARK_EMOJI = "✅"
THINKING_EMOJI = ":thinking_face:"
HISTORY_EMOJI = ":books:"
EXCEPTION_EMOJI = "⚠️"
[docs]class LLMThoughtState(Enum):
    """Enumerator of the LLMThought state."""
    # The LLM is thinking about what to do next. We don't know which tool we'll run.
    THINKING = "THINKING"
    # The LLM has decided to run a tool. We don't have results from the tool yet.
    RUNNING_TOOL = "RUNNING_TOOL"
    # We have results from the tool.
    COMPLETE = "COMPLETE"
[docs]class ToolRecord(NamedTuple):
    """Tool record as a NamedTuple."""
    name: str
    input_str: str
[docs]class LLMThoughtLabeler:
    """
    Generates markdown labels for LLMThought containers. Pass a custom
    subclass of this to StreamlitCallbackHandler to override its default
    labeling logic.
    """
)
[docs]    def on_tool_end(
        self,
        output: Any,
        color: Optional[str] = None,
        observation_prefix: Optional[str] = None,
        llm_prefix: Optional[str] = None,
        **kwargs: Any,
    ) -> None:
        self._container.markdown(f"**{str(output)}**")
[docs]    def on_tool_error(self, error: BaseException, **kwargs: Any) -> None:
        self._container.markdown("**Tool encountered an error...**")
        self._container.exception(error)
[docs]    def on_agent_action(
        self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
    ) -> Any:
        # Called when we're about to kick off a new tool. The `action` data
        # tells us the tool we're about to use, and the input we'll give it.
        # We don't output anything here, because we'll receive this same data
        # when `on_tool_start` is called immediately after.
        pass
[docs]    def complete(self, final_label: Optional[str] = None) -> None:
        """Finish the thought."""
        if final_label is None and self._state == LLMThoughtState.RUNNING_TOOL:
            assert (
                self._last_tool is not None
            ), "_last_tool should never be null when _state == RUNNING_TOOL"
            final_label = self._labeler.get_tool_label(
                self._last_tool, is_complete=True
            )
        self._state = LLMThoughtState.COMPLETE
        if self._collapse_on_complete:
            self._container.update(new_label=final_label, new_expanded=False)
        else:
else:
            self._container.update(new_label=final_label)
[docs]    def clear(self) -> None:
        """Remove the thought from the screen. A cleared thought can't be reused."""
        self._container.clear()
[docs]class StreamlitCallbackHandler(BaseCallbackHandler):
    """Callback handler that writes to a Streamlit app."""
[docs]    def __init__(
        self,
        parent_container: DeltaGenerator,
        *,
        max_thought_containers: int = 4,
        expand_new_thoughts: bool = True,
        collapse_completed_thoughts: bool = True,
        thought_labeler: Optional[LLMThoughtLabeler] = None,
    ):
        """Create a StreamlitCallbackHandler instance.
        Parameters
        ----------
        parent_container
            The `st.container` that will contain all the Streamlit elements that the
            Handler creates.
        max_thought_containers
            The max number of completed LLM thought containers to show at once. When
            this threshold is reached, a new thought will cause the oldest thoughts to
            be collapsed into a "History" expander. Defaults to 4.
        expand_new_thoughts
            Each LLM "thought" gets its own `st.expander`. This param controls whether
            that expander is expanded by default. Defaults to True.
        collapse_completed_thoughts
            If True, LLM thought expanders will be collapsed when completed.
            Defaults to True.
        thought_labeler
            An optional custom LLMThoughtLabeler instance. If unspecified, the handler
            will use the default thought labeling logic. Defaults to None.
        """
        self._parent_container = parent_container
        self._history_parent = parent_container.container()
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
    ) -> None:
        if self._current_thought is None:
            self._current_thought = LLMThought(
                parent_container=self._parent_container,
                expanded=self._expand_new_thoughts,
                collapse_on_complete=self._collapse_completed_thoughts,
                labeler=self._thought_labeler,
            )
        self._current_thought.on_llm_start(serialized, prompts)
        # We don't prune_old_thought_containers here, because our container won't
        # be visible until it has a child.
[docs]    def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
        self._require_current_thought().on_llm_new_token(token, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
        self._require_current_thought().on_llm_end(response, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_llm_error(self, error: BaseException, **kwargs: Any) -> None:
        self._require_current_thought().on_llm_error(error, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_tool_start(
        self, serialized: Dict[str, Any], input_str: str, **kwargs: Any
    ) -> None:
        self._require_current_thought().on_tool_start(serialized, input_str, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_tool_end(
        self,
        output: Any,
[docs]    def on_tool_end(
        self,
        output: Any,
        color: Optional[str] = None,
        observation_prefix: Optional[str] = None,
        llm_prefix: Optional[str] = None,
        **kwargs: Any,
    ) -> None:
        output = str(output)
        self._require_current_thought().on_tool_end(
            output, color, observation_prefix, llm_prefix, **kwargs
        )
        self._complete_current_thought()
[docs]    def on_tool_error(self, error: BaseException, **kwargs: Any) -> None:
        self._require_current_thought().on_tool_error(error, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_text(
        self,
        text: str,
        color: Optional[str] = None,
        end: str = "",
        **kwargs: Any,
    ) -> None:
        pass
[docs]    def on_chain_start(
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
    ) -> None:
        pass
[docs]    def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
        pass
[docs]    def on_chain_error(self, error: BaseException, **kwargs: Any) -> None:
        pass
[docs]    def on_agent_action(
        self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
    ) -> Any:
        self._require_current_thought().on_agent_action(action, color, **kwargs)
        self._prune_old_thought_containers()
[docs]    def on_agent_finish(
Source code for langchain_community.chat_message_histories.tidb
import json
import logging
from datetime import datetime
from typing import List, Optional
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.messages import BaseMessage, message_to_dict, messages_from_dict
from sqlalchemy import create_engine, text
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker
logger = logging.getLogger(__name__)
[docs]class TiDBChatMessageHistory(BaseChatMessageHistory):
    """
    Represents a chat message history stored in a TiDB database.
    """
[docs]    def __init__(
        self,
        session_id: str,
        connection_string: str,
        table_name: str = "langchain_message_store",
        earliest_time: Optional[datetime] = None,
    ):
        """
        Initializes a new instance of the TiDBChatMessageHistory class.
        Args:
            session_id (str): The ID of the chat session.
            connection_string (str): The connection string for the TiDB database.
                format: mysql+pymysql://<host>:<PASSWORD>@<host>:4000/<db>?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true
            table_name (str, optional): the table name to store the chat messages.
                Defaults to "langchain_message_store".
            earliest_time (Optional[datetime], optional): The earliest time to retrieve messages from.
                Defaults to None.
        """  # noqa
        self.session_id = session_id
        self.table_name = table_name
        self.earliest_time = earliest_time
        self.cache: List = []
        # Set up SQLAlchemy engine and session
        self.engine = create_engine(connection_string)
        Session = sessionmaker(bind=self.engine)
self.engine = create_engine(connection_string)
        Session = sessionmaker(bind=self.engine)
        self.session = Session()
        self._create_table_if_not_exists()
        self._load_messages_to_cache()
    def _create_table_if_not_exists(self) -> None:
        """
        Creates a table if it does not already exist in the database.
        """
        create_table_query = text(
            f"""
            CREATE TABLE IF NOT EXISTS {self.table_name} (
                id INT AUTO_INCREMENT PRIMARY KEY,
                session_id VARCHAR(255) NOT NULL,
                message JSON NOT NULL,
                create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                INDEX session_idx (session_id)
            );"""
        )
        try:
            self.session.execute(create_table_query)
            self.session.commit()
        except SQLAlchemyError as e:
            logger.error(f"Error creating table: {e}")
            self.session.rollback()
    def _load_messages_to_cache(self) -> None:
        """
        Loads messages from the database into the cache.
        This method retrieves messages from the database table. The retrieved messages
        are then stored in the cache for faster access.
        Raises:
            SQLAlchemyError: If there is an error executing the database query.
        """
        time_condition = (
            f"AND create_time >= '{self.earliest_time}'" if self.earliest_time else ""
        )
        query = text(
            f"""
            SELECT message FROM {self.table_name} 
            WHERE session_id = :session_id {time_condition} 
            ORDER BY id;
        """
        )
        try:
            result = self.session.execute(query, {"session_id": self.session_id})
            for record in result.fetchall():
                message_dict = json.loads(record[0])
for record in result.fetchall():
                message_dict = json.loads(record[0])
                self.cache.append(messages_from_dict([message_dict])[0])
        except SQLAlchemyError as e:
            logger.error(f"Error loading messages to cache: {e}")
    @property
    def messages(self) -> List[BaseMessage]:  # type: ignore[override]
        """returns all messages"""
        if len(self.cache) == 0:
            self.reload_cache()
        return self.cache
[docs]    def add_message(self, message: BaseMessage) -> None:
        """adds a message to the database and cache"""
        query = text(
            f"INSERT INTO {self.table_name} (session_id, message) VALUES (:session_id, :message);"  # noqa
        )
        try:
            self.session.execute(
                query,
                {
                    "session_id": self.session_id,
                    "message": json.dumps(message_to_dict(message)),
                },
            )
            self.session.commit()
            self.cache.append(message)
        except SQLAlchemyError as e:
            logger.error(f"Error adding message: {e}")
            self.session.rollback()
[docs]    def clear(self) -> None:
        """clears all messages"""
        query = text(f"DELETE FROM {self.table_name} WHERE session_id = :session_id;")
        try:
            self.session.execute(query, {"session_id": self.session_id})
            self.session.commit()
            self.cache.clear()
        except SQLAlchemyError as e:
            logger.error(f"Error clearing messages: {e}")
            self.session.rollback()
[docs]    def reload_cache(self) -> None:
        """reloads messages from database to cache"""
        self.cache.clear()
Source code for langchain_community.chat_message_histories.astradb
"""Astra DB - based chat message history, based on astrapy."""
from __future__ import annotations
import json
import time
from typing import TYPE_CHECKING, List, Optional, Sequence
from langchain_community.utilities.astradb import (
    SetupMode,
    _AstraDBCollectionEnvironment,
)
if TYPE_CHECKING:
    from astrapy.db import AstraDB, AsyncAstraDB
from langchain_core._api.deprecation import deprecated
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.messages import (
    BaseMessage,
    message_to_dict,
    messages_from_dict,
)
DEFAULT_COLLECTION_NAME = "langchain_message_store"
[docs]@deprecated(
    since="0.0.25",
    removal="0.3.0",
    alternative_import="langchain_astradb.AstraDBChatMessageHistory",
)
class AstraDBChatMessageHistory(BaseChatMessageHistory):
[docs]    def __init__(
        self,
        *,
        session_id: str,
        collection_name: str = DEFAULT_COLLECTION_NAME,
        token: Optional[str] = None,
        api_endpoint: Optional[str] = None,
        astra_db_client: Optional[AstraDB] = None,
        async_astra_db_client: Optional[AsyncAstraDB] = None,
        namespace: Optional[str] = None,
        setup_mode: SetupMode = SetupMode.SYNC,
        pre_delete_collection: bool = False,
    ) -> None:
        """Chat message history that stores history in Astra DB.
        Args:
            session_id: arbitrary key that is used to store the messages
                of a single chat session.
of a single chat session.
            collection_name: name of the Astra DB collection to create/use.
            token: API token for Astra DB usage.
            api_endpoint: full URL to the API endpoint,
                such as "https://<DB-ID>-us-east1.apps.astra.datastax.com".
            astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AstraDB' instance.
            async_astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AsyncAstraDB' instance.
            namespace: namespace (aka keyspace) where the
                collection is created. Defaults to the database's "default namespace".
            setup_mode: mode used to create the Astra DB collection (SYNC, ASYNC or
                OFF).
            pre_delete_collection: whether to delete the collection
                before creating it. If False and the collection already exists,
                the collection will be used as is.
        """
        self.astra_env = _AstraDBCollectionEnvironment(
            collection_name=collection_name,
            token=token,
            api_endpoint=api_endpoint,
            astra_db_client=astra_db_client,
            async_astra_db_client=async_astra_db_client,
            namespace=namespace,
            setup_mode=setup_mode,
            pre_delete_collection=pre_delete_collection,
        )
        self.collection = self.astra_env.collection
        self.async_collection = self.astra_env.async_collection
        self.session_id = session_id
        self.collection_name = collection_name
    @property
    def messages(self) -> List[BaseMessage]:
        """Retrieve all session messages from DB"""
        self.astra_env.ensure_db_setup()
        message_blobs = [
self.astra_env.ensure_db_setup()
        message_blobs = [
            doc["body_blob"]
            for doc in sorted(
                self.collection.paginated_find(
                    filter={
                        "session_id": self.session_id,
                    },
                    projection={
                        "timestamp": 1,
                        "body_blob": 1,
                    },
                ),
                key=lambda _doc: _doc["timestamp"],
            )
        ]
        items = [json.loads(message_blob) for message_blob in message_blobs]
        messages = messages_from_dict(items)
        return messages
    @messages.setter
    def messages(self, messages: List[BaseMessage]) -> None:
        raise NotImplementedError("Use add_messages instead")
[docs]    async def aget_messages(self) -> List[BaseMessage]:
        await self.astra_env.aensure_db_setup()
        docs = self.async_collection.paginated_find(
            filter={
                "session_id": self.session_id,
            },
            projection={
                "timestamp": 1,
                "body_blob": 1,
            },
        )
        sorted_docs = sorted(
            [doc async for doc in docs],
            key=lambda _doc: _doc["timestamp"],
        )
        message_blobs = [doc["body_blob"] for doc in sorted_docs]
        items = [json.loads(message_blob) for message_blob in message_blobs]
        messages = messages_from_dict(items)
        return messages
[docs]    def add_messages(self, messages: Sequence[BaseMessage]) -> None:
        self.astra_env.ensure_db_setup()
        docs = [
            {
                "timestamp": time.time(),
                "session_id": self.session_id,
                "body_blob": json.dumps(message_to_dict(message)),
"body_blob": json.dumps(message_to_dict(message)),
            }
            for message in messages
        ]
        self.collection.chunked_insert_many(docs)
[docs]    async def aadd_messages(self, messages: Sequence[BaseMessage]) -> None:
        await self.astra_env.aensure_db_setup()
        docs = [
            {
                "timestamp": time.time(),
                "session_id": self.session_id,
                "body_blob": json.dumps(message_to_dict(message)),
            }
            for message in messages
        ]
        await self.async_collection.chunked_insert_many(docs)
[docs]    def clear(self) -> None:
        self.astra_env.ensure_db_setup()
        self.collection.delete_many(filter={"session_id": self.session_id})
[docs]    async def aclear(self) -> None:
        await self.astra_env.aensure_db_setup()
        await self.async_collection.delete_many(filter={"session_id": self.session_id})