Session id: int -> UUID (#2814)

* session id: int -> UUID

* nit

* validated

* validated downgrade + upgrade + all functionality

* nit

* minor nit

* fix test case
This commit is contained in:
pablodanswer 2024-10-16 15:18:45 -07:00 committed by GitHub
parent f3fb7c572e
commit db0779dd02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 276 additions and 106 deletions

View File

@ -0,0 +1,153 @@
"""
Revision ID: 6756efa39ada
Revises: 5d12a446f5c0
Create Date: 2024-10-15 17:47:44.108537
"""
from alembic import op
import sqlalchemy as sa
revision = "6756efa39ada"
down_revision = "5d12a446f5c0"
branch_labels = None
depends_on = None
"""
Migrate chat_session and chat_message tables to use UUID primary keys.
This script:
1. Adds UUID columns to chat_session and chat_message
2. Populates new columns with UUIDs
3. Updates foreign key relationships
4. Removes old integer ID columns
Note: Downgrade will assign new integer IDs, not restore original ones.
"""
def upgrade() -> None:
op.execute("CREATE EXTENSION IF NOT EXISTS pgcrypto;")
op.add_column(
"chat_session",
sa.Column(
"new_id",
sa.UUID(as_uuid=True),
server_default=sa.text("gen_random_uuid()"),
nullable=False,
),
)
op.execute("UPDATE chat_session SET new_id = gen_random_uuid();")
op.add_column(
"chat_message",
sa.Column("new_chat_session_id", sa.UUID(as_uuid=True), nullable=True),
)
op.execute(
"""
UPDATE chat_message
SET new_chat_session_id = cs.new_id
FROM chat_session cs
WHERE chat_message.chat_session_id = cs.id;
"""
)
op.drop_constraint(
"chat_message_chat_session_id_fkey", "chat_message", type_="foreignkey"
)
op.drop_column("chat_message", "chat_session_id")
op.alter_column(
"chat_message", "new_chat_session_id", new_column_name="chat_session_id"
)
op.drop_constraint("chat_session_pkey", "chat_session", type_="primary")
op.drop_column("chat_session", "id")
op.alter_column("chat_session", "new_id", new_column_name="id")
op.create_primary_key("chat_session_pkey", "chat_session", ["id"])
op.create_foreign_key(
"chat_message_chat_session_id_fkey",
"chat_message",
"chat_session",
["chat_session_id"],
["id"],
ondelete="CASCADE",
)
def downgrade() -> None:
op.drop_constraint(
"chat_message_chat_session_id_fkey", "chat_message", type_="foreignkey"
)
op.add_column(
"chat_session",
sa.Column("old_id", sa.Integer, autoincrement=True, nullable=True),
)
op.execute("CREATE SEQUENCE chat_session_old_id_seq OWNED BY chat_session.old_id;")
op.execute(
"ALTER TABLE chat_session ALTER COLUMN old_id SET DEFAULT nextval('chat_session_old_id_seq');"
)
op.execute(
"UPDATE chat_session SET old_id = nextval('chat_session_old_id_seq') WHERE old_id IS NULL;"
)
op.alter_column("chat_session", "old_id", nullable=False)
op.drop_constraint("chat_session_pkey", "chat_session", type_="primary")
op.create_primary_key("chat_session_pkey", "chat_session", ["old_id"])
op.add_column(
"chat_message",
sa.Column("old_chat_session_id", sa.Integer, nullable=True),
)
op.execute(
"""
UPDATE chat_message
SET old_chat_session_id = cs.old_id
FROM chat_session cs
WHERE chat_message.chat_session_id = cs.id;
"""
)
op.drop_column("chat_message", "chat_session_id")
op.alter_column(
"chat_message", "old_chat_session_id", new_column_name="chat_session_id"
)
op.create_foreign_key(
"chat_message_chat_session_id_fkey",
"chat_message",
"chat_session",
["chat_session_id"],
["old_id"],
ondelete="CASCADE",
)
op.drop_column("chat_session", "id")
op.alter_column("chat_session", "old_id", new_column_name="id")
op.alter_column(
"chat_session",
"id",
type_=sa.Integer(),
existing_type=sa.Integer(),
existing_nullable=False,
existing_server_default=False,
)
# Rename the sequence
op.execute("ALTER SEQUENCE chat_session_old_id_seq RENAME TO chat_session_id_seq;")
# Update the default value to use the renamed sequence
op.alter_column(
"chat_session",
"id",
server_default=sa.text("nextval('chat_session_id_seq'::regclass)"),
)

View File

@ -1,5 +1,6 @@
import re
from typing import cast
from uuid import UUID
from fastapi.datastructures import Headers
from sqlalchemy.orm import Session
@ -34,7 +35,7 @@ def llm_doc_from_inference_section(inference_section: InferenceSection) -> LlmDo
def create_chat_chain(
chat_session_id: int,
chat_session_id: UUID,
db_session: Session,
prefetch_tool_calls: bool = True,
# Optional id at which we finish processing

View File

@ -43,7 +43,7 @@ logger = setup_logger()
def get_chat_session_by_id(
chat_session_id: int,
chat_session_id: UUID,
user_id: UUID | None,
db_session: Session,
include_deleted: bool = False,
@ -87,9 +87,9 @@ def get_chat_sessions_by_slack_thread_id(
def get_valid_messages_from_query_sessions(
chat_session_ids: list[int],
chat_session_ids: list[UUID],
db_session: Session,
) -> dict[int, str]:
) -> dict[UUID, str]:
user_message_subquery = (
select(
ChatMessage.chat_session_id, func.min(ChatMessage.id).label("user_msg_id")
@ -196,7 +196,7 @@ def delete_orphaned_search_docs(db_session: Session) -> None:
def delete_messages_and_files_from_chat_session(
chat_session_id: int, db_session: Session
chat_session_id: UUID, db_session: Session
) -> None:
# Select messages older than cutoff_time with files
messages_with_files = db_session.execute(
@ -253,7 +253,7 @@ def create_chat_session(
def update_chat_session(
db_session: Session,
user_id: UUID | None,
chat_session_id: int,
chat_session_id: UUID,
description: str | None = None,
sharing_status: ChatSessionSharedStatus | None = None,
) -> ChatSession:
@ -276,7 +276,7 @@ def update_chat_session(
def delete_chat_session(
user_id: UUID | None,
chat_session_id: int,
chat_session_id: UUID,
db_session: Session,
hard_delete: bool = HARD_DELETE_CHATS,
) -> None:
@ -337,7 +337,7 @@ def get_chat_message(
def get_chat_messages_by_sessions(
chat_session_ids: list[int],
chat_session_ids: list[UUID],
user_id: UUID | None,
db_session: Session,
skip_permission_check: bool = False,
@ -370,7 +370,7 @@ def get_search_docs_for_chat_message(
def get_chat_messages_by_session(
chat_session_id: int,
chat_session_id: UUID,
user_id: UUID | None,
db_session: Session,
skip_permission_check: bool = False,
@ -397,7 +397,7 @@ def get_chat_messages_by_session(
def get_or_create_root_message(
chat_session_id: int,
chat_session_id: UUID,
db_session: Session,
) -> ChatMessage:
try:
@ -433,7 +433,7 @@ def get_or_create_root_message(
def reserve_message_id(
db_session: Session,
chat_session_id: int,
chat_session_id: UUID,
parent_message: int,
message_type: MessageType,
) -> int:
@ -460,7 +460,7 @@ def reserve_message_id(
def create_new_chat_message(
chat_session_id: int,
chat_session_id: UUID,
parent_message: ChatMessage,
message: str,
prompt_id: int | None,

View File

@ -5,9 +5,12 @@ from typing import Any
from typing import Literal
from typing import NotRequired
from typing import Optional
from uuid import uuid4
from typing_extensions import TypedDict # noreorder
from uuid import UUID
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from fastapi_users_db_sqlalchemy import SQLAlchemyBaseOAuthAccountTableUUID
from fastapi_users_db_sqlalchemy import SQLAlchemyBaseUserTableUUID
from fastapi_users_db_sqlalchemy.access_token import SQLAlchemyBaseAccessTokenTableUUID
@ -920,7 +923,9 @@ class ToolCall(Base):
class ChatSession(Base):
__tablename__ = "chat_session"
id: Mapped[int] = mapped_column(primary_key=True)
id: Mapped[UUID] = mapped_column(
PGUUID(as_uuid=True), primary_key=True, default=uuid4
)
user_id: Mapped[UUID | None] = mapped_column(
ForeignKey("user.id", ondelete="CASCADE"), nullable=True
)
@ -990,7 +995,9 @@ class ChatMessage(Base):
__tablename__ = "chat_message"
id: Mapped[int] = mapped_column(primary_key=True)
chat_session_id: Mapped[int] = mapped_column(ForeignKey("chat_session.id"))
chat_session_id: Mapped[UUID] = mapped_column(
PGUUID(as_uuid=True), ForeignKey("chat_session.id")
)
alternate_assistant_id = mapped_column(
Integer, ForeignKey("persona.id"), nullable=True

View File

@ -1,3 +1,5 @@
from uuid import UUID
from pydantic import BaseModel
from danswer.server.query_and_chat.models import ChatSessionDetails
@ -23,7 +25,7 @@ class FolderUpdateRequest(BaseModel):
class FolderChatSessionRequest(BaseModel):
chat_session_id: int
chat_session_id: UUID
class DeleteFolderOptions(BaseModel):

View File

@ -4,6 +4,7 @@ import uuid
from collections.abc import Callable
from collections.abc import Generator
from typing import Tuple
from uuid import UUID
from fastapi import APIRouter
from fastapi import Depends
@ -131,7 +132,7 @@ def update_chat_session_model(
@router.get("/get-chat-session/{session_id}")
def get_chat_session(
session_id: int,
session_id: UUID,
is_shared: bool = False,
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
@ -254,7 +255,7 @@ def rename_chat_session(
@router.patch("/chat-session/{session_id}")
def patch_chat_session(
session_id: int,
session_id: UUID,
chat_session_update_req: ChatSessionUpdateRequest,
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
@ -271,7 +272,7 @@ def patch_chat_session(
@router.delete("/delete-chat-session/{session_id}")
def delete_chat_session_by_id(
session_id: int,
session_id: UUID,
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
) -> None:

View File

@ -1,5 +1,6 @@
from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import BaseModel
from pydantic import model_validator
@ -34,7 +35,7 @@ class SimpleQueryRequest(BaseModel):
class UpdateChatSessionThreadRequest(BaseModel):
# If not specified, use Danswer default persona
chat_session_id: int
chat_session_id: UUID
new_alternate_model: str
@ -45,7 +46,7 @@ class ChatSessionCreationRequest(BaseModel):
class CreateChatSessionID(BaseModel):
chat_session_id: int
chat_session_id: UUID
class ChatFeedbackRequest(BaseModel):
@ -75,7 +76,7 @@ Currently the different branches are generated by changing the search query
class CreateChatMessageRequest(ChunkContext):
"""Before creating messages, be sure to create a chat_session and get an id"""
chat_session_id: int
chat_session_id: UUID
# This is the primary-key (unique identifier) for the previous message of the tree
parent_message_id: int | None
# New message contents
@ -115,13 +116,18 @@ class CreateChatMessageRequest(ChunkContext):
)
return self
def model_dump(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
data = super().model_dump(*args, **kwargs)
data["chat_session_id"] = str(data["chat_session_id"])
return data
class ChatMessageIdentifier(BaseModel):
message_id: int
class ChatRenameRequest(BaseModel):
chat_session_id: int
chat_session_id: UUID
name: str | None = None
@ -134,7 +140,7 @@ class RenameChatSessionResponse(BaseModel):
class ChatSessionDetails(BaseModel):
id: int
id: UUID
name: str
persona_id: int | None = None
time_created: str
@ -175,7 +181,7 @@ class ChatMessageDetail(BaseModel):
overridden_model: str | None
alternate_assistant_id: int | None = None
# Dict mapping citation number to db_doc_id
chat_session_id: int | None = None
chat_session_id: UUID | None = None
citations: dict[int, int] | None = None
files: list[FileDescriptor]
tool_calls: list[ToolCallFinalResult]
@ -187,14 +193,14 @@ class ChatMessageDetail(BaseModel):
class SearchSessionDetailResponse(BaseModel):
search_session_id: int
search_session_id: UUID
description: str
documents: list[SearchDoc]
messages: list[ChatMessageDetail]
class ChatSessionDetailResponse(BaseModel):
chat_session_id: int
chat_session_id: UUID
description: str
persona_id: int | None = None
persona_name: str | None

View File

@ -1,3 +1,5 @@
from uuid import UUID
from fastapi import APIRouter
from fastapi import Depends
from fastapi import HTTPException
@ -186,7 +188,7 @@ def get_user_search_sessions(
@basic_router.get("/search-session/{session_id}")
def get_search_session(
session_id: int,
session_id: UUID,
is_shared: bool = False,
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),

View File

@ -1,4 +1,5 @@
from typing import Any
from uuid import UUID
from pydantic import BaseModel
from pydantic import model_validator
@ -40,7 +41,7 @@ class ToolCallFinalResult(ToolCallKickoff):
class DynamicSchemaInfo(BaseModel):
chat_session_id: int | None
chat_session_id: UUID | None
message_id: int | None

View File

@ -42,7 +42,7 @@ def get_empty_chat_messages_entries__paginated(
message_skeletons.append(
ChatMessageSkeleton(
message_id=chat_session.id,
message_id=message.id,
chat_session_id=chat_session.id,
user_id=str(chat_session.user_id) if chat_session.user_id else None,
flow_type=flow_type,

View File

@ -1,3 +1,5 @@
from uuid import UUID
from pydantic import BaseModel
from pydantic import Field
@ -36,7 +38,7 @@ class BasicCreateChatMessageRequest(ChunkContext):
Note, for simplicity this option only allows for a single linear chain of messages
"""
chat_session_id: int
chat_session_id: UUID
# New message contents
message: str
# Defaults to using retrieval with no additional filters

View File

@ -4,6 +4,7 @@ from datetime import datetime
from datetime import timedelta
from datetime import timezone
from typing import Literal
from uuid import UUID
from fastapi import APIRouter
from fastapi import Depends
@ -83,7 +84,7 @@ class MessageSnapshot(BaseModel):
class ChatSessionMinimal(BaseModel):
id: int
id: UUID
user_email: str
name: str | None
first_user_message: str
@ -95,7 +96,7 @@ class ChatSessionMinimal(BaseModel):
class ChatSessionSnapshot(BaseModel):
id: int
id: UUID
user_email: str
name: str | None
messages: list[MessageSnapshot]
@ -105,7 +106,7 @@ class ChatSessionSnapshot(BaseModel):
class QuestionAnswerPairSnapshot(BaseModel):
chat_session_id: int
chat_session_id: UUID
# 1-indexed message number in the chat_session
# e.g. the first message pair in the chat_session is 1, the second is 2, etc.
message_pair_num: int
@ -350,7 +351,7 @@ def get_chat_session_history(
@router.get("/admin/chat-session-history/{chat_session_id}")
def get_chat_session_admin(
chat_session_id: int,
chat_session_id: UUID,
_: User | None = Depends(current_admin_user),
db_session: Session = Depends(get_session),
) -> ChatSessionSnapshot:

View File

@ -1,5 +1,6 @@
from datetime import datetime
from enum import Enum
from uuid import UUID
from pydantic import BaseModel
@ -14,7 +15,7 @@ class FlowType(str, Enum):
class ChatMessageSkeleton(BaseModel):
message_id: int
chat_session_id: int
chat_session_id: UUID
user_id: str | None
flow_type: FlowType
time_sent: datetime

View File

@ -1,4 +1,5 @@
import json
from uuid import UUID
import requests
from requests.models import Response
@ -44,7 +45,7 @@ class ChatSessionManager:
@staticmethod
def send_message(
chat_session_id: int,
chat_session_id: UUID,
message: str,
parent_message_id: int | None = None,
user_performing_action: DATestUser | None = None,

View File

@ -123,14 +123,14 @@ class DATestPersona(BaseModel):
#
class DATestChatSession(BaseModel):
id: int
id: UUID
persona_id: int
description: str
class DATestChatMessage(BaseModel):
id: str | None = None
chat_session_id: int
chat_session_id: UUID
parent_message_id: str | None
message: str
response: str

View File

@ -1,4 +1,5 @@
import unittest
import uuid
from typing import Any
from unittest.mock import patch
@ -73,7 +74,7 @@ class TestCustomTool(unittest.TestCase):
}
validate_openapi_schema(self.openapi_schema)
self.dynamic_schema_info: DynamicSchemaInfo = DynamicSchemaInfo(
chat_session_id=10, message_id=20
chat_session_id=uuid.uuid4(), message_id=20
)
@patch("danswer.tools.custom.custom_tool.requests.request")

View File

@ -145,19 +145,17 @@ export function ChatPage({
const existingChatIdRaw = searchParams.get("chatId");
const currentPersonaId = searchParams.get(SEARCH_PARAM_NAMES.PERSONA_ID);
const existingChatSessionId = existingChatIdRaw
? parseInt(existingChatIdRaw)
: null;
const existingChatSessionId = existingChatIdRaw ? existingChatIdRaw : null;
const selectedChatSession = chatSessions.find(
(chatSession) => chatSession.id === existingChatSessionId
);
const chatSessionIdRef = useRef<number | null>(existingChatSessionId);
const chatSessionIdRef = useRef<string | null>(existingChatSessionId);
// Only updates on session load (ie. rename / switching chat session)
// Useful for determining which session has been loaded (i.e. still on `new, empty session` or `previous session`)
const loadedIdSessionRef = useRef<number | null>(existingChatSessionId);
const loadedIdSessionRef = useRef<string | null>(existingChatSessionId);
// Assistants in order
const { finalAssistants } = useMemo(() => {
@ -448,11 +446,11 @@ export function ChatPage({
);
const [completeMessageDetail, setCompleteMessageDetail] = useState<
Map<number | null, Map<number, Message>>
Map<string | null, Map<number, Message>>
>(new Map());
const updateCompleteMessageDetail = (
sessionId: number | null,
sessionId: string | null,
messageMap: Map<number, Message>
) => {
setCompleteMessageDetail((prevState) => {
@ -463,13 +461,13 @@ export function ChatPage({
};
const currentMessageMap = (
messageDetail: Map<number | null, Map<number, Message>>
messageDetail: Map<string | null, Map<number, Message>>
) => {
return (
messageDetail.get(chatSessionIdRef.current) || new Map<number, Message>()
);
};
const currentSessionId = (): number => {
const currentSessionId = (): string => {
return chatSessionIdRef.current!;
};
@ -484,7 +482,7 @@ export function ChatPage({
// if calling this function repeatedly with short delay, stay may not update in time
// and result in weird behavipr
completeMessageMapOverride?: Map<number, Message> | null;
chatSessionId?: number;
chatSessionId?: string;
replacementsMap?: Map<number, number> | null;
makeLatestChildMessage?: boolean;
}) => {
@ -559,23 +557,23 @@ export function ChatPage({
const [submittedMessage, setSubmittedMessage] = useState("");
const [chatState, setChatState] = useState<Map<number | null, ChatState>>(
const [chatState, setChatState] = useState<Map<string | null, ChatState>>(
new Map([[chatSessionIdRef.current, "input"]])
);
const [regenerationState, setRegenerationState] = useState<
Map<number | null, RegenerationState | null>
Map<string | null, RegenerationState | null>
>(new Map([[null, null]]));
const [abortControllers, setAbortControllers] = useState<
Map<number | null, AbortController>
Map<string | null, AbortController>
>(new Map());
// Updates "null" session values to new session id for
// regeneration, chat, and abort controller state, messagehistory
const updateStatesWithNewSessionId = (newSessionId: number) => {
const updateStatesWithNewSessionId = (newSessionId: string) => {
const updateState = (
setState: Dispatch<SetStateAction<Map<number | null, any>>>,
setState: Dispatch<SetStateAction<Map<string | null, any>>>,
defaultValue?: any
) => {
setState((prevState) => {
@ -610,7 +608,7 @@ export function ChatPage({
chatSessionIdRef.current = newSessionId;
};
const updateChatState = (newState: ChatState, sessionId?: number | null) => {
const updateChatState = (newState: ChatState, sessionId?: string | null) => {
setChatState((prevState) => {
const newChatState = new Map(prevState);
newChatState.set(
@ -635,7 +633,7 @@ export function ChatPage({
const updateRegenerationState = (
newState: RegenerationState | null,
sessionId?: number | null
sessionId?: string | null
) => {
setRegenerationState((prevState) => {
const newRegenerationState = new Map(prevState);
@ -647,18 +645,18 @@ export function ChatPage({
});
};
const resetRegenerationState = (sessionId?: number | null) => {
const resetRegenerationState = (sessionId?: string | null) => {
updateRegenerationState(null, sessionId);
};
const currentRegenerationState = (): RegenerationState | null => {
return regenerationState.get(currentSessionId()) || null;
};
const [canContinue, setCanContinue] = useState<Map<number | null, boolean>>(
const [canContinue, setCanContinue] = useState<Map<string | null, boolean>>(
new Map([[null, false]])
);
const updateCanContinue = (newState: boolean, sessionId?: number | null) => {
const updateCanContinue = (newState: boolean, sessionId?: string | null) => {
setCanContinue((prevState) => {
const newCanContinueState = new Map(prevState);
newCanContinueState.set(
@ -1003,7 +1001,7 @@ export function ChatPage({
setAlternativeGeneratingAssistant(alternativeAssistantOverride);
clientScrollToBottom();
let currChatSessionId: number;
let currChatSessionId: string;
const isNewSession = chatSessionIdRef.current === null;
const searchParamBasedChatSessionName =
searchParams.get(SEARCH_PARAM_NAMES.TITLE) || null;
@ -1014,7 +1012,7 @@ export function ChatPage({
searchParamBasedChatSessionName
);
} else {
currChatSessionId = chatSessionIdRef.current as number;
currChatSessionId = chatSessionIdRef.current as string;
}
frozenSessionId = currChatSessionId;
@ -1598,7 +1596,7 @@ export function ChatPage({
}
const [visibleRange, setVisibleRange] = useState<
Map<number | null, VisibleRange>
Map<string | null, VisibleRange>
>(() => {
const initialRange: VisibleRange = {
start: 0,

View File

@ -30,7 +30,7 @@ const FolderItem = ({
initiallySelected,
}: {
folder: Folder;
currentChatId?: number;
currentChatId?: string;
isInitiallyExpanded: boolean;
initiallySelected: boolean;
}) => {
@ -145,10 +145,7 @@ const FolderItem = ({
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(false);
const chatSessionId = parseInt(
event.dataTransfer.getData(CHAT_SESSION_ID_KEY),
10
);
const chatSessionId = event.dataTransfer.getData(CHAT_SESSION_ID_KEY);
try {
await addChatToFolder(folder.folder_id, chatSessionId);
router.refresh(); // Refresh to show the updated folder contents
@ -302,7 +299,7 @@ export const FolderList = ({
newFolderId,
}: {
folders: Folder[];
currentChatId?: number;
currentChatId?: string;
openedFolders?: { [key: number]: boolean };
newFolderId: number | null;
}) => {

View File

@ -17,7 +17,7 @@ export async function createFolder(folderName: string): Promise<number> {
// Function to add a chat session to a folder
export async function addChatToFolder(
folderId: number,
chatSessionId: number
chatSessionId: string
): Promise<void> {
const response = await fetch(`/api/folder/${folderId}/add-chat-session`, {
method: "POST",
@ -34,7 +34,7 @@ export async function addChatToFolder(
// Function to remove a chat session from a folder
export async function removeChatFromFolder(
folderId: number,
chatSessionId: number
chatSessionId: string
): Promise<void> {
const response = await fetch(`/api/folder/${folderId}/remove-chat-session`, {
method: "POST",

View File

@ -86,7 +86,7 @@ export function ChatInputBar({
setFiles: (files: FileDescriptor[]) => void;
handleFileUpload: (files: File[]) => void;
textAreaRef: React.RefObject<HTMLTextAreaElement>;
chatSessionId?: number;
chatSessionId?: string;
refreshUser: () => void;
}) {
useEffect(() => {

View File

@ -60,7 +60,7 @@ export interface ToolCallFinalResult {
}
export interface ChatSession {
id: number;
id: string;
name: string;
persona_id: number;
time_created: string;
@ -70,7 +70,7 @@ export interface ChatSession {
}
export interface SearchSession {
search_session_id: number;
search_session_id: string;
documents: SearchDanswerDocument[];
messages: BackendMessage[];
description: string;
@ -97,7 +97,7 @@ export interface Message {
}
export interface BackendChatSession {
chat_session_id: number;
chat_session_id: string;
description: string;
persona_id: number;
persona_name: string;
@ -110,7 +110,7 @@ export interface BackendChatSession {
export interface BackendMessage {
message_id: number;
comments: any;
chat_session_id: number;
chat_session_id: string;
parent_message: number | null;
latest_child_message: number | null;
message: string;

View File

@ -55,7 +55,7 @@ export function getChatRetentionInfo(
}
export async function updateModelOverrideForChatSession(
chatSessionId: number,
chatSessionId: string,
newAlternateModel: string
) {
const response = await fetch("/api/chat/update-chat-session-model", {
@ -74,7 +74,7 @@ export async function updateModelOverrideForChatSession(
export async function createChatSession(
personaId: number,
description: string | null
): Promise<number> {
): Promise<string> {
const createChatSessionResponse = await fetch(
"/api/chat/create-chat-session",
{
@ -131,7 +131,7 @@ export async function* sendMessage({
message: string;
fileDescriptors: FileDescriptor[];
parentMessageId: number | null;
chatSessionId: number;
chatSessionId: string;
promptId: number | null | undefined;
filters: Filters | null;
selectedDocumentIds: number[] | null;
@ -203,7 +203,7 @@ export async function* sendMessage({
yield* handleSSEStream<PacketType>(response);
}
export async function nameChatSession(chatSessionId: number, message: string) {
export async function nameChatSession(chatSessionId: string, message: string) {
const response = await fetch("/api/chat/rename-chat-session", {
method: "PUT",
headers: {
@ -252,7 +252,7 @@ export async function handleChatFeedback(
return response;
}
export async function renameChatSession(
chatSessionId: number,
chatSessionId: string,
newName: string
) {
const response = await fetch(`/api/chat/rename-chat-session`, {
@ -269,7 +269,7 @@ export async function renameChatSession(
return response;
}
export async function deleteChatSession(chatSessionId: number) {
export async function deleteChatSession(chatSessionId: string) {
const response = await fetch(
`/api/chat/delete-chat-session/${chatSessionId}`,
{
@ -348,6 +348,7 @@ export function getCitedDocumentsFromMessage(message: Message) {
}
export function groupSessionsByDateRange(chatSessions: ChatSession[]) {
console.log(chatSessions);
const today = new Date();
today.setHours(0, 0, 0, 0); // Set to start of today for accurate comparison
@ -584,7 +585,7 @@ const PARAMS_TO_SKIP = [
export function buildChatUrl(
existingSearchParams: ReadonlyURLSearchParams,
chatSessionId: number | null,
chatSessionId: string | null,
personaId: number | null,
search?: boolean
) {

View File

@ -6,12 +6,12 @@ import { ChatSessionSharedStatus } from "../interfaces";
import { FiCopy } from "react-icons/fi";
import { CopyButton } from "@/components/CopyButton";
function buildShareLink(chatSessionId: number) {
function buildShareLink(chatSessionId: string) {
const baseUrl = `${window.location.protocol}//${window.location.host}`;
return `${baseUrl}/chat/shared/${chatSessionId}`;
}
async function generateShareLink(chatSessionId: number) {
async function generateShareLink(chatSessionId: string) {
const response = await fetch(`/api/chat/chat-session/${chatSessionId}`, {
method: "PATCH",
headers: {
@ -26,7 +26,7 @@ async function generateShareLink(chatSessionId: number) {
return null;
}
async function deleteShareLink(chatSessionId: number) {
async function deleteShareLink(chatSessionId: string) {
const response = await fetch(`/api/chat/chat-session/${chatSessionId}`, {
method: "PATCH",
headers: {
@ -44,7 +44,7 @@ export function ShareChatSessionModal({
onShare,
onClose,
}: {
chatSessionId: number;
chatSessionId: string;
existingSharedStatus: ChatSessionSharedStatus;
onShare?: (shared: boolean) => void;
onClose: () => void;

View File

@ -14,7 +14,7 @@ interface LlmTabProps {
llmOverrideManager: LlmOverrideManager;
currentLlm: string;
openModelSettings: () => void;
chatSessionId?: number;
chatSessionId?: string;
close: () => void;
currentAssistant: Persona;
}

View File

@ -23,7 +23,7 @@ export function PagesTab({
}: {
page: pageType;
existingChats?: ChatSession[];
currentChatId?: number;
currentChatId?: string;
folders?: Folder[];
openedFolders?: { [key: number]: boolean };
closeSidebar?: () => void;
@ -44,10 +44,7 @@ export function PagesTab({
) => {
event.preventDefault();
setIsDragOver(false); // Reset drag over state on drop
const chatSessionId = parseInt(
event.dataTransfer.getData(CHAT_SESSION_ID_KEY),
10
);
const chatSessionId = event.dataTransfer.getData(CHAT_SESSION_ID_KEY);
const folderId = event.dataTransfer.getData(FOLDER_ID_KEY);
if (folderId) {

View File

@ -48,7 +48,7 @@ export default async function Page({ params }: { params: { chatId: string } }) {
const user = results[1] as User | null;
const chatSession = results[2] as BackendChatSession | null;
const assistantsResponse = results[3] as FetchAssistantsResponse | null;
const [availableAssistants, _] = assistantsResponse ?? [[], null];
const [availableAssistants, error] = assistantsResponse ?? [[], null];
const authDisabled = authTypeMetadata?.authType === "disabled";
if (!authDisabled && !user) {
@ -58,7 +58,6 @@ export default async function Page({ params }: { params: { chatId: string } }) {
if (user && !user.is_verified && authTypeMetadata?.requiresVerification) {
return redirect("/auth/waiting-on-verification");
}
const persona: Persona =
chatSession?.persona_id && availableAssistants?.length
? (availableAssistants.find((p) => p.id === chatSession.persona_id) ??
@ -72,7 +71,7 @@ export default async function Page({ params }: { params: { chatId: string } }) {
</div>
<div className="flex relative bg-background text-default overflow-hidden pt-16 h-screen">
<SharedChatDisplay chatSession={chatSession} persona={persona!} />
<SharedChatDisplay chatSession={chatSession} persona={persona} />
</div>
</div>
);

View File

@ -168,13 +168,10 @@ export const SearchSection = ({
});
const searchParams = useSearchParams();
const existingSearchIdRaw = searchParams.get("searchId");
const existingSearchessionId = existingSearchIdRaw
? parseInt(existingSearchIdRaw)
: null;
const existingSearchessionId = searchParams.get("searchId");
useEffect(() => {
if (existingSearchIdRaw == null) {
if (existingSearchessionId == null) {
return;
}
function extractFirstMessageByType(
@ -207,7 +204,7 @@ export const SearchSection = ({
quotes: null,
selectedDocIndices: null,
error: null,
messageId: existingSearchIdRaw ? parseInt(existingSearchIdRaw) : null,
messageId: searchSession.messages[0].message_id,
suggestedFlowType: null,
additional_relevance: undefined,
};
@ -219,7 +216,7 @@ export const SearchSection = ({
}
}
initialSessionFetch();
}, [existingSearchessionId, existingSearchIdRaw]);
}, [existingSearchessionId]);
// Overrides for default behavior that only last a single query
const [defaultOverrides, setDefaultOverrides] =
@ -328,7 +325,7 @@ export const SearchSection = ({
};
const updateMessageAndThreadId = (
messageId: number,
chat_session_id: number
chat_session_id: string
) => {
setSearchResponse((prevState) => ({
...(prevState || initialSearchResponse),

View File

@ -136,8 +136,10 @@ export async function fetchChatData(searchParams: {
);
}
// Larger ID -> created later
chatSessions.sort((a, b) => (a.id > b.id ? -1 : 1));
chatSessions.sort(
(a, b) =>
new Date(b.time_created).getTime() - new Date(a.time_created).getTime()
);
let documentSets: DocumentSet[] = [];
if (documentSetsResponse?.ok) {

View File

@ -152,7 +152,7 @@ export interface SearchRequestArgs {
updateError: (error: string) => void;
updateMessageAndThreadId: (
messageId: number,
chat_session_id: number
chat_session_id: string
) => void;
finishedSearching: () => void;
updateComments: (comments: any) => void;