Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.8.1 #1023

Merged
merged 33 commits into from
Jan 27, 2025
Merged

1.8.1 #1023

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3497ad2
bump qdrant client to 1.9.4
nickprock May 30, 2024
9c4299d
Merge branch 'cheshire-cat-ai:develop' into develop
nickprock May 30, 2024
f4b8757
minor release supported is 1.9.0
nickprock May 30, 2024
d069e31
Merge branch 'develop' of https://github.com/nickprock/core into develop
nickprock May 30, 2024
9dba228
rollback to 1.8
nickprock May 30, 2024
d6afc2f
bump to 1.9.0
nickprock May 30, 2024
0dbd3b0
Merge branch 'cheshire-cat-ai:develop' into develop
nickprock Jun 2, 2024
0585b8a
Merge branch 'cheshire-cat-ai:develop' into develop
nickprock Jun 4, 2024
69ba6b3
Update Dockerfile
pieroit Jan 21, 2025
d8e4cbc
Move history methods from StrayCat to WorkingMemory and update reference
samadpls Jan 23, 2025
8b271c0
simplify endpoint permissions signature
pieroit Jan 24, 2025
aad474a
remove unused imports
pieroit Jan 24, 2025
30de04b
permission tests for custom endpoint
pieroit Jan 24, 2025
497b15a
fix comment and imports
pieroit Jan 24, 2025
be80f9a
Merge branch 'develop' of https://github.com/nickprock/core into develop
nickprock Jan 27, 2025
5e307a6
issue #988
nickprock Jan 27, 2025
651ad22
Merge branch 'ref/move-history-methods-to-working-memory' of https://…
pieroit Jan 27, 2025
da49198
Merge branch 'dev/filter' into develop
nickprock Jan 27, 2025
555dfa7
add docstrings to working memory; increase conversation size in prompt
pieroit Jan 27, 2025
05c73e4
test working memory
pieroit Jan 27, 2025
8d6b5ef
Merge branch 'samadpls-ref/move-history-methods-to-working-memory' in…
pieroit Jan 27, 2025
99c55e6
fix linter
pieroit Jan 27, 2025
edf19c9
Fix: `send_notification`
Pingdred Jan 27, 2025
55b35a6
Merge pull request #1020 from Pingdred/develop
pieroit Jan 27, 2025
2552b47
Merge branch 'develop' of https://github.com/nickprock/core into nick…
pieroit Jan 27, 2025
5fd79f3
fix conflict
pieroit Jan 27, 2025
94d5acc
Merge branch 'nickprock-develop' into develop
pieroit Jan 27, 2025
356b822
more tests for WorkingMemory
pieroit Jan 27, 2025
5148518
Merge branch 'develop' of https://github.com/cheshire-cat-ai/core int…
pieroit Jan 27, 2025
3683228
fix cat.llm for wide-range compatibility
lucagobbi Jan 27, 2025
6f82bfd
removed unused imports
lucagobbi Jan 27, 2025
796c3e7
Merge pull request #1022 from lucagobbi/develop
pieroit Jan 27, 2025
7d67129
Update pyproject.toml
pieroit Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RUN apt-get -y update && apt-get install -y curl build-essential fastjar libmagi

### ADMIN (static build) ###
WORKDIR /admin
RUN curl -sL https://github.com/cheshire-cat-ai/admin-vue/releases/download/Admin/release.zip | jar -xv
RUN curl -sL https://github.com/cheshire-cat-ai/admin-vue/releases/download/Admin/develop.zip | jar -xv

### PREPARE BUILD WITH NECESSARY FILES AND FOLDERS ###
COPY ./pyproject.toml /app/pyproject.toml
Expand Down
2 changes: 1 addition & 1 deletion core/cat/agents/main_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def format_agent_input(self, stray):

# format conversation history to be inserted in the prompt
# TODOV2: take away
conversation_history_formatted_content = stray.stringify_chat_history()
conversation_history_formatted_content = stray.working_memory.stringify_chat_history()

return BaseModelDict(**{
"episodic_memory": episodic_memory_formatted_content,
Expand Down
2 changes: 1 addition & 1 deletion core/cat/agents/memory_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def execute(self, stray, prompt_prefix, prompt_suffix) -> AgentOutput:
SystemMessagePromptTemplate.from_template(
template=sys_prompt
),
*(stray.langchainfy_chat_history()),
*(stray.working_memory.langchainfy_chat_history()),
]
)

Expand Down
2 changes: 1 addition & 1 deletion core/cat/agents/procedures_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def execute_chain(self, stray, procedures_prompt_template, allowed_procedures) -
SystemMessagePromptTemplate.from_template(
template=procedures_prompt_template
),
*(stray.langchainfy_chat_history()),
*(stray.working_memory.langchainfy_chat_history()),
]
)

Expand Down
27 changes: 27 additions & 0 deletions core/cat/auth/permissions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import Enum
from typing import Dict, List

from fastapi import Depends

from cat.utils import BaseModelDict

Expand Down Expand Up @@ -68,3 +69,29 @@ class AuthUserInfo(BaseModelDict):
# - roles
extra: BaseModelDict = {}


def check_permissions(resource: AuthResource, permission: AuthPermission):
"""
Helper function to inject stray into endpoints after checking for required permissions.

Parameters
----------
resource: AuthResource | str
The resource that the user must have permission for.
permission: AuthPermission | str
The permission that the user must have for the resource.

Returns
----------
stray: StrayCat | None
User session object if auth is successfull, None otherwise.
"""


# import here to avoid circular imports
from cat.auth.connection import HTTPAuth
return Depends(HTTPAuth(
# explicit convert to Enum
resource = AuthResource(resource),
permission = AuthPermission(permission),
))
2 changes: 1 addition & 1 deletion core/cat/experimental/form/cat_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def extract(self):
return output_model

def extraction_prompt(self):
history = self.cat.stringify_chat_history()
history = self.cat.working_memory.stringify_chat_history()

# JSON structure
# BaseModel.__fields__['my_field'].type_
Expand Down
63 changes: 13 additions & 50 deletions core/cat/looking_glass/stray_cat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Literal, get_args, List, Dict, Union, Any

from langchain.docstore.document import Document
from langchain_core.messages import SystemMessage, BaseMessage
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_core.runnables import RunnableConfig, RunnableLambda
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers.string import StrOutputParser
Expand Down Expand Up @@ -151,7 +151,7 @@ def send_notification(self, content: str):
Args:
content (str): message to send
"""
self.send_ws_message(text=content, msg_type="notification")
self.send_ws_message(content=content, msg_type="notification")

def send_error(self, error: Union[str, Exception]):
"""Sends an error message to the user using the active WebSocket connection.
Expand Down Expand Up @@ -248,14 +248,14 @@ def recall_relevant_memories_to_working_memory(self, query=None):
"embedding": recall_query_embedding,
"k": 3,
"threshold": 0.7,
"metadata": None,
"metadata": {},
}

default_procedural_recall_config = {
"embedding": recall_query_embedding,
"k": 3,
"threshold": 0.7,
"metadata": None,
"metadata": {},
}

# hooks to change recall configs for each memory
Expand Down Expand Up @@ -322,8 +322,8 @@ def llm(self, prompt: str, stream: bool = False) -> str:
# here we deal with motherfucking langchain
prompt = ChatPromptTemplate(
messages=[
SystemMessage(content=prompt)
# TODO: add here optional convo history passed to the method,
HumanMessage(content=prompt) # We decided to use HumanMessage for wide-range compatibility even if it could bring some problem with tokenizers
# TODO: add here optional convo history passed to the method,
# or taken from working memory
]
)
Expand Down Expand Up @@ -551,50 +551,13 @@ def classify(
# set 0.5 as threshold - let's see if it works properly
return best_label if score < 0.5 else None

def stringify_chat_history(self, latest_n: int = 5) -> str:
"""Serialize chat history.
Converts to text the recent conversation turns.

Parameters
----------
latest_n : int
Hoe many latest turns to stringify.

Returns
-------
history : str
String with recent conversation turns.

Notes
-----
Such context is placed in the `agent_prompt_suffix` in the place held by {chat_history}.

The chat history is a dictionary with keys::
'who': the name of who said the utterance;
'message': the utterance.

"""

history = self.working_memory.history[-latest_n:]

history_string = ""
for turn in history:
history_string += f"\n - {turn.who}: {turn.text}"

return history_string

def langchainfy_chat_history(self, latest_n: int = 5) -> List[BaseMessage]:

chat_history = self.working_memory.history[-latest_n:]
recent_history = chat_history[-latest_n:]
langchain_chat_history = []

for message in recent_history:
langchain_chat_history.append(
message.langchainfy()
)

return langchain_chat_history
def langchainfy_chat_history(self, latest_n: int = 10) -> List[BaseMessage]:
"""Redirects to WorkingMemory.langchainfy_chat_history. Will be removed from this class in v2."""
return self.working_memory.langchainfy_chat_history(latest_n)

def stringify_chat_history(self, latest_n: int = 10) -> str:
"""Redirects to WorkingMemory.stringify_chat_history. Will be removed from this class in v2."""
return self.working_memory.stringify_chat_history(latest_n)

async def close_connection(self):
if self.__ws:
Expand Down
2 changes: 1 addition & 1 deletion core/cat/memory/vector_memory_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def create_collection(self):

# adapted from https://github.com/langchain-ai/langchain/blob/bfc12a4a7644cfc4d832cc4023086a7a5374f46a/libs/langchain/langchain/vectorstores/qdrant.py#L1965
def _qdrant_filter_from_dict(self, filter: dict) -> Filter:
if not filter:
if not filter or len(filter)<1:
return None

return Filter(
Expand Down
49 changes: 49 additions & 0 deletions core/cat/memory/working_memory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import List, Optional
from langchain_core.messages import BaseMessage

from cat.convo.messages import Role, ConversationMessage, UserMessage, CatMessage
from cat.convo.model_interactions import ModelInteraction
Expand Down Expand Up @@ -95,3 +96,51 @@ def update_history(self, message: ConversationMessage):
"""
self.history.append(message)


def stringify_chat_history(self, latest_n: int = 10) -> str:
"""Serialize chat history.
Converts to text the recent conversation turns.
Useful for retrocompatibility with old non-chat models, and to easily insert convo into a prompt without using dedicated objects and libraries.

Parameters
----------
latest_n : int
How many latest turns to stringify.

Returns
-------
history : str
String with recent conversation turns.
"""

history = self.history[-latest_n:]

history_string = ""
for turn in history:
history_string += f"\n - {turn.who}: {turn.text}"

return history_string

def langchainfy_chat_history(self, latest_n: int = 10) -> List[BaseMessage]:
"""Convert chat history in working memory to langchain objects.

Parameters
----------
latest_n : int
How many latest turns to convert.

Returns
-------
history : List[BaseMessage]
List of langchain HumanMessage / AIMessage.
"""
chat_history = self.history[-latest_n:]
recent_history = chat_history[-latest_n:]
langchain_chat_history = []

for message in recent_history:
langchain_chat_history.append(
message.langchainfy()
)

return langchain_chat_history
11 changes: 5 additions & 6 deletions core/cat/routes/auth_handler.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from typing import Dict
from fastapi import Request, APIRouter, Body, HTTPException, Depends
from fastapi import Request, APIRouter, Body, HTTPException

from cat.db import crud, models
from cat.factory.auth_handler import get_auth_handlers_schemas
from cat.auth.connection import HTTPAuth
from cat.auth.permissions import AuthPermission, AuthResource
from cat.auth.permissions import AuthPermission, AuthResource, check_permissions

router = APIRouter()

Expand All @@ -15,7 +14,7 @@

@router.get(
"/settings",
dependencies=[Depends(HTTPAuth(AuthResource.AUTH_HANDLER, AuthPermission.LIST))],
dependencies=[check_permissions(AuthResource.AUTH_HANDLER, AuthPermission.LIST)],
)
def get_auth_handler_settings(request: Request) -> Dict:
"""Get the list of the AuthHandlers"""
Expand Down Expand Up @@ -51,7 +50,7 @@ def get_auth_handler_settings(request: Request) -> Dict:

@router.get(
"/settings/{auth_handler_name}",
dependencies=[Depends(HTTPAuth(AuthResource.AUTH_HANDLER, AuthPermission.READ))],
dependencies=[check_permissions(AuthResource.AUTH_HANDLER, AuthPermission.READ)],
)
def get_auth_handler_setting(request: Request, auth_handler_name: str) -> Dict:
"""Get the settings of a specific AuthHandler"""
Expand Down Expand Up @@ -80,7 +79,7 @@ def get_auth_handler_setting(request: Request, auth_handler_name: str) -> Dict:

@router.put(
"/settings/{auth_handler_name}",
dependencies=[Depends(HTTPAuth(AuthResource.AUTH_HANDLER, AuthPermission.EDIT))],
dependencies=[check_permissions(AuthResource.AUTH_HANDLER, AuthPermission.EDIT)],
)
def upsert_authenticator_setting(
request: Request,
Expand Down
9 changes: 4 additions & 5 deletions core/cat/routes/base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from fastapi import APIRouter, Depends, Body
from fastapi import APIRouter, Body
from fastapi.concurrency import run_in_threadpool
from typing import Dict
import tomli
from cat.auth.permissions import AuthPermission, AuthResource
from cat.auth.connection import HTTPAuth
from cat.auth.permissions import AuthPermission, AuthResource, check_permissions

from cat.convo.messages import CatMessage

Expand All @@ -13,7 +12,7 @@
# server status
@router.get("/")
async def status(
stray=Depends(HTTPAuth(AuthResource.STATUS, AuthPermission.READ)),
stray=check_permissions(AuthResource.STATUS, AuthPermission.READ),
) -> Dict:
"""Server status"""
with open("pyproject.toml", "rb") as f:
Expand All @@ -25,7 +24,7 @@ async def status(
@router.post("/message", response_model=CatMessage)
async def message_with_cat(
payload: Dict = Body({"text": "hello!"}),
stray=Depends(HTTPAuth(AuthResource.CONVERSATION, AuthPermission.WRITE)),
stray=check_permissions(AuthResource.CONVERSATION, AuthPermission.WRITE),
) -> Dict:
"""Get a response from the Cat"""
user_message_json = {"user_id": stray.user_id, **payload}
Expand Down
11 changes: 5 additions & 6 deletions core/cat/routes/embedder.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import Dict

from cat.auth.connection import HTTPAuth
from cat.auth.permissions import AuthPermission, AuthResource
from fastapi import Request, APIRouter, Body, HTTPException, Depends
from cat.auth.permissions import AuthPermission, AuthResource, check_permissions
from fastapi import Request, APIRouter, Body, HTTPException

from cat.factory.embedder import get_allowed_embedder_models, get_embedders_schemas
from cat.db import crud, models
Expand All @@ -25,7 +24,7 @@
@router.get("/settings")
def get_embedders_settings(
request: Request,
stray=Depends(HTTPAuth(AuthResource.EMBEDDER, AuthPermission.LIST)),
stray=check_permissions(AuthResource.EMBEDDER, AuthPermission.LIST),
) -> Dict:
"""Get the list of the Embedders"""

Expand Down Expand Up @@ -72,7 +71,7 @@ def get_embedders_settings(
def get_embedder_settings(
request: Request,
languageEmbedderName: str,
stray=Depends(HTTPAuth(AuthResource.EMBEDDER, AuthPermission.READ)),
stray=check_permissions(AuthResource.EMBEDDER, AuthPermission.READ),
) -> Dict:
"""Get settings and schema of the specified Embedder"""

Expand Down Expand Up @@ -103,7 +102,7 @@ def upsert_embedder_setting(
request: Request,
languageEmbedderName: str,
payload: Dict = Body({"openai_api_key": "your-key-here"}),
stray=Depends(HTTPAuth(AuthResource.EMBEDDER, AuthPermission.EDIT)),
stray=check_permissions(AuthResource.EMBEDDER, AuthPermission.EDIT),
) -> Dict:
"""Upsert the Embedder setting"""

Expand Down
11 changes: 5 additions & 6 deletions core/cat/routes/llm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import Dict

from cat.auth.connection import HTTPAuth
from cat.auth.permissions import AuthPermission, AuthResource
from fastapi import Request, APIRouter, Body, HTTPException, Depends
from cat.auth.permissions import AuthPermission, AuthResource, check_permissions
from fastapi import Request, APIRouter, Body, HTTPException

from cat.factory.llm import get_llms_schemas
from cat.db import crud, models
Expand All @@ -24,7 +23,7 @@
# get configured LLMs and configuration schemas
@router.get("/settings")
def get_llms_settings(
stray=Depends(HTTPAuth(AuthResource.LLM, AuthPermission.LIST)),
stray=check_permissions(AuthResource.LLM, AuthPermission.LIST),
) -> Dict:
"""Get the list of the Large Language Models"""
LLM_SCHEMAS = get_llms_schemas()
Expand Down Expand Up @@ -63,7 +62,7 @@ def get_llms_settings(
def get_llm_settings(
request: Request,
languageModelName: str,
stray=Depends(HTTPAuth(AuthResource.LLM, AuthPermission.READ)),
stray=check_permissions(AuthResource.LLM, AuthPermission.READ),
) -> Dict:
"""Get settings and schema of the specified Large Language Model"""
LLM_SCHEMAS = get_llms_schemas()
Expand Down Expand Up @@ -94,7 +93,7 @@ def upsert_llm_setting(
request: Request,
languageModelName: str,
payload: Dict = Body({"openai_api_key": "your-key-here"}),
stray=Depends(HTTPAuth(AuthResource.LLM, AuthPermission.EDIT)),
stray=check_permissions(AuthResource.LLM, AuthPermission.EDIT),
) -> Dict:
"""Upsert the Large Language Model setting"""
LLM_SCHEMAS = get_llms_schemas()
Expand Down
Loading
Loading