Chainlit / chainlit

Build Conversational AI in minutes ⚡️
https://docs.chainlit.io
Apache License 2.0
6.86k stars 903 forks source link

Handle session ID does not exist in the user_sessions dictionary #1364

Open gsornsen opened 1 week ago

gsornsen commented 1 week ago

When trying to resume a chat using the SQLAlchemyDataLayer with SQLite as the database, and the following SQL to create the tables with:

as UUID, JSONB, TEXT[], and BOOLEAN are not support types in SQLite:

create_tables_sql = """
        CREATE TABLE IF NOT EXISTS users (
            "id" TEXT PRIMARY KEY,
            "identifier" TEXT NOT NULL UNIQUE,
            "metadata" TEXT NOT NULL,
            "createdAt" TEXT
        );

        CREATE TABLE IF NOT EXISTS threads (
            "id" TEXT PRIMARY KEY,
            "createdAt" TEXT,
            "name" TEXT,
            "userId" TEXT,
            "userIdentifier" TEXT,
            "tags" TEXT,
            "metadata" TEXT,
            FOREIGN KEY ("userId") REFERENCES users("id") ON DELETE CASCADE
        );

        CREATE TABLE IF NOT EXISTS steps (
            "id" TEXT PRIMARY KEY,
            "name" TEXT NOT NULL,
            "type" TEXT NOT NULL,
            "threadId" TEXT NOT NULL,
            "parentId" TEXT,
            "disableFeedback" INTEGER NOT NULL DEFAULT 0,
            "streaming" INTEGER NOT NULL,
            "waitForAnswer" INTEGER,
            "isError" INTEGER,
            "metadata" TEXT,
            "tags" TEXT,
            "input" TEXT,
            "output" TEXT,
            "createdAt" TEXT,
            "start" TEXT,
            "end" TEXT,
            "generation" TEXT,
            "showInput" TEXT,
            "language" TEXT,
            "indent" INTEGER
        );

        CREATE TABLE IF NOT EXISTS elements (
            "id" TEXT PRIMARY KEY,
            "threadId" TEXT,
            "type" TEXT,
            "url" TEXT,
            "chainlitKey" TEXT,
            "name" TEXT NOT NULL,
            "display" TEXT,
            "objectKey" TEXT,
            "size" TEXT,
            "page" INTEGER,
            "language" TEXT,
            "forId" TEXT,
            "mime" TEXT
        );

        CREATE TABLE IF NOT EXISTS feedbacks (
            "id" TEXT PRIMARY KEY,
            "forId" TEXT NOT NULL,
            "threadId" TEXT NOT NULL,
            "value" INTEGER NOT NULL,
            "comment" TEXT
        );
        """

I'd get the following AttributeError:

2024-09-21 16:18:23 - Task exception was never retrieved
future: <Task finished name='Task-78' coro=<AsyncServer._handle_event_internal() done, defined at /home/gerald/git/secbot/.venv/lib/python3.10/site-packages/socketio/async_server.py:608> exception=AttributeError("'str' object has no attribute 'copy'")>
Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/tasks.py", line 232, in __step
    result = coro.send(None)
  File "/home/gerald/git/secbot/.venv/lib/python3.10/site-packages/socketio/async_server.py", line 610, in _handle_event_internal
    r = await server._trigger_event(data[0], namespace, sid, *data[1:])
  File "/home/gerald/git/secbot/.venv/lib/python3.10/site-packages/socketio/async_server.py", line 637, in _trigger_event
    ret = await handler(*args)
  File "/home/gerald/git/secbot/.venv/lib/python3.10/site-packages/chainlit/socket.py", line 179, in connection_successful
    thread = await resume_thread(context.session)
  File "/home/gerald/git/secbot/.venv/lib/python3.10/site-packages/chainlit/socket.py", line 58, in resume_thread
    user_sessions[session.id] = metadata.copy()
AttributeError: 'str' object has no attribute 'copy'

The AttributeError appeared to come from:

    if user_is_author:
        metadata = thread.get("metadata") or {}
        user_sessions[session.id] = metadata.copy()

Modifying to:

    if user_is_author:
        metadata = thread.get("metadata") or {}
        print(metadata)
        user_sessions[session.id] = metadata.copy()

Yielded:

{"memory": null, "id": "3cd2ee0c-a271-4ebf-bf4d-fd3fdfb0b4ea", "env": "{\"api_key=<redacted>\"}", "chat_settings": {}, "user": null, "chat_profile": null, "http_referer": "http://localhost:8080/thread/4eaaee1c-d630-488d-b15d-1fdf36610606", "client_type": "webapp", "languages": "en-US,en;q=0.9", "runnable": null, "metadata": {}}

Modifying to:

    if user_is_author:
        metadata = thread.get("metadata") or {}
        print(f"User sessions: {user_sessions}")
        user_sessions[session.id] = metadata.copy()

Yieled:

User sessions: {}

With the changes introduced in the PR, all of the persisted storage functionality works with SQLite as the database using the SQLAlchemyDataLayer and all of the cypress and backend tests passed locally.

Please point me in another direction if there's a better way to handle this elsewhere! I'm fairly new to using Chainlit and I'm a big fan.

dokterbob commented 5 days ago

I propose we try and tackle this one as part of #1365