diff --git a/.github/actions/pnpm-node-install/action.yaml b/.github/actions/pnpm-node-install/action.yaml index d3bd27338d..5cbb111073 100644 --- a/.github/actions/pnpm-node-install/action.yaml +++ b/.github/actions/pnpm-node-install/action.yaml @@ -5,11 +5,18 @@ inputs: node-version: description: Node.js version required: true + default: '22.7.0' pnpm-version: description: pnpm version required: true + default: '9.7.0' + pnpm-skip-install: + description: Skip install. + required: false + default: 'false' pnpm-install-args: description: Extra arguments for pnpm install, e.g. --no-frozen-lockfile. + default: '--frozen-lockfile' runs: using: composite @@ -25,3 +32,5 @@ runs: - name: Install JS dependencies run: pnpm install ${{ inputs.pnpm-install-args }} shell: bash + # Skip install if pnpm-skip-install is true + if: ${{ inputs.pnpm-skip-install != 'true' }} diff --git a/.github/actions/poetry-python-install/action.yaml b/.github/actions/poetry-python-install/action.yaml index f423e8be1f..c5cc8548cc 100644 --- a/.github/actions/poetry-python-install/action.yaml +++ b/.github/actions/poetry-python-install/action.yaml @@ -5,9 +5,11 @@ inputs: python-version: description: Python version required: true + default: '3.9' poetry-version: description: Poetry version required: true + default: '1.8.3' poetry-working-directory: description: Working directory for poetry command. required: false diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6304522dd6..b2c6d7dda3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,9 +4,9 @@ on: workflow_call: workflow_dispatch: pull_request: - branches: [main, dev] + branches: [main, dev, 'release/**'] push: - branches: [main, dev] + branches: [main, dev, 'release/**'] permissions: read-all @@ -20,10 +20,13 @@ jobs: e2e-tests: uses: ./.github/workflows/e2e-tests.yaml secrets: inherit + lint-ui: + uses: ./.github/workflows/lint-ui.yaml + secrets: inherit ci: runs-on: ubuntu-latest name: Run CI - needs: [mypy, pytest, e2e-tests] + needs: [mypy, pytest, lint-ui, e2e-tests] steps: - name: Done run: echo "Done" diff --git a/.github/workflows/e2e-tests.yaml b/.github/workflows/e2e-tests.yaml index c7f704eb92..81b701b962 100644 --- a/.github/workflows/e2e-tests.yaml +++ b/.github/workflows/e2e-tests.yaml @@ -13,22 +13,20 @@ jobs: env: BACKEND_DIR: ./backend steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/pnpm-node-install name: Install Node, pnpm and dependencies. with: - node-version: 22.7.0 - pnpm-version: 9.7.0 - pnpm-install-args: --no-frozen-lockfile + pnpm-skip-install: true + - name: Install depdendencies and Cypress + uses: cypress-io/github-action@v6 + with: + runTests: false - uses: ./.github/actions/poetry-python-install name: Install Python, poetry and Python dependencies with: - python-version: 3.9 - poetry-version: 1.8.3 poetry-working-directory: ${{ env.BACKEND_DIR }} poetry-install-args: --with tests - - name: Lint UI - run: pnpm run lintUi - name: Run tests env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} diff --git a/.github/workflows/lint-ui.yaml b/.github/workflows/lint-ui.yaml new file mode 100644 index 0000000000..c4562def0b --- /dev/null +++ b/.github/workflows/lint-ui.yaml @@ -0,0 +1,17 @@ +name: LintUI + +on: [workflow_call] + +permissions: read-all + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/pnpm-node-install + name: Install Node, pnpm and dependencies. + - name: Build UI + run: pnpm run buildUi + - name: Lint UI + run: pnpm run lintUi diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index fff0c4bfe6..4ff0cdf49d 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -10,12 +10,10 @@ jobs: env: BACKEND_DIR: ./backend steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/poetry-python-install name: Install Python, poetry and Python dependencies with: - python-version: 3.9 - poetry-version: 1.8.3 poetry-install-args: --with tests --with mypy --with custom-data --no-root poetry-working-directory: ${{ env.BACKEND_DIR }} - name: Run Mypy diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 8dc7708b4a..5e420edea9 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -23,25 +23,20 @@ jobs: contents: read id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: main - uses: ./.github/actions/pnpm-node-install name: Install Node, pnpm and dependencies. with: - node-version: 22.7.0 - pnpm-version: 9.7.0 pnpm-install-args: --no-frozen-lockfile - uses: ./.github/actions/poetry-python-install name: Install Python, poetry and Python dependencies with: - python-version: 3.9 - poetry-version: 1.8.3 poetry-working-directory: ${{ env.BACKEND_DIR }} - - name: Copy readme to backend - run: cp README.md backend/ - - name: Build chainlit - run: pnpm run build + - name: Build Python distribution + run: poetry self add poetry-plugin-ignore-build-script && poetry build --ignore-build-script + working-directory: ${{ env.BACKEND_DIR }} - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 70436c35a2..e98c6260c6 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -14,25 +14,18 @@ jobs: env: BACKEND_DIR: ./backend steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: ./.github/actions/pnpm-node-install + name: Install Node, pnpm and dependencies. - uses: ./.github/actions/poetry-python-install name: Install Python, poetry and Python dependencies with: python-version: ${{ matrix.python-version }} - poetry-version: 1.8.3 - poetry-install-args: --with tests --with mypy --with custom-data --no-root + poetry-install-args: --with tests --with mypy --with custom-data poetry-working-directory: ${{ env.BACKEND_DIR }} - name: Install fastapi ${{ matrix.fastapi-version }} run: poetry add fastapi@^${{ matrix.fastapi-version}} working-directory: ${{ env.BACKEND_DIR }} - - uses: ./.github/actions/pnpm-node-install - name: Install Node, pnpm and dependencies. - with: - node-version: 22.7.0 - pnpm-version: 9.7.0 - pnpm-install-args: --no-frozen-lockfile - - name: Build UI - run: pnpm run buildUi - name: Run Pytest run: poetry run pytest --cov=chainlit/ working-directory: ${{ env.BACKEND_DIR }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 608b5cb9b0..eb58059a0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,110 @@ All notable changes to Chainlit will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.3.1] - 2024-10-25 + +### Security Advisory + +- **IMPORTANT**: This release temporarily reverts the file access security improvements from 1.3.0 to restore element functionality. The element feature currently has a known security vulnerability that could allow unauthorized access to files. We strongly recommend against using elements in production environments until the next release. +- A comprehensive security fix using HTTP-only cookie authentication will be implemented in an upcoming release. + +### Changed + +- Reverted authentication requirements for file access endpoints to restore element functionality (#1474) + +### Development + +- Work in progress on implementing HTTP-only cookie authentication for proper security (#1472) + +## [1.3.0] - 2024-10-22 + +### Security + +- Fixed critical endpoint security vulnerabilities (#1441) +- Enhanced authentication for file-related endpoints (#1431) +- Upgraded frontend and backend dependencies to address security issues (#1431) + +### Added + +- SQLite support in SQLAlchemy integration (#1319) +- Support for IETF BCP 47 language tags, enabling localized languages like es-419 (#1399) +- Environment variables `OAUTH__PROMPT` and `OAUTH_PROMPT` to +override oauth prompt parameter. Enabling users to explicitly enable login/consent prompts for oauth, e.g. `OAUTH_PROMPT=consent` to prevent automatic re-login. (#1362, #1456). +- Added `get_element()` method to SQLAlchemyDataLayer (#1346) + +### Changed + +- Bumped LiteralAI dependency to version 0.0.625 (#1376) +- Optimized LiteralDataLayer for improved performance and consistency (#1376) +- Refactored context handling in SQLAlchemy data layer (#1319) +- Updated package metadata with correct authors, license, and documentation links (#1413) +- Enhanced GitHub Actions workflow with restricted permissions (#1349) + +### Fixed + +- Resolved dialog boxes extending beyond window bounds (#1446) +- Fixed tasklist functionality when Chainlit is submounted (#1433) +- Corrected handling of `display_name` in PersistentUser during authentication (#1425) +- Fixed SQLAlchemy identifier quoting (#1395) +- Improved spaces handling in avatar filenames (#1418) + +### Development + +- Implemented extensive test coverage for LiteralDataLayer and SQLAlchemyDataLayer +- Added comprehensive unit tests for file-related endpoints +- Enhanced code organization and import structure +- Improved Python code style and linting (#1353) +- Resolved various small text and documentation issues (#1347, #1348) + +## [2.0.dev2] - 2024-10-25 + +### Security Advisory + +- **IMPORTANT**: This release temporarily reverts the file access security improvements from 2.0.dev1 to restore element functionality. The element feature currently has a known security vulnerability that could allow unauthorized access to files. We strongly recommend against using elements in production environments until the next release. +- A comprehensive security fix using HTTP-only cookie authentication will be implemented in an upcoming release. + +### Changed + +- Reverted authentication requirements for file access endpoints to restore element functionality (#1474) + +### Development + +- Work in progress on implementing HTTP-only cookie authentication for proper security (#1472) + +## [2.0.dev1] - 2024-10-22 + +### Added + +- Interactive DataFrame display component using MUI Data Grid (#1373) +- Optional websocket connection in react-client (#1379) +- Current URL in message payload (#1403) +- Improved image interaction - clicking opens popup with download option (#1402) +- Configurable user session timeout (#1032) + +### Security + +- Fixed file access vulnerability in get_file and upload_file endpoints (#1441) +- Added authentication to /project/file endpoint (#1441) +- Addressed security vulnerabilities in frontend dependencies (#1431, #1414) + +### Fixed + +- Dialog boxes extending beyond window (#1446) +- Allow empty chat input when submitting attachments (#1261) +- Tasklist when Chainlit is submounted (#1433) +- Spaces in avatar filenames (#1418) +- Step argument input and concurrency issues (#1409) +- Display_name copying to PersistentUser during authentication (#1425) + +### Development + +- Refactored storage clients into separate modules (#1363) +- Support for IETF BCP 47 language tags (#1399) +- Improved GitHub Actions workflows and build process (#1445) +- Direct installation from GitHub support (#1423) +- Extended package metadata with homepage and documentation links (#1413) +- Various backend fixes and code cleanup (#1432) + ## [2.0.dev0] - 2024-10-08 ### Breaking Changes @@ -40,36 +144,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added new wavtools directory with various audio processing utilities - Implemented new AudioWorklet processors for more efficient audio handling -## [1.3.0rc0] - 2024-10-02 - -### Added - -- SQLite support in SQLAlchemy integration (#1137) -- Extensive test coverage for LiteralDataLayer and SQLAlchemyDataLayer -- `get_element()` method to SQLAlchemyDataLayer (#1346) - -### Changed - -- Bumped LiteralAI dependency to version 0.0.625 (#1376) -- Refactored LiteralDataLayer for improved performance and consistency -- Refactored context handling in SQLAlchemy data layer (#1319) -- Enhanced GitHub Actions workflow with restricted permissions (#1349) - -### Fixed - -- Resolved issues with SQLite database support (#1137) -- Addressed automatic OAuth login after logout (#1362) -- Various code style and linting improvements (#1353, #1348, #1347) - -### Development - -- Implemented LiteralToChainlitConverter class for handling conversions -- Added comprehensive unit tests for data layer components -- Improved import structure and removed unused imports -- Updated README with latest project information (#1351) - -We encourage users to thoroughly test this release candidate, particularly the LiteralAI integration and history features, and provide feedback before the final 1.3.0 release. - ## [1.2.0] - 2024-09-16 ### Security diff --git a/backend/README.md b/backend/README.md index ffd682b9af..ab9aab12c1 100644 --- a/backend/README.md +++ b/backend/README.md @@ -18,7 +18,7 @@ Chainlit is an open-source async Python framework which allows developers to bui Full documentation is available [here](https://docs.chainlit.io). You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/), an app built using Chainlit! -> [!NOTE] +> [!NOTE] > Check out [Literal AI](https://literalai.com), our product to monitor and evaluate LLM applications! It works with any Python or TypeScript applications and [seamlessly](https://docs.chainlit.io/data-persistence/overview) with Chainlit by adding a `LITERAL_API_KEY` in your project. > > Chainlit is developed and maintained by the Literal AI team, which is currently focused on expanding the capabilities of Literal AI. While we continue to support and maintain Chainlit, we are also committed to enabling the community to contribute, particularly in areas like integrations and data layers. @@ -43,7 +43,7 @@ If this opens the `hello app` in your browser, you're all set! The latest in-development version can be installed straight from GitHub with: ```sh -pip install git+https://github.com/Chainlit/chainlit.git@dokterbob/build_frontend_on_poetry_build#subdirectory=backend/ +pip install git+https://github.com/Chainlit/chainlit.git#subdirectory=backend/ ``` (Requires Node and pnpm installed on the system.) diff --git a/backend/build.py b/backend/build.py index 2c8377632c..bdbe9cbb3d 100644 --- a/backend/build.py +++ b/backend/build.py @@ -6,7 +6,9 @@ def pnpm_install(project_root, pnpm_path): - subprocess.run([pnpm_path, "install"], cwd=project_root, check=True) + subprocess.run( + [pnpm_path, "install", "--frozen-lockfile"], cwd=project_root, check=True + ) def pnpm_buildui(project_root, pnpm_path): diff --git a/backend/chainlit/auth.py b/backend/chainlit/auth.py index 093d4a7407..8ee0943f84 100644 --- a/backend/chainlit/auth.py +++ b/backend/chainlit/auth.py @@ -52,7 +52,9 @@ def create_jwt(data: User) -> str: to_encode: Dict[str, Any] = data.to_dict() to_encode.update( { - "exp": datetime.utcnow() + timedelta(minutes=60 * 24 * 15), # 15 days + "exp": datetime.utcnow() + timedelta( + seconds=config.project.user_session_timeout + ), } ) encoded_jwt = jwt.encode(to_encode, get_jwt_secret(), algorithm="HS256") diff --git a/backend/chainlit/config.py b/backend/chainlit/config.py index 60bc764b47..ad9c1aaf88 100644 --- a/backend/chainlit/config.py +++ b/backend/chainlit/config.py @@ -62,6 +62,9 @@ # Duration (in seconds) during which the session is saved when the connection is lost session_timeout = 3600 +# Duration (in seconds) of the user session expiry +user_session_timeout = 1296000 # 15 days + # Enable third parties caching (e.g LangChain cache) cache = false @@ -306,6 +309,8 @@ class ProjectSettings(DataClassJsonMixin): # Path to the local chat db # Duration (in seconds) during which the session is saved when the connection is lost session_timeout: int = 3600 + # Duration (in seconds) of the user session expiry + user_session_timeout: int = 1296000 # 15 days # Enable third parties caching (e.g LangChain cache) cache: bool = False # Follow symlink for asset mount (see https://github.com/Chainlit/chainlit/issues/317) @@ -447,7 +452,7 @@ def load_settings(): if not meta or meta.get("generated_by") <= "0.3.0": raise ValueError( - "Your config file is outdated. Please delete it and restart the app to regenerate it." + f"Your config file '{config_file}' is outdated. Please delete it and restart the app to regenerate it." ) lc_cache_path = os.path.join(config_dir, ".langchain.db") diff --git a/backend/chainlit/oauth_providers.py b/backend/chainlit/oauth_providers.py index c383b7592c..5ed9228f51 100644 --- a/backend/chainlit/oauth_providers.py +++ b/backend/chainlit/oauth_providers.py @@ -16,6 +16,7 @@ class OAuthProvider: client_secret: str authorize_url: str authorize_params: Dict[str, str] + default_prompt: Optional[str] = None def is_configured(self): return all([os.environ.get(env) for env in self.env]) @@ -26,6 +27,21 @@ async def get_token(self, code: str, url: str) -> str: async def get_user_info(self, token: str) -> Tuple[Dict[str, str], User]: raise NotImplementedError() + def get_env_prefix(self) -> str: + """Return environment prefix, like AZURE_AD.""" + + return self.id.replace("-", "_").upper() + + def get_prompt(self) -> Optional[str]: + """Return OAuth prompt param.""" + if prompt := os.environ.get(f"OAUTH_{self.get_env_prefix()}_PROMPT"): + return prompt + + if prompt := os.environ.get("OAUTH_PROMPT"): + return prompt + + return self.default_prompt + class GithubOAuthProvider(OAuthProvider): id = "github" @@ -37,9 +53,11 @@ def __init__(self): self.client_secret = os.environ.get("OAUTH_GITHUB_CLIENT_SECRET") self.authorize_params = { "scope": "user:email", - "prompt": "consent", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -96,9 +114,11 @@ def __init__(self): "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email", "response_type": "code", "access_type": "offline", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -164,9 +184,11 @@ def __init__(self): "response_type": "code", "scope": "https://graph.microsoft.com/User.Read", "response_mode": "query", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -249,9 +271,11 @@ def __init__(self): "scope": "https://graph.microsoft.com/User.Read https://graph.microsoft.com/openid", "response_mode": "form_post", "nonce": nonce, - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -329,9 +353,11 @@ def __init__(self): "response_type": "code", "scope": "openid profile email", "response_mode": "query", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + def get_authorization_server_path(self): if not self.authorization_server_id: return "/default" @@ -401,9 +427,11 @@ def __init__(self): "response_type": "code", "scope": "openid profile email", "audience": f"{self.original_domain}/userinfo", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -459,9 +487,11 @@ def __init__(self): "response_type": "code", "scope": "openid profile email", "audience": f"{self.domain}/userinfo", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -518,9 +548,11 @@ def __init__(self): "response_type": "code", "client_id": self.client_id, "scope": "openid profile email", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, @@ -587,9 +619,11 @@ def __init__(self): self.authorize_params = { "scope": "openid profile email", "response_type": "code", - "prompt": "login", } + if prompt := self.get_prompt(): + self.authorize_params["prompt"] = prompt + async def get_token(self, code: str, url: str): payload = { "client_id": self.client_id, diff --git a/backend/chainlit/server.py b/backend/chainlit/server.py index bce6018806..be3ee19ca6 100644 --- a/backend/chainlit/server.py +++ b/backend/chainlit/server.py @@ -892,7 +892,7 @@ async def upload_file( async def get_file( file_id: str, session_id: str, - current_user: Annotated[Union[User, PersistedUser], Depends(get_current_user)], + # current_user: Annotated[Union[User, PersistedUser], Depends(get_current_user)], #TODO: Causes 401 error. See https://github.com/Chainlit/chainlit/issues/1472 ): """Get a file from the session files directory.""" @@ -906,12 +906,13 @@ async def get_file( detail="Unauthorized", ) - if current_user: - if not session.user or session.user.identifier != current_user.identifier: - raise HTTPException( - status_code=401, - detail="You are not authorized to download files from this session", - ) + #TODO: Causes 401 error. See https://github.com/Chainlit/chainlit/issues/1472 + # if current_user: + # if not session.user or session.user.identifier != current_user.identifier: + # raise HTTPException( + # status_code=401, + # detail="You are not authorized to download files from this session", + # ) if file_id in session.files: file = session.files[file_id] diff --git a/backend/chainlit/version.py b/backend/chainlit/version.py index ee8f8def00..5abe48f638 100644 --- a/backend/chainlit/version.py +++ b/backend/chainlit/version.py @@ -3,5 +3,6 @@ try: __version__ = metadata.version(__package__) except metadata.PackageNotFoundError: - # Case where package metadata is not available. - __version__ = "" + # Case where package metadata is not available, default to a 'non-outdated' version. + # Ref: config.py::load_settings() + __version__ = "0.3.1" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 20eb9a900e..e8f06c13b9 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "chainlit" -version = "2.0.dev0" +version = "2.0.dev2" keywords = [ 'LLM', 'Agents', @@ -14,7 +14,7 @@ keywords = [ ] description = "Build Conversational AI." authors = ["Willy Douhard", "Dan Andre Constantini"] -license = " Apache-2.0" +license = "Apache-2.0" homepage = "https://chainlit.io/" documentation = "https://docs.chainlit.io/" classifiers = [ diff --git a/frontend/src/components/atoms/elements/InlinedDataframeList.tsx b/frontend/src/components/atoms/elements/InlinedDataframeList.tsx index 9f9275b433..d6140e878f 100644 --- a/frontend/src/components/atoms/elements/InlinedDataframeList.tsx +++ b/frontend/src/components/atoms/elements/InlinedDataframeList.tsx @@ -16,7 +16,7 @@ const InlinedDataframeList = ({ items }: Props) => ( key={i} style={{ height: 450, - maxWidth: '650px' + maxWidth: 'fit-content' }} > diff --git a/frontend/src/components/molecules/messages/Message.tsx b/frontend/src/components/molecules/messages/Message.tsx index ac20f42676..4672edeaea 100644 --- a/frontend/src/components/molecules/messages/Message.tsx +++ b/frontend/src/components/molecules/messages/Message.tsx @@ -112,7 +112,12 @@ const Message = memo( > {/* User message is displayed differently */} {isUserMessage ? ( - + { - if (value === '' || disabled) { + if (disabled || (value === '' && attachments.length === 0)) { return; } if (askUser) { diff --git a/libs/react-client/src/types/file.ts b/libs/react-client/src/types/file.ts index af3fde1eba..9099a4163d 100644 --- a/libs/react-client/src/types/file.ts +++ b/libs/react-client/src/types/file.ts @@ -22,4 +22,5 @@ export interface IAsk { timeout: number; } & FileSpec & ActionSpec; + parentId?: string; } diff --git a/libs/react-client/src/useChatInteract.ts b/libs/react-client/src/useChatInteract.ts index ab646de970..b598093034 100644 --- a/libs/react-client/src/useChatInteract.ts +++ b/libs/react-client/src/useChatInteract.ts @@ -118,6 +118,7 @@ const useChatInteract = () => { const replyMessage = useCallback( (message: IStep) => { if (askUser) { + if (askUser.parentId) message.parentId = askUser.parentId; setMessages((oldMessages) => addMessage(oldMessages, message)); askUser.callback(message); } diff --git a/libs/react-client/src/useChatSession.ts b/libs/react-client/src/useChatSession.ts index 94f8d74eb5..9020847d2a 100644 --- a/libs/react-client/src/useChatSession.ts +++ b/libs/react-client/src/useChatSession.ts @@ -277,7 +277,7 @@ const useChatSession = () => { ); socket.on('ask', ({ msg, spec }, callback) => { - setAskUser({ spec, callback }); + setAskUser({ spec, callback, parentId: msg.parentId }); setMessages((oldMessages) => addMessage(oldMessages, msg)); setLoading(false); diff --git a/package.json b/package.json index 24a3288f98..4d1d2b640a 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "formatUi": "cd frontend && pnpm run format", "lintPython": "cd backend && poetry run mypy chainlit/ tests/", "formatPython": "black `git ls-files | grep '.py$'` && isort --profile=black .", - "buildUi": "cd libs/react-client && pnpm run build && cd ../copilot && pnpm run build && cd ../../frontend && pnpm run build", - "build": "pnpm run buildUi && (mkdir -p backend/chainlit/frontend && cp -R frontend/dist backend/chainlit/frontend) && (mkdir -p backend/chainlit/copilot && cp -R libs/copilot/dist backend/chainlit/copilot) && (cd backend && poetry build)" + "buildUi": "cd libs/react-client && pnpm run build && cd ../copilot && pnpm run build && cd ../../frontend && pnpm run build" }, "pnpm": { "overrides": {