Showing preview only (2,312K chars total). Download the full file or copy to clipboard to get everything.
Repository: Chainlit/chainlit
Branch: main
Commit: 3843e8a401ca
Files: 588
Total size: 2.1 MB
Directory structure:
gitextract_rcugvcbq/
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── actions/
│ │ ├── pnpm-node-install/
│ │ │ └── action.yaml
│ │ └── uv-python-install/
│ │ └── action.yaml
│ ├── copilot-instructions.md
│ └── workflows/
│ ├── ci.yaml
│ ├── close_stale.yml
│ ├── copilot-setup-steps.yaml
│ ├── e2e-tests.yaml
│ ├── lint-backend.yaml
│ ├── lint-ui.yaml
│ ├── publish-libs.yaml
│ ├── publish.yaml
│ └── pytest.yaml
├── .gitignore
├── .husky/
│ └── pre-commit
├── .npmrc
├── .prettierrc
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── PRIVACY_POLICY.md
├── RELENG.md
├── backend/
│ ├── build.py
│ ├── chainlit/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── _utils.py
│ │ ├── action.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── cookie.py
│ │ │ └── jwt.py
│ │ ├── cache.py
│ │ ├── callbacks.py
│ │ ├── chat_context.py
│ │ ├── chat_settings.py
│ │ ├── cli/
│ │ │ └── __init__.py
│ │ ├── config.py
│ │ ├── context.py
│ │ ├── data/
│ │ │ ├── __init__.py
│ │ │ ├── acl.py
│ │ │ ├── base.py
│ │ │ ├── chainlit_data_layer.py
│ │ │ ├── dynamodb.py
│ │ │ ├── literalai.py
│ │ │ ├── sql_alchemy.py
│ │ │ ├── storage_clients/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── azure.py
│ │ │ │ ├── azure_blob.py
│ │ │ │ ├── base.py
│ │ │ │ ├── gcs.py
│ │ │ │ └── s3.py
│ │ │ └── utils.py
│ │ ├── discord/
│ │ │ ├── __init__.py
│ │ │ └── app.py
│ │ ├── element.py
│ │ ├── emitter.py
│ │ ├── input_widget.py
│ │ ├── langchain/
│ │ │ ├── __init__.py
│ │ │ └── callbacks.py
│ │ ├── langflow/
│ │ │ └── __init__.py
│ │ ├── llama_index/
│ │ │ ├── __init__.py
│ │ │ └── callbacks.py
│ │ ├── logger.py
│ │ ├── markdown.py
│ │ ├── mcp.py
│ │ ├── message.py
│ │ ├── mistralai/
│ │ │ └── __init__.py
│ │ ├── mode.py
│ │ ├── oauth_providers.py
│ │ ├── openai/
│ │ │ └── __init__.py
│ │ ├── py.typed
│ │ ├── sample/
│ │ │ ├── hello.py
│ │ │ └── starters_demo.py
│ │ ├── secret.py
│ │ ├── semantic_kernel/
│ │ │ └── __init__.py
│ │ ├── server.py
│ │ ├── session.py
│ │ ├── sidebar.py
│ │ ├── slack/
│ │ │ ├── __init__.py
│ │ │ └── app.py
│ │ ├── socket.py
│ │ ├── step.py
│ │ ├── sync.py
│ │ ├── teams/
│ │ │ ├── __init__.py
│ │ │ └── app.py
│ │ ├── translations/
│ │ │ ├── ar-SA.json
│ │ │ ├── bn.json
│ │ │ ├── da-DK.json
│ │ │ ├── de-DE.json
│ │ │ ├── el-GR.json
│ │ │ ├── en-US.json
│ │ │ ├── es.json
│ │ │ ├── fr-FR.json
│ │ │ ├── gu.json
│ │ │ ├── he-IL.json
│ │ │ ├── hi.json
│ │ │ ├── it.json
│ │ │ ├── ja.json
│ │ │ ├── kn.json
│ │ │ ├── ko.json
│ │ │ ├── ml.json
│ │ │ ├── mr.json
│ │ │ ├── nl.json
│ │ │ ├── ta.json
│ │ │ ├── te.json
│ │ │ ├── zh-CN.json
│ │ │ └── zh-TW.json
│ │ ├── translations.py
│ │ ├── types.py
│ │ ├── user.py
│ │ ├── user_session.py
│ │ ├── utils.py
│ │ └── version.py
│ ├── pyproject.toml
│ └── tests/
│ ├── __init__.py
│ ├── auth/
│ │ ├── __init__.py
│ │ └── test_cookie.py
│ ├── conftest.py
│ ├── data/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── storage_clients/
│ │ │ ├── test_gcs.py
│ │ │ └── test_s3.py
│ │ ├── test_chainlit_data_layer.py
│ │ ├── test_get_data_layer.py
│ │ ├── test_literalai.py
│ │ └── test_sql_alchemy.py
│ ├── langchain/
│ │ ├── __init__.py
│ │ ├── test_async_callback.py
│ │ ├── test_chain_types.py
│ │ └── test_sync_callback.py
│ ├── llama_index/
│ │ └── test_callbacks.py
│ ├── test_action.py
│ ├── test_cache.py
│ ├── test_callbacks.py
│ ├── test_chat_context.py
│ ├── test_chat_settings.py
│ ├── test_context.py
│ ├── test_element.py
│ ├── test_emitter.py
│ ├── test_input_widget.py
│ ├── test_markdown.py
│ ├── test_mcp.py
│ ├── test_message.py
│ ├── test_modes.py
│ ├── test_oauth_providers.py
│ ├── test_server.py
│ ├── test_session.py
│ ├── test_sidebar.py
│ ├── test_slack_socket_mode.py
│ ├── test_socket.py
│ ├── test_step.py
│ ├── test_translations.py
│ ├── test_user_session.py
│ └── test_utils.py
├── cypress/
│ ├── e2e/
│ │ ├── action/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── ask_custom_element/
│ │ │ ├── main.py
│ │ │ ├── public/
│ │ │ │ └── elements/
│ │ │ │ └── JiraTicket.jsx
│ │ │ └── spec.cy.ts
│ │ ├── ask_file/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── ask_multiple_files/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── ask_user/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── audio_element/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── auth/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── blinking_cursor/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── chat_context/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── chat_prefill/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── chat_profiles/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── chat_settings/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── command/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── config_overrides/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── context/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── copilot/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── custom_build/
│ │ │ ├── .gitignore
│ │ │ ├── main.py
│ │ │ ├── public/
│ │ │ │ ├── .gitignore
│ │ │ │ └── build/
│ │ │ │ ├── assets/
│ │ │ │ │ └── .PLACEHOLDER
│ │ │ │ └── index.html
│ │ │ └── spec.cy.ts
│ │ ├── custom_data_layer/
│ │ │ └── sql_alchemy.py
│ │ ├── custom_element/
│ │ │ ├── main.py
│ │ │ ├── public/
│ │ │ │ └── elements/
│ │ │ │ └── Counter.jsx
│ │ │ └── spec.cy.ts
│ │ ├── custom_element_auth/
│ │ │ ├── main.py
│ │ │ ├── spec.cy.ts
│ │ │ └── test.txt
│ │ ├── custom_element_command/
│ │ │ ├── main.py
│ │ │ ├── public/
│ │ │ │ └── elements/
│ │ │ │ └── Commander.jsx
│ │ │ └── spec.cy.ts
│ │ ├── custom_theme/
│ │ │ ├── main.py
│ │ │ ├── public/
│ │ │ │ └── theme.json
│ │ │ └── spec.cy.ts
│ │ ├── data_layer/
│ │ │ ├── .gitignore
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── dataframe/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── edit_message/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── elements/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── error_handling/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── file_element/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── header_auth/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── llama_index_cb/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── modes/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── on_chat_start/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── password_auth/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── plotly/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── pyplot/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── readme/
│ │ │ ├── chainlit_pt-BR.md
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── remove_elements/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── remove_step/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── sidebar/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── starters/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── starters_categories/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── step/
│ │ │ ├── async-spec.cy.ts
│ │ │ ├── main_async.py
│ │ │ ├── main_sync.py
│ │ │ ├── sync-spec.cy.ts
│ │ │ └── tests.ts
│ │ ├── stop_task/
│ │ │ ├── async-spec.cy.ts
│ │ │ ├── main_async.py
│ │ │ ├── main_sync.py
│ │ │ ├── sync-spec.cy.ts
│ │ │ └── tests.ts
│ │ ├── streaming/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── tasklist/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── thread_resume/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── update_step/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── upload_attachments/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── user_env/
│ │ │ ├── .gitignore
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ ├── user_session/
│ │ │ ├── main.py
│ │ │ └── spec.cy.ts
│ │ └── window_message/
│ │ ├── main.py
│ │ ├── public/
│ │ │ └── iframe.html
│ │ └── spec.cy.ts
│ ├── fixtures/
│ │ ├── hello.cpp
│ │ ├── hello.py
│ │ └── state_of_the_union.txt
│ └── support/
│ ├── e2e.ts
│ ├── run.ts
│ └── testUtils.ts
├── cypress.config.ts
├── frontend/
│ ├── .eslintignore
│ ├── .gitignore
│ ├── components.json
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── src/
│ │ ├── App.tsx
│ │ ├── AppWrapper.tsx
│ │ ├── api/
│ │ │ └── index.ts
│ │ ├── components/
│ │ │ ├── Alert.tsx
│ │ │ ├── AudioPresence.tsx
│ │ │ ├── AutoResizeTextarea.tsx
│ │ │ ├── AutoResumeThread.tsx
│ │ │ ├── BlinkingCursor.tsx
│ │ │ ├── ButtonLink.tsx
│ │ │ ├── ChatSettings/
│ │ │ │ ├── ChatSettingsSidebar.tsx
│ │ │ │ ├── CheckboxInput.tsx
│ │ │ │ ├── DatePickerInput.tsx
│ │ │ │ ├── FormInput.tsx
│ │ │ │ ├── InputLabel.tsx
│ │ │ │ ├── InputStateHandler.tsx
│ │ │ │ ├── MultiSelectInput.tsx
│ │ │ │ ├── NotificationCount.tsx
│ │ │ │ ├── RadioButtonGroup.tsx
│ │ │ │ ├── SelectInput.tsx
│ │ │ │ ├── SliderInput.tsx
│ │ │ │ ├── SwitchInput.tsx
│ │ │ │ ├── TagsInput.tsx
│ │ │ │ ├── TextInput.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── CodeSnippet.tsx
│ │ │ ├── CopyButton.tsx
│ │ │ ├── ElementSideView.tsx
│ │ │ ├── ElementView.tsx
│ │ │ ├── Elements/
│ │ │ │ ├── Audio.tsx
│ │ │ │ ├── CustomElement/
│ │ │ │ │ ├── Imports.ts
│ │ │ │ │ ├── Renderer.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Dataframe.tsx
│ │ │ │ ├── ElementRef.tsx
│ │ │ │ ├── File.tsx
│ │ │ │ ├── Image.tsx
│ │ │ │ ├── LazyDataframe.tsx
│ │ │ │ ├── PDF.tsx
│ │ │ │ ├── Plotly.tsx
│ │ │ │ ├── Text.tsx
│ │ │ │ ├── Video.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── Icon.tsx
│ │ │ ├── Kbd.tsx
│ │ │ ├── LeftSidebar/
│ │ │ │ ├── Search.tsx
│ │ │ │ ├── ThreadHistory.tsx
│ │ │ │ ├── ThreadList.tsx
│ │ │ │ ├── ThreadOptions.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── LoginForm.tsx
│ │ │ ├── Logo.tsx
│ │ │ ├── Markdown.tsx
│ │ │ ├── MarkdownAlert.tsx
│ │ │ ├── ProviderButton.tsx
│ │ │ ├── QuiltedGrid.tsx
│ │ │ ├── ReadOnlyThread.tsx
│ │ │ ├── Tasklist/
│ │ │ │ ├── Task.tsx
│ │ │ │ ├── TaskStatusIcon.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── WaterMark.tsx
│ │ │ ├── chat/
│ │ │ │ ├── Footer.tsx
│ │ │ │ ├── MessageComposer/
│ │ │ │ │ ├── Attachment.tsx
│ │ │ │ │ ├── Attachments.tsx
│ │ │ │ │ ├── CommandButtons.tsx
│ │ │ │ │ ├── CommandPopoverButton.tsx
│ │ │ │ │ ├── FavoriteButton.tsx
│ │ │ │ │ ├── Input.tsx
│ │ │ │ │ ├── Mcp/
│ │ │ │ │ │ ├── AddForm.tsx
│ │ │ │ │ │ ├── AnimatedPlugIcon.tsx
│ │ │ │ │ │ ├── List.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ModePicker.tsx
│ │ │ │ │ ├── SubmitButton.tsx
│ │ │ │ │ ├── UploadButton.tsx
│ │ │ │ │ ├── VoiceButton.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Messages/
│ │ │ │ │ ├── Message/
│ │ │ │ │ │ ├── AskActionButtons.tsx
│ │ │ │ │ │ ├── AskFileButton.tsx
│ │ │ │ │ │ ├── Avatar.tsx
│ │ │ │ │ │ ├── Buttons/
│ │ │ │ │ │ │ ├── Actions/
│ │ │ │ │ │ │ │ ├── ActionButton.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── DebugButton.tsx
│ │ │ │ │ │ │ ├── FeedbackButtons.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── Content/
│ │ │ │ │ │ │ ├── InlinedElements/
│ │ │ │ │ │ │ │ ├── InlineCustomElementList.tsx
│ │ │ │ │ │ │ │ ├── InlinedAudioList.tsx
│ │ │ │ │ │ │ │ ├── InlinedDataframeList.tsx
│ │ │ │ │ │ │ │ ├── InlinedFileList.tsx
│ │ │ │ │ │ │ │ ├── InlinedImageList.tsx
│ │ │ │ │ │ │ │ ├── InlinedPDFList.tsx
│ │ │ │ │ │ │ │ ├── InlinedPlotlyList.tsx
│ │ │ │ │ │ │ │ ├── InlinedTextList.tsx
│ │ │ │ │ │ │ │ ├── InlinedVideoList.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── Step.tsx
│ │ │ │ │ │ ├── UserMessage.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MessagesContainer/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ScrollContainer.tsx
│ │ │ │ ├── ScrollDownButton.tsx
│ │ │ │ ├── Starter.tsx
│ │ │ │ ├── StarterCategory.tsx
│ │ │ │ ├── Starters.tsx
│ │ │ │ ├── WelcomeScreen.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── header/
│ │ │ │ ├── ApiKeys.tsx
│ │ │ │ ├── ChatProfiles.tsx
│ │ │ │ ├── NewChat.tsx
│ │ │ │ ├── Readme.tsx
│ │ │ │ ├── Share.tsx
│ │ │ │ ├── SidebarTrigger.tsx
│ │ │ │ ├── ThemeToggle.tsx
│ │ │ │ ├── UserNav.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── i18n/
│ │ │ │ ├── Translator.tsx
│ │ │ │ └── index.ts
│ │ │ ├── icons/
│ │ │ │ ├── Auth0.tsx
│ │ │ │ ├── Cognito.tsx
│ │ │ │ ├── Descope.tsx
│ │ │ │ ├── EditSquare.tsx
│ │ │ │ ├── Github.tsx
│ │ │ │ ├── Gitlab.tsx
│ │ │ │ ├── Google.tsx
│ │ │ │ ├── Microsoft.tsx
│ │ │ │ ├── Okta.tsx
│ │ │ │ ├── PaperClip.tsx
│ │ │ │ ├── Pencil.tsx
│ │ │ │ ├── Search.tsx
│ │ │ │ ├── Send.tsx
│ │ │ │ ├── Settings.tsx
│ │ │ │ ├── Sidebar.tsx
│ │ │ │ ├── Stop.tsx
│ │ │ │ ├── ToolBox.tsx
│ │ │ │ └── VoiceLines.tsx
│ │ │ ├── share/
│ │ │ │ └── ShareDialog.tsx
│ │ │ └── ui/
│ │ │ ├── accordion.tsx
│ │ │ ├── alert-dialog.tsx
│ │ │ ├── aspect-ratio.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── button.tsx
│ │ │ ├── calendar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── carousel.tsx
│ │ │ ├── checkbox.tsx
│ │ │ ├── command.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── dropdown-menu.tsx
│ │ │ ├── form.tsx
│ │ │ ├── hover-card.tsx
│ │ │ ├── input.tsx
│ │ │ ├── label.tsx
│ │ │ ├── pagination.tsx
│ │ │ ├── popover.tsx
│ │ │ ├── progress.tsx
│ │ │ ├── radio-group.tsx
│ │ │ ├── resizable.tsx
│ │ │ ├── scroll-area.tsx
│ │ │ ├── select.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── sheet.tsx
│ │ │ ├── sidebar.tsx
│ │ │ ├── skeleton.tsx
│ │ │ ├── slider.tsx
│ │ │ ├── sonner.tsx
│ │ │ ├── switch.tsx
│ │ │ ├── table.tsx
│ │ │ ├── tabs.tsx
│ │ │ ├── textarea.tsx
│ │ │ └── tooltip.tsx
│ │ ├── contexts/
│ │ │ └── MessageContext.tsx
│ │ ├── hooks/
│ │ │ ├── query.ts
│ │ │ ├── use-mobile.tsx
│ │ │ ├── useCommandNavigation.tsx
│ │ │ ├── useFetch.tsx
│ │ │ ├── useLayoutMaxWidth.tsx
│ │ │ ├── usePlatform.ts
│ │ │ └── useUpload.tsx
│ │ ├── i18n/
│ │ │ ├── dateLocale.ts
│ │ │ └── index.ts
│ │ ├── index.css
│ │ ├── index.d.ts
│ │ ├── lib/
│ │ │ ├── message.ts
│ │ │ ├── router.ts
│ │ │ └── utils.ts
│ │ ├── main.tsx
│ │ ├── pages/
│ │ │ ├── AuthCallback.tsx
│ │ │ ├── Element.tsx
│ │ │ ├── Env.tsx
│ │ │ ├── Home.tsx
│ │ │ ├── Login.tsx
│ │ │ ├── Page.tsx
│ │ │ └── Thread.tsx
│ │ ├── router.tsx
│ │ ├── state/
│ │ │ ├── chat.ts
│ │ │ ├── project.ts
│ │ │ └── user.ts
│ │ ├── types/
│ │ │ ├── Input.ts
│ │ │ ├── NotificationCount.tsx
│ │ │ ├── chat.ts
│ │ │ ├── index.ts
│ │ │ └── messageContext.ts
│ │ └── vite-env.d.ts
│ ├── tailwind.config.js
│ ├── tests/
│ │ ├── FavoriteButton.spec.tsx
│ │ ├── NewChat.spec.tsx
│ │ ├── content.spec.tsx
│ │ ├── icon.spec.tsx
│ │ ├── setup-tests.ts
│ │ └── tsconfig.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vite.config.ts
│ └── vitest.config.ts
├── libs/
│ ├── copilot/
│ │ ├── .storybook/
│ │ │ ├── main.ts
│ │ │ └── preview.ts
│ │ ├── components.json
│ │ ├── index.tsx
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── sonner.css
│ │ ├── src/
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── api.ts
│ │ │ ├── app.tsx
│ │ │ ├── appWrapper.tsx
│ │ │ ├── chat/
│ │ │ │ ├── body.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── ElementSideView.tsx
│ │ │ │ ├── Header.tsx
│ │ │ │ └── WelcomeScreen.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── index.ts
│ │ │ │ └── useCopilotInteract.ts
│ │ │ ├── index.css
│ │ │ ├── lib/
│ │ │ │ └── utils.ts
│ │ │ ├── state.ts
│ │ │ ├── types.ts
│ │ │ └── widget.tsx
│ │ ├── stories/
│ │ │ └── App.stories.ts
│ │ ├── tailwind.config.js
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── react-client/
│ ├── README.md
│ ├── package.json
│ ├── src/
│ │ ├── api/
│ │ │ ├── hooks/
│ │ │ │ ├── api.ts
│ │ │ │ └── auth/
│ │ │ │ ├── config.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── sessionManagement.ts
│ │ │ │ ├── state.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── userManagement.ts
│ │ │ └── index.tsx
│ │ ├── context.ts
│ │ ├── index.ts
│ │ ├── state.ts
│ │ ├── types/
│ │ │ ├── action.ts
│ │ │ ├── audio.ts
│ │ │ ├── command.ts
│ │ │ ├── config.ts
│ │ │ ├── element.ts
│ │ │ ├── feedback.ts
│ │ │ ├── file.ts
│ │ │ ├── history.ts
│ │ │ ├── index.ts
│ │ │ ├── mcp.ts
│ │ │ ├── mode.ts
│ │ │ ├── step.ts
│ │ │ ├── thread.ts
│ │ │ └── user.ts
│ │ ├── useAudio.ts
│ │ ├── useChatData.ts
│ │ ├── useChatInteract.ts
│ │ ├── useChatMessages.ts
│ │ ├── useChatSession.ts
│ │ ├── useConfig.ts
│ │ ├── utils/
│ │ │ ├── group.ts
│ │ │ └── message.ts
│ │ └── wavtools/
│ │ ├── analysis/
│ │ │ ├── audio_analysis.js
│ │ │ └── constants.js
│ │ ├── index.ts
│ │ ├── wav_packer.js
│ │ ├── wav_recorder.js
│ │ ├── wav_renderer.ts
│ │ ├── wav_stream_player.js
│ │ └── worklets/
│ │ ├── audio_processor.js
│ │ └── stream_processor.js
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── lint-staged.config.js
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = lf
[*.{py,ts,tsx}]
indent_style = space
insert_final_newline = true
[*.py]
indent_size = 4
trim_trailing_whitespace = true
[*.{ts,tsx}]
indent_size = 2
================================================
FILE: .eslintignore
================================================
node_modules
dist
================================================
FILE: .eslintrc
================================================
{
"root": true,
"parser": "@typescript-eslint/parser",
"ignorePatterns": ["**/*.jsx"],
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
]
}
}
================================================
FILE: .github/CODEOWNERS
================================================
* @hayescode @asvishnyakov @sandangel
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: needs-triage
assignees: ''
type: 'Bug'
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: needs-triage
assignees: ''
type: 'Feature'
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/actions/pnpm-node-install/action.yaml
================================================
name: Install Node, pnpm and dependencies.
description: Install Node, pnpm and dependencies using cache.
inputs:
node-version:
description: Node.js version
required: true
default: '24.3.0' # Switch to 'lts' as soon as Node 24 reaches LTS status.
runs:
using: composite
steps:
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Install JS dependencies
run: pnpm install
shell: bash
================================================
FILE: .github/actions/uv-python-install/action.yaml
================================================
name: Install Python, uv and dependencies.
description: Install Python, uv and project dependencies using cache
inputs:
python-version:
description: Python version
required: true
default: '3.10'
uv-version:
description: uv version
required: true
default: 'latest'
working-directory:
description: Working directory for uv command.
required: false
default: .
extra-dependencies:
description: Extra dependencies to install, e.g. --extra tests --extra dev.
required: false
runs:
using: composite
steps:
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: ${{ inputs.uv-version }}
enable-cache: true
- name: Set up Python ${{ inputs.python-version }}
id: setup_python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install Python dependencies
run: uv sync --no-install-project --no-editable ${{ inputs.extra-dependencies }}
shell: bash
working-directory: ${{ inputs.working-directory }}
================================================
FILE: .github/copilot-instructions.md
================================================
# Chainlit Development Instructions
Chainlit is a Python framework for building conversational AI applications with Python backend and React frontend. It uses uv for Python dependency management and pnpm for Node.js packages.
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
## Working Effectively
### Bootstrap, Build, and Test the Repository
**CRITICAL**: All commands must complete - NEVER CANCEL any build or test operations. Use appropriate timeouts.
1. **Install Dependencies (Required first)**:
```bash
# Install uv (if not available)
python3 -m pip install pipx
python3 -m pipx install uv
export PATH="$HOME/.local/bin:$PATH"
# Install pnpm (if not available)
npm install -g pnpm
# Install Python dependencies - takes ~2 minutes, NEVER CANCEL
cd backend
uv sync --extra tests --extra mypy --extra dev --extra custom-data
# Timeout: Use 300+ seconds (5+ minutes)
# Install Node.js dependencies - takes ~3 minutes, NEVER CANCEL
cd ..
pnpm install --frozen-lockfile
# Timeout: Use 600+ seconds (10+ minutes)
# NOTE: Cypress download may fail due to network restrictions - this is expected in CI environments
```
2. **Build the Frontend - takes ~1 minute, NEVER CANCEL**:
```bash
pnpm run buildUi
# Timeout: Use 300+ seconds (5+ minutes)
```
3. **Run Tests**:
```bash
# Backend tests - takes ~17 seconds, NEVER CANCEL
cd backend
export PATH="$HOME/.local/bin:$PATH"
uv run pytest --cov=chainlit/
# Timeout: Use 120+ seconds (2+ minutes)
# Frontend tests - takes ~4 seconds
cd ../frontend
pnpm test
# Timeout: Use 60 seconds
# E2E tests require Cypress download - may not work in restricted environments
# If available: pnpm test (takes variable time depending on tests)
```
4. **Run Development Servers**:
```bash
# Start backend (in one terminal)
cd backend
export PATH="$HOME/.local/bin:$PATH"
uv run chainlit run chainlit/sample/hello.py -h
# Available at http://localhost:8000
# Start frontend dev server (in another terminal)
cd frontend
pnpm run dev
# Available at http://localhost:5173/
```
## Validation
### Manual Validation Requirements
- **ALWAYS** manually validate any changes by running complete scenarios.
- **ALWAYS** test the Chainlit application after making changes.
- Create a test app and verify it runs: `uv run chainlit run /path/to/test.py -h`
- **ALWAYS** run through at least one complete user workflow after making changes.
### Linting and Formatting - takes ~2 minutes, NEVER CANCEL
```bash
# Run all linting (UI + Python)
pnpm run lint
# Timeout: Use 300+ seconds (5+ minutes)
# Format UI code - takes ~5 seconds
pnpm run formatUi
# Format Python code using ruff (preferred)
cd backend
export PATH="$HOME/.local/bin:$PATH"
uv run ruff format chainlit/ tests/
# NOTE: pnpm run formatPython may fail if black is not installed
# Use ruff format instead as shown above
```
### CI Requirements
- **ALWAYS** run `pnpm run lint` before committing or the CI (.github/workflows/ci.yaml) will fail.
- The CI runs: pytest, lint-backend, lint-ui, and e2e-tests.
- **NEVER CANCEL** any CI commands - they take time but must complete.
## Key Project Structure
### Repository Root
```
/
├── README.md
├── CONTRIBUTING.md
├── package.json # Root pnpm workspace config
├── pnpm-workspace.yaml # Workspace definition
├── backend/ # Python backend with uv
├── frontend/ # React frontend app
├── libs/
│ ├── react-client/ # React client library
│ └── copilot/ # Copilot functionality
├── cypress/ # E2E tests
└── .github/
├── workflows/ # CI/CD pipelines
└── actions/ # Reusable GitHub actions
```
### Working with the Backend
- **Technology**: Python 3.10+ with uv, FastAPI, SocketIO
- **Entry point**: `backend/chainlit/`
- **Tests**: `backend/tests/`
- **Dependencies**: Defined in `backend/pyproject.toml`
- **Hello app**: `backend/chainlit/sample/hello.py`
### Working with the Frontend
- **Technology**: React 18+ with Vite, TypeScript, Tailwind CSS
- **Entry point**: `frontend/src/`
- **Dependencies**: Defined in `frontend/package.json`
- **Build output**: `frontend/dist/`
## Common Tasks
### Creating a New Chainlit App
```python
# Create app.py
import chainlit as cl
@cl.on_message
async def main(message: cl.Message):
await cl.Message(content=f"You said: {message.content}").send()
# Run it
uv run chainlit run app.py -w
```
### Timing Expectations
- **pnpm install**: ~3 minutes (may fail on Cypress - this is normal)
- **uv install**: ~2 minutes
- **pnpm run buildUi**: ~1 minute
- **pnpm run lint**: ~2 minutes
- **Backend tests**: ~17 seconds
- **Frontend tests**: ~4 seconds
- **pnpm run formatUi**: ~5 seconds
### Common Gotchas
- **NEVER CANCEL** long-running operations - they need time to complete.
- Cypress download often fails in CI environments - this is expected.
- Use `uv run` prefix for all Python commands in backend.
- Use `export PATH="$HOME/.local/bin:$PATH"` to ensure uv is available.
- The `pnpm run formatPython` command may fail - use `uv run ruff format` instead.
- Frontend dev server connects to backend at localhost:8000.
- Always start backend before frontend for development.
### File Locations for Quick Reference
- **Main CLI**: `backend/chainlit/cli/`
- **Server code**: `backend/chainlit/server.py`
- **Frontend app**: `frontend/src/App.tsx`
- **React client**: `libs/react-client/src/`
- **CI workflows**: `.github/workflows/ci.yaml`
- **uv config**: `backend/pyproject.toml`
- **Frontend config**: `frontend/package.json`
## Requirements
- **Python**: >= 3.10
- **Node.js**: >= 20 (24+ recommended)
- **uv**: 2.1.3 (install via pipx)
- **pnpm**: Latest (install via npm)
================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI
on:
workflow_call:
workflow_dispatch:
merge_group:
pull_request:
branches: [main, dev, 'release/**']
paths-ignore:
- '*.md'
- LICENSE
push:
branches: [main, dev, 'release/**']
paths-ignore:
- '*.md'
- LICENSE
permissions: read-all
jobs:
pytest:
uses: ./.github/workflows/pytest.yaml
secrets: inherit
lint-backend:
uses: ./.github/workflows/lint-backend.yaml
secrets: inherit
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
if: always() # This ensures the job always runs
needs: [lint-backend, pytest, lint-ui, e2e-tests]
steps:
# Propagate failure
- name: Check dependent jobs
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'action_required') || contains(needs.*.result, 'timed_out')
run: |
echo "Not all required jobs succeeded"
exit 1
================================================
FILE: .github/workflows/close_stale.yml
================================================
name: Close inactive issues and pull requests
on:
schedule:
- cron: "30 1 * * *"
workflow_dispatch:
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
operations-per-run: 400
ascending: true
days-before-issue-stale: 14
days-before-issue-close: 7
stale-issue-label: "stale"
exempt-issue-labels: "enhancement,dev-tooling,e2e-tests,unit-tests,keep-for-a-while"
stale-issue-message: "This issue is stale because it has been open for 14 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale."
days-before-pr-stale: 14
days-before-pr-close: 7
stale-pr-label: "stale"
exempt-pr-labels: "enhancement,dev-tooling,e2e-tests,unit-tests,keep-for-a-while"
stale-pr-message: "This PR is stale because it has been open for 14 days with no activity."
close-pr-message: "This PR was closed because it has been inactive for 7 days since being marked as stale."
repo-token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/copilot-setup-steps.yaml
================================================
name: "Copilot Setup Steps"
# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
# This workflow optimizes the GitHub Copilot coding agent's ephemeral development environment
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yaml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yaml
jobs:
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
copilot-setup-steps:
runs-on: ubuntu-latest
timeout-minutes: 15
# Set the permissions to the lowest permissions possible needed for your steps.
# Copilot will be given its own token for its operations.
permissions:
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
contents: read
# You can define any steps you want, and they will run before the agent starts.
# If you do not check out your code, Copilot will do this for you.
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Node.js, pnpm and dependencies
uses: ./.github/actions/pnpm-node-install
- name: Install Python, uv and dependencies
uses: ./.github/actions/uv-python-install
with:
python-version: "3.10"
uv-version: "latest"
working-directory: "./backend"
extra-dependencies: "--extra tests --extra mypy --extra dev --extra custom-data"
- name: Build UI components
run: pnpm run buildUi
timeout-minutes: 5
================================================
FILE: .github/workflows/e2e-tests.yaml
================================================
name: E2ETests
on: [workflow_call]
permissions: read-all
jobs:
ci:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
env:
BACKEND_DIR: ./backend
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/pnpm-node-install
name: Install Node, pnpm and dependencies.
- name: Install Cypress
uses: cypress-io/github-action@v6
with:
runTests: false
- uses: ./.github/actions/uv-python-install
name: Install Python, uv and Python & pnpm (uv does it automatically) dependencies
with:
working-directory: ${{ env.BACKEND_DIR }}
extra-dependencies: --extra tests
- name: Build UI components
run: pnpm run buildUi
timeout-minutes: 5
- name: Run tests
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
run: pnpm test
shell: bash
- name: Upload screenshots
uses: actions/upload-artifact@v4
if: always() && hashFiles('cypress/screenshots/**') != ''
with:
name: cypress-screenshots-${{ matrix.os }}
path: cypress/screenshots
================================================
FILE: .github/workflows/lint-backend.yaml
================================================
name: LintBackend
on: [workflow_call]
permissions: read-all
jobs:
lint-backend:
runs-on: ubuntu-latest
env:
BACKEND_DIR: ./backend
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/uv-python-install
name: Install Python, uv and Python dependencies
with:
extra-dependencies: --extra tests --extra mypy --extra custom-data
working-directory: ${{ env.BACKEND_DIR }}
- name: Lint with ruff
uses: astral-sh/ruff-action@v1
with:
src: ${{ env.BACKEND_DIR }}
changed-files: "true"
- name: Check formatting with ruff
uses: astral-sh/ruff-action@v1
with:
src: ${{ env.BACKEND_DIR }}
changed-files: "true"
args: "format --check"
- name: Run Mypy
run: uv run --no-project mypy chainlit/ tests/
working-directory: ${{ env.BACKEND_DIR }}
================================================
FILE: .github/workflows/lint-ui.yaml
================================================
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
================================================
FILE: .github/workflows/publish-libs.yaml
================================================
name: Publish libs
on:
workflow_dispatch:
inputs:
dry_run:
description: 'Dry run (test publishing)'
required: false
default: false
type: boolean
release:
types: [published]
permissions: read-all
jobs:
validate:
name: Validate inputs
runs-on: ubuntu-latest
steps:
- name: Validate publishing branch and destination package index
run: |
if [[ "${{ github.ref_name }}" != "main" && "${{ github.event_name }}" != "release" ]]; then
if [[ "${{ inputs.dry_run }}" != "true" ]]; then
echo "❌ Error: Only build from main branch or release tag can be published to npm registry."
echo "Please check 'Dry run (test publishing)' when running from branch: ${{ github.ref_name }}"
exit 1
fi
fi
echo "✅ Validation passed"
ci:
needs: [validate]
uses: ./.github/workflows/ci.yaml
secrets: inherit
build-n-publish:
name: Upload libs release to npm registry
runs-on: ubuntu-latest
needs: [ci]
permissions:
contents: read
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/pnpm-node-install
name: Install Node, pnpm and dependencies.
- name: Build libs
run: pnpm build:libs
- name: Publish packages to npm
# --no-git-checks allows testing from non-main branches and publishing from release tags
run: pnpm publish --recursive --no-git-checks ${{ inputs.dry_run && '--dry-run' || '' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_REACT_CLIENT }}
================================================
FILE: .github/workflows/publish.yaml
================================================
name: Publish
on:
workflow_dispatch:
inputs:
use_testpypi:
description: 'Publish to TestPyPI instead of PyPI'
required: false
default: false
type: boolean
release:
types: [published]
permissions: read-all
jobs:
validate:
name: Validate inputs
runs-on: ubuntu-latest
steps:
- name: Validate publishing branch and destination package index
run: |
if [[ "${{ github.ref_name }}" != "main" && "${{ github.event_name }}" != "release" ]]; then
if [[ "${{ inputs.use_testpypi }}" != "true" ]]; then
echo "❌ Error: Only build from main branch or release tag can be published to PyPI."
echo "Please check 'Publish to TestPyPI instead of PyPI' when running from branch: ${{ github.ref_name }}"
exit 1
fi
fi
echo "✅ Validation passed"
ci:
needs: [validate]
uses: ./.github/workflows/ci.yaml
secrets: inherit
build-n-publish:
name: Upload release to PyPI/TestPyPI
runs-on: ubuntu-latest
needs: [ci]
env:
name: ${{ inputs.use_testpypi && 'testpypi' || 'pypi' }}
url: ${{ inputs.use_testpypi && 'https://test.pypi.org/project/chainlit' || 'https://pypi.org/project/chainlit' }}
BACKEND_DIR: ./backend
permissions:
contents: read
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/pnpm-node-install
name: Install Node, pnpm and dependencies.
- uses: ./.github/actions/uv-python-install
name: Install Python, uv and Python dependencies
with:
working-directory: ${{ env.BACKEND_DIR }}
- name: Build Python distribution
run: uv build
working-directory: ${{ env.BACKEND_DIR }}
- name: Check frontend and copilot folder included
run: |
pip install wheel
python -m wheel unpack dist/chainlit-*.whl -d unpacked
ls unpacked/chainlit-*/chainlit/frontend/dist
ls unpacked/chainlit-*/chainlit/copilot/dist
working-directory: ${{ env.BACKEND_DIR }}
- name: Publish package distributions to TestPyPI
if: inputs.use_testpypi
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: backend/dist
repository-url: https://test.pypi.org/legacy/
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
verbose: true
- name: Publish package distributions to PyPI
if: ${{ !inputs.use_testpypi }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: backend/dist
password: ${{ secrets.PYPI_API_TOKEN }}
================================================
FILE: .github/workflows/pytest.yaml
================================================
name: Pytest
on: [workflow_call]
permissions: read-all
jobs:
pytest:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']
env:
BACKEND_DIR: ./backend
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/pnpm-node-install
name: Install Node, pnpm and dependencies.
- uses: ./.github/actions/uv-python-install
name: Install Python, uv and Python dependencies
with:
python-version: ${{ matrix.python-version }}
extra-dependencies: --extra tests --extra mypy --extra custom-data
working-directory: ${{ env.BACKEND_DIR }}
- name: Build UI components
run: pnpm run buildUi
timeout-minutes: 5
- name: Run Pytest
run: uv run --no-project pytest --cov=chainlit/
working-directory: ${{ env.BACKEND_DIR }}
================================================
FILE: .gitignore
================================================
build
dist
*.egg-info
.env
*.files
venv
.venv
.DS_Store
**/.chainlit/*
chainlit.md
cypress/screenshots
cypress/videos
cypress/downloads
__pycache__
.ipynb_checkpoints
*.db
.mypy_cache
chat_files
.chroma
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.pnpm-store
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.aider*
.coverage
backend/README.md
backend/.dmypy.json
.history
================================================
FILE: .husky/pre-commit
================================================
pnpm lint-staged
================================================
FILE: .npmrc
================================================
shared-workspace-lockfile=false
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=@types*
side-effects-cache=false
================================================
FILE: .prettierrc
================================================
{
"semi": true,
"trailingComma": "none",
"singleQuote": true,
"printWidth": 80,
"plugins": ["@trivago/prettier-plugin-sort-imports"],
"importOrder": [
"pages/(.*)$",
"@chainlit/(.*)$",
"components/(.*)$",
"assets/(.*)$",
"hooks/(.*)$",
"state/(.*)$",
"types/(.*)$",
"^./*.*.css",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true
}
================================================
FILE: CHANGELOG.md
================================================
# Changelog
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/).
## [2.10.0] - 2026-03-05
### Added
- Add starter categories for grouped starters
- Always show the favorite messages button with an empty state
- Add option to disable rendering markdown in user messages
- Allow easy deletion of favorites
- Make state cookie lifetime configurable via env var
- Add Arabic translation
- Add Danish translation
- Add settings change listener
- Add image preview
- Add selected option for command pre-selection
- Add `auto_collapse` parameter to `Step`
- Add `/health` endpoint for container orchestration
- Add `hidden` option for `default_sidebar_state`
- Make avatar size configurable via `config.toml`
### Fixed
- Reorder chat history sidebar after messages in existing chats
- Use login error detail for credential failures
- Convert UUID fields to strings in feedback extraction
- Preserve thread metadata when updated without metadata
- Reset audio UI when microphone permission is denied
- Fix sidebar inset overflow causing horizontal scroll
- Prevent empty strings from overwriting step content on upsert
- Use correct URL scheme when SSL is configured
## [2.9.6] - 2026-01-20
### Added
- Allow skip new chat creation
- Add data picker input widget
- Toggle chat settings in sidebar instead of composer
### Fixed
- Fix: Starters now correctly use the selected/default mode if configured
## [2.9.5] - 2026-01-08
### Added
- Add favorite messages (prompt templates)
### Fixed
- Fix: Starters now correctly use the selected/default mode if configured
## [2.9.4] - 2025-12-24
### Added
- Add an icon for shared thread
- New option to allow disabling auto scroll of assistant messages
- Add modes: you may allow users to select an LLM model, a mode (for example, planning), allow to enable reasoning etc.
- Breaking change: you need to run `ALTER TABLE steps ADD COLUMN IF NOT EXISTS modes JSONB;` for migration
### Fixed
- Fix tiny avatar for long messages
- Security vulnerability in Chainlit: added missed sanitization to custom elements update endpoint
### Changed
- Bumped watchfiles version
## [2.9.3] - 2025-12-04
### Added
- Add tests for oauth providers and messages
- Merge metadata in chainlit data layer
- Add native video support in markdown rendering
- Optimize chat message rendering
- Add language configuration option to config.toml
- Upgrade langchain imports for v1 compatibility
- Improve icon name formatting issues
### Fixed
- Fixed page blinking issue with header_auth
- Set environ when restoring websocket session
- Move hello.py to avoid import issues
- Fix issue showing thread sharing when disabled
- Disable Chainlit from setting logging globally
## [2.9.2] - 2025-11-22
### Added
- Add tests for socket, chat context, cache, translations & oauth providers
### Fixed
- Fix copilot breaking change introduced in 2.8.5
## [2.9.1] - 2025-11-20
### Added
- Add support for tabs in chat settings
- Support markdown in watermark
- Add italian translation to translations folder
- Add query param prefill for chat
- Add tests for utils, markdown, sidebar, chat settings, mcp, input widget, langchain, elements, steps, and actions
## [2.9.0] - 2025-11-06
### Added
- Add better support for Multi-Agent implementations
- Nested steps are now step.input -> child step -> step.output
- Improved formatting and styling of Tasklist
## [2.8.5] - 2025-11-07
### Added
- Add display_name to ChatProfile
- Add slack reaction event callback
- Add raw response from OAuth providers
### Fixed
- Security vulnerability in Chainlint: added missed ACL check for session initialization
### Changed
- Remove FastAPI version restrictions
## [2.8.4] - 2025-10-29
### Added
- Add support for GitHub Enterprise OAuth provider
- Explicit disable on input widgets
### Fixed
- Tasklist tasks are now properly reconnected to their steps/messages
- ci: fix pnpm publish checks
- fix: missing / in url with base path when connecting Streamable HTTP MCP
- fix - persist custom_elements to data layer without cloud storage
- fix: propagate IME composition events in AutoResizeTextarea
- fix: confirm when enter
- Fix(translation): correct French translation of chat watermark
- fix(ui): add fallback logo if custom logo is missing
## [2.8.3] - 2025-10-06
### Added
- Support for the `target` attribute in header links, which can be configured through the configuration options
### Changed
- `@chainlit/react-client` automatic publishing
## [2.8.2] - 2025-10-01
### Changed
- Remove autofocus in mobile message composer
- Improve error handling in sqlalchemy data layer `get_read_url()`
### Fixed
- Fix voice hotkey (P) triggering when typing in chat input
- Properly finalize data layers
- Fix `on_chat_start` not always firing
## [2.8.1] - 2025-09-24
### Added
- Add German and Korean translations
- Add support for custom_meta_url in config.toml
### Changed
- `cl.on_thread_share_view` will allow shared thread viewing if it returns `True` to enable custom/admin viewing.
### Fixed
- Removed redundant message sending in Slack when images are present.
- Generate signed url when loading elements using SQLAlchemy data layer.
## [2.8.0] - 2025-09-12
### Added
- Add ability to share threads. See documentation for how to enable it.
- https://docs.chainlit.io/api-reference/lifecycle-hooks/on-shared-thread-view
- Add new chat settings: multi-select, radio-group, and checkbox
- Add optional language parameter to set_starters
- Add neutral Spanish translation
- Allow sending commands from custom elements
### Changed
- Reordered message composer elements
### Fixed
- Default to plaintext code blocks for unsupported languages like CSV
- Sort threads by updated_at field
- Replace hardcoded strings with translation keys
- GCP storage provider dependency is now optional
- CI/CD fixes
- Fixed issues with hot-reloading in dev mode (`-w` flag)
- Take overridden config into account in audio handlers
## [2.7.2] - 2025-08-26
### Added
- Added LiteralAI data layer deprecation warning
- Added context to `@cl.on_feedback` callback
- Added Traditional Chinese (Taiwan) translations
- Added configurable user_env persistence to database
- New `persist_user_env` and `mask_user_env` field in `config.toml`
- Added new command translations to all languages
- Added CODEOWNERS
### Fixed
- Improved dynamic config overrides for chat profiles
- Import GCSStorageClient only when needed to avoid requiring optional dependencies
- Updated CONTRIBUTING.md for `uv` usage
## [2.7.1.1] - 2025-08-21
- Fix publishing to include frontend and copilot folders
## [2.7.1] - 2025-08-20
- Fix publishing to work with uv
## [2.7.0] - 2025-08-20
### Added
- New ChatGPT-style command selection and improve message input handling
- Added the ability to override certain config.toml settings for Chat Profiles, so some profiles can have MCP and some can't for example. [Documentation Updated](https://docs.chainlit.io/api-reference/chat-profiles#dynamic-configuration).
- You must now explicity enable audio and MCP as these are no longer inferred by the presence of `on_audio_start` or `on_mcp_connect` callbacks
- Delete your `config.toml`, run `chainlit init`, and update your settings
- Added copilot setup instructions for GitHub Copilot SWE Agent
- Added Slack socket mode support
- AskFileButton can now upload file with proper checking and it's own limits
- Added content-disposition metadata to azure blob uploads to persist download file name
- Migrated from poetry to uv
### Fixed
- Changed thread sorting to use updated time instead of creation time
- Add missing headers when connecting Streamable HTTP MCP
- Remove undocumented `CHAINLIT_CUSTOM_AUTH` environment variable used in Copilot
## [2.6.9] - 2025-08-14
### Added
- Add GitHub Copilot instructions for automated PRs
- (Slack) Add threadId for user feedback
- (Copilot) Add new optional opened property has been added to the widget config
### Fixed
- Fix blinking cursor indicator
- (Copilot) Rename copilot inner div id `chainlit-copilot` to `chainlit-copilot-chat` due to naming conflict with the outer div
- Disable gzip for websocket-relaed http endpoint (Safari compatibility)
- Prevent constant refresh on the login screen when using custom authenication
- Fix MCP type hints
## [2.6.8] - 2025-08-08
### Other
- Reverted PR with newline preservation in messages due to incorrect rendering in child components like lists
## [2.6.7] - 2025-08-07
### Fixed
- Formatting when pasting HTML code and newlines in received messages
## [2.6.6] - 2025-08-05
### Added
- Add support for emoji reaction on message received in Slack
- Add Greek translation
- Copy both plain text and rich text to clipboard, if available (rich text pasting to editors like Word)
- Rename `CHAINLIT_COOKIE_PATH` to `CHAINLIT_AUTH_COOKIE_PATH` and now espect CHAINLIT_ROOT_PATH
- Add language parameter to Copilot widget configuration
### Fixed
- Prevent HTML code in user message to be rendered as HTML instead of displaying as code
- Properly parse `user_env` when `config.project.user_env` is empty
## [2.6.5] - 2025-08-02
### Fixed
- Properly escape HTML on paste
- Enable gzip compression for frontend
- Address security vulnerabilities in dependencies by upgrading them to the closest safe versions
- CI e2e tests and pnpm cache issues
## [2.6.4] - 2025-08-01
### Added
- Add streamable HTTP MCP support
- Improve e2e test stability and performance
- Add configuration for expanded copilot mode
- Add French translation
### Fixed
- Fix inputs/outputs for langchain callbacks
- Fix blinking indicator for in-progress steps
- Avoid unnecessary logo fetching when supplied in config.toml
### Other
- Bump dependencies
## [2.6.3] - 2025-07-25
### Added
- Ability to send empty commands
- Wider element view in copilot and improved styling
- Support signed urls for elements using dynamoDB persistence
- Support additional connection arguments in SQLAlchemy data layer
- Added `CHAINLIT_COOKIE_PATH` environment variable to set the cookie path
### Fixed
- Message inputs formatting
- Language pattern to allow `tzm-Latn-DZ`
- Properly encode parentheses in markdown links
- Fix chainlit data layer metadata upserts
- Improve database connection handling
- Fixed cookie path
- Improve lanchain callbacks
### Other
- Improve robustness of E2E tests
- Removed watermark "Built with Chainlit"
## [2.6.2] - 2025-07-16
Technical release due to missed `frontend` and `copilot` folders in previous one.
## [2.6.1] - 2025-07-15
### Added
- New `on_feedback` callback
- Relaxed restriction on number of starters (now more than 4 can be displayed)
### Fixed
- Command persistence when `"button": True` is missing from command definition
- `openai` and `mistralai` sub-modules fail due to incorrect `timestamp_utc` import
- Temporarily reverted fix caused the following issues with Chainlit data layer:
- `null value in column "metadata" of relation "Thread"`
- `syntax error at or near ";"`
- Google Cloud Storage private bucket support in Chainlit data layer
- Portals (popups, dialogs, etc.) now render correctly inside Copilot’s shadow DOM
### Other
- Removed telemetry
- Updated versions for Node.js, Poetry, and pnpm; added Corepack support
## [2.6.0] - 2025-07-01
### Added
- Add commands to starters
- Collapse command buttons to icons for small screens
- Add timegated custom elements
- Added ADC support for google cloud storage adapter
- Added scope as env variable (`OAUTH_COGNITO_SCOPE`) to Cognito auth provider
- Add MarkdownAlert Style Switcher. Control via `alert_style` in `config.toml`.
- Allow custom s3 endpoint for the official data layer
- Added container prop to dialog portal in Copilot shadow DOM
- Bump dependencies
- Add python 3.13 support
### Fixed
- Fix chat input double-spacing issue
- Resolve python deprecation warning for utc_now() and logger.warn
- Fixed an issue where the portal for the ChatProfiles selector was being rendered outside the Copilot shadow DOM
- Add mime type to element emitter
- Handle float/Decimal conversion for DynamoDB persistence
- Fix cancel button in Chat settings
- Only update thread metadata when not empty
### Breaking
- **LiteralAI** is being sunset and will be removed in one of the next releases. Please migrate to the official data layer instead.
- Telemetry is now opt-in by default and will be removed in the next release.
## [2.5.5] - 2025-04-14
### Added
- Avatars now support `.` in their name (will be replaced with `_`).
- Typed session accessors for user session
- Allow set attributes for the tags of the custom_js or custom_css
- Hovering a past chat in the sidebar will display the full title of the chat in a tooltip
- The `X-Chainlit-Session-id` header is now automatically set to facilitate sticky sessions with websockets
- `cl.ErrorMessage` now have a different avatar
- The copy button is now only displayed on the final message of a run, like feedback buttons
- CopilotFunction is now usable in custom JS
- Header link now have an optional `display_name` to display text next to the icon
- The default .env file loaded by chainlit is now configurable with `CHAINLIT_ENV_FILE`
### Changed
- **[breaking]**: `http_referer`, `http_cookie` and `languages` are no longer directly available in the session object. Instead, `environ` is available containing all of those plus other HTTP headers
- The scroll to the bottom animation is now smooth
## [2.4.400] - 2025-03-29
### Added
- `@cl.on_app_startup` and `@cl.on_app_shutdown`
- Configuration option for chat history default open state
- Configuration option for login page background image and filter
- Most commonly customized ui elements now have specific IDs
### Fixed
- App should no longer flicker on load
- Attachments icons for microsoft files should now correctly display
- Pasting should no longer be duplicated
## [2.4.302] - 2025-03-26
### Added
- Add thinking token support to langchain callback handler
### Fixed
- Pasting issues in the chat input
- Rename nl-NL.json to nl.json
## [2.4.301] - 2025-03-24
### Fixed
- Mcp button should not be displayed if `@on_mcp_connect` is not defined
## [2.4.3] - 2025-03-23
### Added
- Canvas mode for the element side bar if title == `canvas`
- Allow list for MCP stdio commands
- `key` parameter to `ElementSidebar.set_elements` method
### Fixed
- Literal AI should now correctly store custom elements props
- Element should correctly load from azure storage
- Plotly elements should now take full width
## [2.4.2] - 2025-03-19
### Added
- Hide commands button if all commands are specified as button.
### Fixed
- Chat profiles tooltip should no longer freeze is hover rapidly
## [2.4.1] - 2025-03-13
### Added
- The user message auto scroll behavior is now a feature `config.features.user_message_autoscroll`
- Stdio MCP commands now support environment variables
### Fixed
- Submounting a Chainlit app to a FastAPI app with a root path should now work
## [2.4.0] - 2025-03-11
### Changed
- Chainlit now requires python `>=3.10`
### Added
- MCP support through `@cl.on_mcp_connect` and `@cl.on_mcp_disconnect`
### Fixed
- Pasting text/images into Chainlit Copilot should now work
- OAuth redirection should work when submounting Chainlit with root path `/`
- Successive AskUser messages should no longer collide
### Removed
- Outdated Haystack integration
## [2.3.0] - 2025-03-09
### Added
- New user messages are now placed/scrolled to the top of the chat to enhance readability
- Commands have a new optional boolean field `button` to turn them into buttons
- Custom elements have access to a new API `sendUserMessage`
### Fixed
- Chainlit app using a custom root path should now work correctly when running in docker containers
- Chat history time groups should now be sorted properly
## [2.2.1] - 2025-02-14
### Added
- `default_open` parameter to the step decorator/class
### Fixed
- Input should not replace <,>,&
- Starters should be disabled if no ws connection
- Prevent orphaned thread record when deleting active conversation
## [2.2.0] - 2025-02-08
### Added
- You can now add custom buttons in the header
### Fixed
- Step open/close is now animated
- prevent unstyled flash when streaming code blocks
- Docking/undocking scroll while streaming show now work better
## [2.1.2] - 2025-02-05
### Fixed
- The default loader should now be displayed if the chat is running and no response is yet sent
- Pasting HTML in the chat input show now work
- React warnings and accessibility issues
- Command filtering now works with `includes` instead of `startWith`
- The submit button should be disabled in the chat input is empty
## [2.1.1] - 2025-02-03
### Fixed
- Reintroduce including URL location after UI refactor
- Ensure SAS token start time is set to UTC
- Prevent showing 0's on resumed thread if AskAction/File was used
- Remove 22px element ref height
- Update Microsoft OAuth offline_access scope to be fully qualified with the prefix
## [2.1.0] - 2025-01-30
### Added
- You can now send toasts with `cl.context.emitter.send_toast`
- Markdown now supports alerts
- Theme options are now translatable
- Copilot can now load custom css
### Fixed
- Mounting Chainlit as a sub app should no longer break the parent's app endpoints
- Pasting text in the chat input should now remove extra formatting and preserve new lines
## [2.0.603] - 2025-01-28
### Added
- Data layer initialization to the telemetry
### Fixed
- Gap between the word `Used` and tool name in step name
## [2.0.602] - 2025-01-27
### Fixed
- Chat input should now auto focus
- When unfolding a step, the `Output` title should only show if there is an input to display
## [2.0.601] - 2025-01-25
### Fixed
- Element sidebar should take full height
## [2.0.6] - 2025-01-24
### Added
- The element sidebar is now controllable from the python code
### Fixed
- The auth cookie no longer has a maximal size
- Pasting text in the chat input should now work
- Long text in AskAction buttons are now gracefully displayed
- Server connection error translation path
## [2.0.5] - 2025-01-21
### Added
- Chat GPT like commands
- Translation options. The translation schema has been simplified
### Fixed
- Warnings around file upload mime types
- `uvicorn` and `packaging` version requirement have been relaxed
## [2.0.4] - 2025-01-17
### Added
- Overhaul element reference link styling
- Japanese translations
- Improved Chinese translations
- Translations for feedback buttons
### Fixed
- Cookie max age should now correctly use the config `user_session_timeout` field
- Thread grouping in the chat history should now correctly handle timezones
- File from `AskFileMessage` should now share ID with the data layer
- Data layer boolean casting issues
- Chat settings modal scrolling issue
## [2.0.3] - 2025-01-14
### Added
- `CustomElement.update()` to update a custom element props server side
- Translation for the copy button
### Fixed
- The official data layer should not overwrite elements anymore
- A bug where resuming a thread would not load the thread
- Prevent authentication before the app is fully loaded
- Installing Chainlit from github should work again
- `tool` steps should count as a thread start
## [2.0.2] - 2025-01-10
### Added
- `http_cookie` is now available in the user session and websocket session
### Fixed
- Chat profile description on the welcome screen now supports custom html and latex
- Thread history batch size has been increased to 35 to ensure scroll on a taller screens
- Chat settings modal should now scroll if too tall
- Errors in thread resume (like thread not found) now properly redirects to the the home page
- Elements like Dataframe, Plotly or text should now load correctly from cloud storages
- AskFileMessage is now usable even if spontaneous uploads are disabled
- Remove element objects from cloud storage on thread removal (Official & SQLAlchemy data layers)
- Fix custom element `props` storage for SQL Alchemy data layer
## [2.0.1] - 2025-01-09
### Added
- `window.toggleChainlitCopilot()` to toggle the copilot
### Fixed
- Chat profiles icon and description should now be displayed on the welcome screen
- Action should be able to trigger the first interaction
- Raw code blocks should now be displayed correctly
- TextInput for chat settings should now work
- Upload attachement button should not be displayed when upload is disabled
- Removed unused numpy dependency
## [2.0.0] - 2025-01-06
The Chainlit UI (including the copilot) has been completely re-written with Shadcn/Tailwind. This brings several advantages:
1. The codebase is simpler and more contribution friendly.
2. It enabled the new custom element feature.
3. The theme customisation is more powerful.
### Added
- Custom Elements (code your own elements)
- `Cmd+k` thread search
- Thread rename
- Official PostGres open source data layer
- New `@data_layer` decorator for configuring custom data layers declaratively
### Changed
- Authentication is now based on cookies. Cross Origins are disallowed unless added in `allow_origins` in the `config.toml` file
- No longer need to click on `resume` to resume a thread
- **[breaking]**: Theme customisation is now handled in `public/theme.json` instead of `config.toml`.
- **[breaking]**: Changed fields on the `Action` class:
- The `value` field has replaced with `payload` which accepts a Python dict
- The `description` field has been renamed `tooltip`
- The field `icon` has been added
- The `collapsed` field has been removed.
- **[breaking]**: Completely revamped audio implementation (#1401, #1410):
- Replaced `AudioChunk` with `InputAudioChunk` and `OutputAudioChunk`
- Changed default audio sampling rate from 44100 to 24000
- Removed several audio configuration options (`min_decibels`, `initial_silence_timeout`, `silence_timeout`, `chunk_duration`, `max_duration`)
### Fixed
- Autoscaling of Chainlit app behind a load balancer should now work. Don't forget to enable sticky sessions
## [2.1.dev0] - 2024-11-14
Pre-release: developer preview.
### Added
- New `@data_layer` decorator for configuring custom data layers declaratively
- Unit tests for `get_data_layer()` and `@data_layer` functionality
### Changed
- Data layer configuration system now prioritizes `@data_layer` decorator over environment variables
- Data layer initialization is now more explicit and testable through the decorator pattern
- Updated example code in `/cypress/e2e/custom_data_layer` and `/cypress/e2e/data_layer` to use the new decorator
### Developer Experience
- Improved test infrastructure with new fixtures for data layer mocking
- Added comprehensive tests for data layer configuration scenarios
## [1.3.2] - 2024-11-08
### Security Advisory
**IMPORTANT**:
- This release drops support for FastAPI versions before 0.115.3 and Starlette versions before 0.41.2 due to a severe security vulnerability (CVE-2024-47874). We strongly encourage all downstream dependencies to upgrade as well.
- This release still contains a known security vulnerability in the element feature that could allow unauthorized file access. We strongly recommend against using elements in production environments until a comprehensive fix is implemented in an upcoming release.
### Security
- **[breaking]** Updated dependencies to address critical issues (#1493):
- Upgraded fastapi to 0.115.3 to address CVE-2024-47874 in Starlette
- Upgraded starlette to 0.41.2 (required for security fix)
- Upgraded werkzeug to 3.0.6
Note: This is a breaking change as older FastAPI versions are no longer supported.
To prioritize security, we opted to break with semver on this particular occasion.
### Fixed
- Resolved incorrect message ordering in UI (#1501)
## [2.0rc0] - 2024-11-08
### Security Advisory
**IMPORTANT**:
- The element feature currently contains a known security vulnerability that could allow unauthorized file access. We strongly recommend against using elements in production environments until a comprehensive fix is implemented in an upcoming release.
### Changed
- **[breaking]**: Completely revamped audio implementation (#1401, #1410):
- Replaced `AudioChunk` with `InputAudioChunk` and `OutputAudioChunk`
- Changed default audio sampling rate from 44100 to 24000
- Removed several audio configuration options (`min_decibels`, `initial_silence_timeout`, `silence_timeout`, `chunk_duration`, `max_duration`)
- Removed `RecordScreen` component
- Factored storage clients into separate modules (#1363)
### Added
- Realtime audio streaming and processing (#1401, #1406, #1410):
- New `AudioPresence` component for visual representation
- Implemented `WavRecorder` and `WavStreamPlayer` classes
- Introduced new `on_audio_start` callback
- Added audio interruption functionality
- New audio connection signaling with `on` and `off` states
- Interactive DataFrame display with auto-fit content using MUI Data Grid (#1373, #1467)
- Optional websocket connection in react-client (#1379)
- Enhanced image interaction with popup view and download option (#1402)
- Current URL included in message payload (#1403)
- Allow empty chat input when submitting attachments (#1261)
### Fixes
- Various backend fixes and cleanup (#1432):
- Use importlib.util.find_spec to check if a package is installed
- Use `raise... from` to wrap exceptions
- Fix error message in Discord integration
- Several minor fixups/cleanup
### Development
- Implemented ruff for linting and formatting (#1495)
- Added mypy daemon for faster type-checking (#1495)
- Added GitHub Actions linting (#1445)
- Enabled direct installation from GitHub (#1423)
- Various build script improvements (#1462)
## [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 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_<PROVIDER>_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)
## [1.2.0] - 2024-09-16
### Security
- Fixed critical vulnerabilities allowing arbitrary file read access (#1326)
- Improved path traversal protection in various endpoints (#1326)
### Added
- Hebrew translation JSON (#1322)
- Translation files for Indian languages (#1321)
- Support for displaying function calls as tools in Chain of Thought for LlamaIndexCallbackHandler (#1285)
- Improved feedback UI with refined type handling (#1325)
### Changed
- Upgraded cryptography from 43.0.0 to 43.0.1 in backend dependencies (#1298)
- Improved GitHub Actions workflow (#1301)
- Enhanced data layer cleanup for better performance (#1288)
- Factored out callbacks with extensive test coverage (#1292)
- Adopted strict adherence to Semantic Versioning (SemVer)
### Fixed
- Websocket connection issues when submounting Chainlit (#1337)
- Show_input functionality on chat resume for SQLAlchemy (#1221)
- Negative feedback class incorrectness (#1332)
- Interaction issues with Chat Profile Description Popover (#1276)
- Centered steps within assistant messages (#1324)
- Minor spelling errors (#1341)
### Development
- Added documentation for release engineering process (#1293)
- Implemented testing for FastAPI version matrix (#1306)
- Removed wait statements from E2E tests for improved performance (#1270)
- Bumped dataclasses to latest version (#1291)
- Ensured environment loading before other imports (#1328)
## [1.1.404] - 2024-09-04
### Security
- **[breaking]**: Listen to 127.0.0.1 (localhost) instead on 0.0.0.0 (public) (#861).
- **[breaking]**: Dropped support for Python 3.8, solving dependency resolution, addressing vulnerable dependencies (#1192, #1236, #1250).
### Fixed
- Frontend connection resuming after connection loss (#828).
- Gracefully handle HTTP errors in data layers (#1232).
- AttributeError: 'ChatCompletionChunk' object has no attribute 'get' in llama_index (#1229).
- `edit_message` in correct place in default config, allowing users to edit messages (#1218).
### Added
- `CHAINLIT_APP_ROOT` environment variable to modify `APP_ROOT`, enabling the ability to set the location of `config.toml` and other setting files (#1259).
- Poetry lockfile in GIT repository for reproducible builds (#1191).
- pytest-based testing infrastructure, first unit tests of backend and testing on all supported Python versions (#1245 and #1271).
- Black and isort added to dev dependencies group (#1217).
## [1.1.403rc0] - 2024-08-13
### Fixed
- Langchain Callback handler IndexError
- Attempt to fix websocket issues
## [1.1.402] - 2024-08-07
### Added
- The `User` class now has a `display_name` field. It will not be persisted by the data layer.
- The logout button will now reload the page (needed for custom auth providers)
## [1.1.401] - 2024-08-02
### Changed
- Directly log step input args by name instead of wrapping them in "args" for readability.
### Fixed
- Langchain Callback handler ValueError('not enough values to unpack (expected 2, got 0)')
## [1.1.400] - 2024-07-29
### Changed
- hide_cot becomes cot and has three possible values: hidden, tool_call, full
- User feedback are now scoring an entire run instead of a specific message
- Slack/Teams/Discord DM threads are now split by day
- Slack DM now also use threads
- Avatars are always displayed at the root level of the conversation
### Removed
- disable_feedback has been removed
- root_message has been removed
## [1.1.306] - 2024-07-03
### Added
- Messages are now editable. You can disable this feature with `config.features.edit_message = false`
- `cl.chat_context` to help keeping track of the messages of the current thread
- You can now enable debug_mode when mounting Chainlit as a sub app by setting the `CHAINLIT_DEBUG` to `true`.
### Fixed
- Message are now collapsible if too long
- Only first level tool calls are displayed
- OAuth redirection when mounting Chainlit on a FastAPI app should now work
- The Langchain callback handler should better capture chain runs
- The Llama Index callback handler should now work with other decorators
## [1.1.305] - 2024-06-26
### Added
- Mistral AI instrumentation
## [1.1.304] - 2024-06-21
### Fixed
- OAuth final redirection should account for root path if provided
## [1.1.303] - 2024-06-20
### Fixed
- OAuth URL redirection should be correctly formed when using CHAINLIT_URL + submounted chainlit app
## [1.1.302] - 2024-06-16
### Added
- Width and height option for the copilot bubble
### Fixed
- Chat profile icon in copilot should load
- Theme should work with Copilot
### Removed
- Running toast when an action is running
## [1.1.301] - 2024-06-14
### Fixed
- Azure AD oauth get_user_info not implemented error
## [1.1.300] - 2024-06-13
### Added
- `@cl.set_starters` and `cl.Starter` to suggest conversation starters to the user
- Teams integration
- Expand copilot button
- Debug mode when starting with `-d`. Only available if the data layer supports it. This replaces the Prompt Playground.
- `default` theme config in `config.toml`
- If only one OAuth provider is set, automatically redirect the user to it
- Input streaming for tool calls
### Changed
- **[BREAKING]** Custom endpoints have been reworked. You should now mount your Chainlit app as a FastAPI subapp.
- **[BREAKING]** Avatars have been reworked. `cl.Avatar` has been removed, instead place your avatars by name in `/public/avatars/*`
- **[BREAKING]** The `running`, `took_one` and `took_other` translations have been replaced by `used`.
- **[BREAKING]** `root` attribute of `cl.Step` has been removed. Use `cl.Message` to send root level messages.
- Chain of Thought has been reworked. Only steps of type `tool` will be displayed if `hide_cot` is false
- The `show_readme_as_default` config has been removed
- No longer collapse root level messages
- The blue alert "Continuing chat" has been removed.
### Fix
- The Chat Profile description should now disappear when not hovered.
- Error handling of steps has been improved
- No longer stream the first token twice
- Copilot should now work as expected even if the user is closing/reopening it
- Copilot CSS should no longer leak/be impacted by the host website CSS
- Fix various `cl.Context` errors
- Reworked message padding and spacing
- Chat profile should now support non-ASCII characters (like chinese)
## [1.1.202] - 2024-05-22
### Added
- Support for video players like youtube or vimeo
### Fixed
- Fix audio capture on windows browsers
## [1.1.201] - 2024-05-21
### Fixed
- Intermediary steps button placement
## [1.1.200] - 2024-05-21
### Changed
- User message UI has been updated
- Loading indicator has been improved and visually updated
- Icons have been updated
- Dark theme is now the default
### Fixed
- Scroll issues on mobile browsers
- Github button now showing
## [1.1.101] - 2024-05-14
### Added
- The discord bot now shows "typing" while responding
### Fixed
- Discord and Slack bots should no longer fail to respond if the data layer fails
## [1.1.0] - 2024-05-13
### Added
- You can know serve your Chainlit app as a Slack bot
- You can know serve your Chainlit app as a Discord bot
- `cl.on_audio_chunk` decorator to process incoming the user incoming audio stream
- `cl.on_audio_end` decorator to react to the end of the user audio stream
- The `cl.Audio` element now has an `auto_play` property
- `layout` theme config, wide or default
- `http_referer` is now available in `cl.user_session`
### Changed
- The UI has been revamped, especially the navigation
- The arrow up button has been removed from the input bar, however pressing the arrow up key still opens the last inputs menu
- The user session will no longer be persisted as metadata if > 1mb
- **[breaking]** the `send()` method on `cl.Message` now returns the message instead of the message id
- **[breaking]** The `multi_modal` feature has been renamed `spontaneous_file_upload` in the config
- Element display property now defaults to `inline` instead of `side`
- The SQL Alchemy data layer logging has been improved
### Fixed
- Fixed a bug disconnecting the user when loading the chat history
- Elements based on an URL should now have a mime type
- Stopping a task should now work better (using asyncio task.cancel)
## [1.0.506] - 2024-04-30
### Added
- add support for multiline option in TextInput chat settings field - @kevinwmerritt
### Changed
- disable gzip middleware to prevent a compression issue on safari
### Fixed
- pasting from microsoft products generates text instead of an image
- do not prevent thread history revalidation - @kevinwmerritt
- display the label instead of the value for menu item - @kevinwmerritt
### Added
## [1.0.505] - 2024-04-23
### Added
- The user's browser language configuration is available in `cl.user_session.get("languages")`
- Allow html in text elements - @jdb78
- Allow for setting a ChatProfile default - @kevinwmerritt
### Changed
- The thread history refreshes right after a new thread is created.
- The thread auto-tagging feature is now opt-in using `auto_tag_thread` in the config.toml file
### Fixed
- Fixed incorrect step ancestor in the OpenAI instrumentation
- Enabled having a `storage_provider` set to `None` in SQLAlchemyDataLayer - @mohamedalani
- Correctly serialize `generation` in SQLAlchemyDataLayer - @mohamedalani
## [1.0.504] - 2024-04-16
### Changed
- Chainlit apps should function correctly even if the data layer is down
## [1.0.503] - 2024-04-15
### Added
- Enable persisting threads using a Custom Data Layer (through SQLAlchemy) - @hayescode
### Changed
- React-client: Expose `sessionId` in `useChatSession`
- Add chat profile as thread tag metadata
### Fixed
- Add quotes around the chainlit create-secret CLI output to avoid any issues with special characters
## [1.0.502] - 2024-04-08
### Added
- Actions now trigger conversation persistence
## [1.0.501] - 2024-04-08
### Added
- Messages and steps now accept tags and metadata (useful for the data layer)
### Changed
- The LLama Index callback handler should now show retrieved chunks in the intermadiary steps
- Renamed the Literal environment variable to `LITERAL_API_URL` (it used to be `LITERAL_SERVER`)
### Fixed
- Starting a new conversation should close the element side bar
- Resolved security issues by upgrading starlette dependency
## [1.0.500] - 2024-04-02
### Added
- Added a new command `chainlit lint-translations` to check that translations file are OK
- Added new sections to the translations, like signin page
- chainlit.md now supports translations based on the browser's language. Like chainlit_pt-BR.md
- A health check endpoint is now available through a HEAD http call at root
- You can now specify a custom frontend build path
### Fixed
- Translated will no longer flash at app load
- Llama Index callback handler has been updated
- File watcher should now properly refresh the app when the code changes
- Markdown titles should now have the correct line height
### Changed
- `multi_modal` is now under feature in the config.toml and has more granularity
- Feedback no longer has a -1 value. Instead a delete_feedback method has been added to the data layer
- ThreadDict no longer has the full User object. Instead it has user_id and user_identifier fields
## [1.0.400] - 2024-03-06
### Added
- OpenAI integration
### Fixed
- Langchain final answer streaming should work again
- Elements with public URLs should be correctly persisted by the data layer
### Changed
- Enforce UTC DateTimes
## [1.0.300] - 2024-02-19
### Added
- Custom js script injection
- First token and token throughput per second metrics
### Changed
- The `ChatGeneration` and `CompletionGeneration` has been reworked to better match the OpenAI semantics
## [1.0.200] - 2024-01-22
### Added
- Chainlit Copilot
- Translations
- Custom font
### Fixed
- Tasklist flickering
## [1.0.101] - 2024-01-12
### Fixed
- Llama index callback handler should now correctly nest the intermediary steps
- Toggling hide_cot parameter in the UI should correctly hide the `took n steps` buttons
- `running` loading button should only be displayed once when `hide_cot` is true and a message is being streamed
## [1.0.100] - 2024-01-10
### Added
- `on_logout` hook allowing to clear cookies when a user logs out
### Changed
- Chainlit apps won't crash anymore if the data layer is not reachable
### Fixed
- File upload now works when switching chat profiles
- Avatar with an image no longer have a background color
- If `hide_cot` is set to `true`, the UI will never get the intermediary steps (but they will still be persisted)
- Fixed a bug preventing to open past chats
## [1.0.0] - 2024-01-08
### Added
- Scroll down button
- If `hide_cot` is set to `true`, a `running` loader is displayed by default under the last message when a task is running.
### Changed
- Avatars are now always displayed
- Chat history sidebar has been revamped
- Stop task button has been moved to the input bar
### Fixed
- If `hide_cot` is set to `true`, the UI will never get the intermediary steps (but they will still be persisted)
## [1.0.0rc3] - 2023-12-21
### Fixed
- Elements are now working when authenticated
- First interaction is correctly set when resuming a chat
### Changed
- The copy button is hidden if `disable_feedback` is `true`
## [1.0.0rc2] - 2023-12-18
### Added
- Copy button under messages
- OAuth samesite cookie policy is now configurable through the `CHAINLIT_COOKIE_SAMESITE` env var
### Changed
- Relax Python version requirements
- If `hide_cot` is configured to `true`, steps will never be sent to the UI, but still persisted.
- Message buttons are now positioned below
## [1.0.0rc0] - 2023-12-12
### Added
- cl.Step
### Changed
- File upload uses HTTP instead of WS and no longer has size limitation
- `cl.AppUser` becomes `cl.User`
- `Prompt` has been split in `ChatGeneration` and `CompletionGeneration`
- `Action` now display a toaster in the UI while running
## [0.7.700] - 2023-11-28
### Added
- Support for custom HTML in message content is now an opt in feature in the config
- Uvicorn `ws_per_message_deflate` config param is now configurable like `UVICORN_WS_PER_MESSAGE_DEFLATE=false`
### Changed
- Latex support is no longer enabled by default and is now a feature in the config
### Fixed
- Fixed LCEL memory message order in the prompt playground
- Fixed a key error when using the file watcher (-w)
- Fixed several user experience issues with `on_chat_resume`
- `on_chat_end` is now always called when a chat ends
- Switching chat profiles correctly clears previous AskMessages
## [0.7.604] - 2023-11-15
### Fixed
- `on_chat_resume` now works properly with non json serializable objects
- `LangchainCallbackHandler` no longer send tokens to the wrong user under high concurrency
- Langchain cache should work when `cache` is to `true` in `config.toml`
## [0.7.603] - 2023-11-15
### Fixed
- Markdown links special characters are no longer encoded
- Collapsed messages no longer make the chat scroll
- Stringified Python objects are now displayed in a Python code block
## [0.7.602] - 2023-11-14
### Added
- Latex support (only supporting $$ notation)
- Go back button on element page
### Fixed
- Code blocks should no longer flicker or display `[object object]`.
- Now properly displaying empty messages with inlined elements
- Fixed `Too many values to unpack error` in langchain callback
- Langchain final streamed answer is now annotable with human feedback
- AzureOpenAI should now work properly in the Prompt Playground
### Changed
- Code blocks display has been enhanced
- Replaced aiohttp with httpx
- Prompt Playground has been updated to work with the new openai release (v1). Including tools
- Auth0 oauth provider has a new configurable env variable `OAUTH_AUTH0_ORIGINAL_DOMAIN`
## [0.7.500] - 2023-11-07
### Added
- `cl.on_chat_resume` decorator to enable users to continue a conversation.
- Support for OpenAI functions in the Prompt Playground
- Ability to add/remove messages in the Prompt Playground
- Plotly element to display interactive charts
### Fixed
- Langchain intermediate steps display are now much more readable
- Chat history loading latency has been enhanced
- UTF-8 characters are now correctly displayed in json code blocks
- Select widget `items` attribute is now working properly
- Chat profiles widget is no longer scrolling horizontally
## [0.7.400] - 2023-10-27
### Added
- Support for Langchain Expression Language. https://docs.chainlit.io/integrations/langchain
- UI rendering optimization to guarantee high framerate
- Chainlit Cloud latency optimization
- Speech recognition to type messages. https://docs.chainlit.io/backend/config/features
- Descope OAuth provider
### Changed
- `LangchainCallbackHandler` is now displaying inputs and outputs of intermediate steps.
### Fixed
- AskUserMessage now work properly with data persistence
- You can now use a custom okta authorization server for authentication
## [0.7.3] - 2023-10-17
### Added
- `ChatProfile` allows to configure different agents that the user can freely chose
- Multi modal support at the input bar level. Enabled by `features.multi_modal` in the config
- `cl.AskUserAction` allows to block code execution until the user clicked an action.
- Displaying readme when chat is empty is now configurable through `ui.show_readme_as_default` in the config
### Changed
- `cl.on_message` is no longer taking a string as parameter but rather a `cl.Message`
### Fixed
- Chat history is now correctly displayed on mobile
- Azure AD OAuth authentication should now correctly display the user profile picture
### Removed
- `@cl.on_file_upload` is replaced by true multi modal support at the input bar level
## [0.7.2] - 2023-10-10
### Added
- Logo is displayed in the UI header (works with custom logo)
- Azure AD single tenant is now supported
- `collapsed` attribute on the `Action` class
- Latency improvements when data persistence is enabled
### Changed
- Chat history has been entirely reworked
- Chat messages redesign
- `config.ui.base_url` becomes `CHAINLIT_URL` env variable
### Fixed
- File watcher (-w) is now working with nested module imports
- Unsupported character during OAuth authentication
## [0.7.1] - 2023-09-29
### Added
- Pydantic v2 support
- Okta auth provider
- Auth0 auth provider
- Prompt playground support for mix of template/formatted prompts
- `@cl.on_chat_end` decorator
- Textual comments to user feedback
### Fixed
- Langchain errors are now correctly indented
- Langchain nested chains prompts are now correctly displayed
- Langchain error TypeError: 'NoneType' object is not a mapping.
- Actions are now displayed on mobile
- Custom logo is now working as intended
## [0.7.0] - 2023-09-13
### Changed
- Authentication is now unopinionated:
1. `@cl.password_auth_callback` for login/password auth
2. `@cl.oauth_callback` for oAuth auth
3. `@cl.header_auth_callback` for header auth
- Data persistence is now enabled through `CHAINLIT_API_KEY` env variable
### Removed
- `@cl.auth_client_factory` (see new authentication)
- `@cl.db_client_factory` (see new data persistence)
### Added
- `disable_human_feedback` parameter on `cl.Message`
- Configurable logo
- Configurable favicon
- Custom CSS injection
- GCP Vertex AI LLM provider
- Long message collpasing feature flag
- Enable Prompt Playground feature flag
### Fixed
- History page filters now work properly
- History page does not show empty conversations anymore
- Langchain callback handler Message errors
## [0.6.4] - 2023-08-30
### Added
- `@cl.on_file_upload` to enable spontaneous file uploads
- `LangchainGenericProvider` to add any Langchain LLM in the Prompt Playground
- `cl.Message` content now support dict (previously only supported string)
- Long messages are now collapsed by default
### Fixed
- Deadlock in the Llama Index callback handler
- Langchain MessagesPlaceholder and FunctionMessage are now correctly supported
## [0.6.3] - 2023-08-22
### Added
- Complete rework of the Prompt playground. Now supports custom LLMs, templates, variables and more
- Enhanced Langchain final answer streaming
- `remove_actions` method on the `Message` class
- Button to clear message history
### Fixed
- Chainlit CLI performance issue
- Llama Index v0.8+ callback handler. Now supports messages prompts
- Tasklist display, persistence and `.remove()`
- Custom headers growing infinitely large
- Action callback can now handle multiple actions
- Langflow integration load_flow_from_json
- Video and audio elements on Safari
## [0.6.2] - 2023-08-06
### Added
- Make the chat experience configurable with Chat Settings
- Authenticate users based on custom headers with the Custom Auth client
### Fixed
- Author rename now works with all kinds of messages
- Create message error with chainlit cloud (chenjuneking)
## [0.6.1] - 2023-07-24
### Added
- Security improvements
- Haystack callback handler
- Theme customizability
### Fixed
- Allow multiple browser tabs to connect to one Chainlit app
- Sidebar blocking the send button on mobile
## [0.6.0] - 2023-07-20
### Breaking changes
- Factories, run and post process decorators are removed.
- langchain_rename becomes author_rename and works globally
- Message.update signature changed
Migration guide available [here](https://docs.chainlit.io/guides/migration/0.6.0).
### Added
- Langchain final answer streaming
- Redesign of chainlit input elements
- Possibility to add custom endpoints to the fast api server
- New File Element
- Copy button in code blocks
### Fixed
- Persist session between websocket reconnection
- The UI is now more mobile friendly
- Avatar element Path parameter
- Increased web socket message max size to 100 mb
- Duplicated conversations in the history tab
## [0.5.2] - 2023-07-10
### Added
- Add the video element
### Fixed
- Fix the inline element flashing when scrolling the page, due to un-needed re-rendering
- Fix the orange flash effect on messages
## [0.5.1] - 2023-07-06
### Added
- Task list element
- Audio element
- All elements can use the `.remove()` method to remove themselves from the UI
- Can now use cloud auth with any data persistence mode (like local)
- Microsoft auth
### Fixed
- Files in app dir are now properly served (typical use case is displaying an image in the readme)
- Add missing attribute `size` to Pyplot element
## [0.5.0] - 2023-06-28
### Added
- Llama Index integration. Learn more [here](https://docs.chainlit.io/integrations/llama-index).
- Langflow integration. Learn more [here](https://docs.chainlit.io/integrations/langflow).
### Fixed
- AskUserMessage.remove() now works properly
- Avatar element cannot be referenced in messages anymore
## [0.4.2] - 2023-06-26
### Added
- New data persistence mode `local` and `custom` are available on top of the pre-existing `cloud` one. Learn more [here](https://docs.chainlit.io/data).
## [0.4.101] - 2023-06-24
### Fixed
- Performance improvements and bug fixes on run_sync and asyncify
## [0.4.1] - 2023-06-20
### Added
- File watcher now reloads the app when the config is updated
- cl.cache to avoid wasting time reloading expensive resources every time the app reloads
### Fixed
- Bug introduced by 0.4.0 preventing to run private apps
- Long line content breaking the sidebar with Text elements
- File watcher preventing to keyboard interrupt the chainlit process
- Updated socket io to fix a security issue
- Bug preventing config settings to be the default values for the settings in the UI
## [0.4.0] - 2023-06-16
### Added
- Pyplot chart element
- Config option `default_expand_messages` to enable the default expand message settings by default in the UI (breaking change)
### Fixed
- Scoped elements sharing names are now correctly displayed
- Clickable Element refs are now correctly displayed, even if another ref being a substring of it exists
## [0.3.0] - 2023-06-13
### Added
- Moving from sync to async runtime (breaking change):
- Support async implementation (eg openai, langchain)
- Performance improvements
- Removed patching of different libraries
- Elements:
- Merged LocalImage and RemoteImage to Image (breaking change)
- New Avatar element to display avatars in messages
- AskFileMessage now supports multi file uploads (small breaking change)
- New settings interface including a new "Expand all" messages setting
- The element sidebar is resizable
### Fixed
- Secure origin issues when running on HTTP
- Updated the callback handler to langchain 0.0.198 latest changes
- Filewatcher issues
- Blank screen issues
- Port option in the CLI does not fail anymore because of os import
## [0.2.111] - 2023-06-09
### Fixed
- Pdf element reloading issue
- CI is more stable
## [0.2.110] - 2023-06-08
### Added
- `AskFileMessage`'s accept parameter can now can take a Dict to allow more fine grained rules. More infos here https://react-dropzone.org/#!/Accepting%20specific%20file%20types.
- The PDF viewer element helps you display local or remote PDF files ([documentation](https://docs.chainlit.io/api-reference/elements/pdf-viewer)).
### Fixed
- When running the tests, the chainlit cli is installed is installed in editable mode to run faster.
## [0.2.109] - 2023-05-31
### Added
- URL preview for social media share
### Fixed
- `max_http_buffer_size` is now set to 100mb, fixing the `max_size_mb` parameter of `AskFileMessage`
## [0.2.108] - 2023-05-30
### Fixed
- Enhanced security
- Global element display
- Display elements with display `page` based on their ids instead of their names
## [0.2.107] - 2023-05-28
### Added
- Rework of the Message, AskUserMessage and AskFileMessage APIs:
- `cl.send_message(...)` becomes `cl.Message(...).send()`
- `cl.send_ask_user(...)` becomes `cl.AskUserMessage(...).send()`
- `cl.send_ask_file(...)` becomes `cl.AskFileMessage(...).send()`
- `update` and `remove` methods to the `cl.Message` class
### Fixed
- Blank screen for windows users (https://github.com/Chainlit/chainlit/issues/3)
- Header navigation for mobile (https://github.com/Chainlit/chainlit/issues/12)
## [0.2.106] - 2023-05-26
### Added
- Starting to log changes in CHANGELOG.md
- Port and hostname are now configurable through the `CHAINLIT_HOST` and `CHAINLIT_PORT` env variables. You can also use `--host` and `--port` when running `chainlit run ...`.
- A label attribute to Actions to facilitate localization.
### Fixed
- Clicks on inlined `RemoteImage` now opens the image in a NEW tab.
================================================
FILE: CONTRIBUTING.md
================================================
# Contribute to Chainlit
To contribute to Chainlit, you first need to set up the project on your local machine.
## Table of Contents
<!--
Generated using https://ecotrust-canada.github.io/markdown-toc/.
I've copy/pasted the whole document there, and then formatted it with prettier.
-->
- [Contribute to Chainlit](#contribute-to-chainlit)
- [Table of Contents](#table-of-contents)
- [Local setup](#local-setup)
- [Requirements](#requirements)
- [Set up the repo](#set-up-the-repo)
- [Install dependencies](#install-dependencies)
- [Build Frontend](#build-frontend)
- [Start the Chainlit server from source](#start-the-chainlit-server-from-source)
- [Start the UI from source](#start-the-ui-from-source)
- [Run the tests](#run-the-tests)
- [Backend unit tests](#backend-unit-tests)
- [E2E tests](#e2e-tests)
- [Headed/debugging](#headeddebugging)
## Local setup
### Requirements
1. Python >= `3.10`
2. uv ([See how to install](https://docs.astral.sh/uv/getting-started/installation/))
3. NodeJS >= `24` ([See how to install](https://nodejs.org/en/download))
4. Pnpm ([See how to install](https://pnpm.io/installation))
> **Note**
> If you are on windows, some pnpm commands like `pnpm run formatPython` won't work. You can fix this by changing the pnpm script-shell to bash: `pnpm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe"` (default x64 install location, [Info](https://pnpm.io/cli/run#script-shell))
### Set up the repo
With this setup you can easily code in your fork and fetch updates from the main repository.
1. Go to [https://github.com/Chainlit/chainlit/fork](https://github.com/Chainlit/chainlit/fork) to fork the chainlit code into your own repository.
2. Clone your fork locally
```sh
git clone https://github.com/YOUR_USERNAME/YOUR_FORK.git
```
3. Go into your fork and list the current configured remote repository.
```sh
$ git remote -v
> origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
> origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
```
4. Specify the new remote upstream repository that will be synced with the fork.
```sh
git remote add upstream https://github.com/Chainlit/chainlit.git
```
5. Verify the new upstream repository you've specified for your fork.
```sh
$ git remote -v
> origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
> origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
> upstream https://github.com/Chainlit/chainlit.git (fetch)
> upstream https://github.com/Chainlit/chainlit.git (push)
```
### Install dependencies
The following command will install Python dependencies, Node (pnpm) dependencies and build the frontend.
```sh
cd backend
uv sync --extra tests --extra mypy --extra dev --extra custom-data
```
## Start the Chainlit server from source
Start by running `backend/chainlit/sample/hello.py` as an example.
```sh
cd backend
uv run chainlit run chainlit/sample/hello.py
```
You should now be able to access the Chainlit app you just launched on `http://127.0.0.1:8000`.
If you've made it this far, you can now replace `chainlit/sample/hello.py` by your own target. 😎
## Start the UI from source
First, you will have to start the server either [from source](#start-the-chainlit-server-from-source) or with `chainlit run...`. Since we are starting the UI from source, you can start the server with the `-h` (headless) option.
Then, start the UI.
```sh
cd frontend
pnpm run dev
```
If you visit `http://localhost:5173/`, it should connect to your local server. If the local server is not running, it should say that it can't connect to the server.
## Run the tests
### Backend unit tests
This will run the backend's unit tests.
```sh
cd backend
uv run pytest --cov=chainlit
```
### E2E tests
You may need additional configuration or dependency installation to run Cypress. See the [Cypress system requirements](https://docs.cypress.io/app/get-started/install-cypress#System-requirements) for details.
This will run end to end tests, assessing both the frontend, the backend and their interaction. First install cypress with `pnpm exec cypress install`, and then run:
```sh
// from root
pnpm test // will do cypress run
pnpm test -- --spec cypress/e2e/copilot // will run single test with the name copilot
pnpm test -- --spec "cypress/e2e/copilot,cypress/e2e/data_layer" // will run two tests with the names copilot and data_layer
pnpm test -- --spec "cypress/e2e/**/async-*" // will run all async tests
pnpm test -- --spec "cypress/e2e/**/sync-*" // will run all sync tests
pnpm test -- --spec "cypress/e2e/**/spec.cy.ts" // will run all usual tests
```
(Go grab a cup of something, this will take a while.)
For debugging purposes, you can use the **interactive mode** (Cypress UI). Run:
```
pnpm test:interactive // runs `cypress open`
```
Once you create a pull request, the tests will automatically run. It is a good practice to run the tests locally before pushing.
Make sure to run `uv sync` again whenever you've updated the frontend!
### Headed/debugging
Causes the Electron browser to be shown on screen and keeps it open after tests are done.
Extremely useful for debugging!
```sh
SINGLE_TEST=password_auth CYPRESS_OPTIONS='--headed --no-exit' pnpm test
```
================================================
FILE: LICENSE
================================================
Copyright 2023- The Chainlit team. All rights reserved.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: PRIVACY_POLICY.md
================================================
# Privacy Policy
Chainlit doesn't collect any data from its users after 2.6.1 release.
================================================
FILE: RELENG.md
================================================
# Release Engineering Instructions
This document outlines the steps for maintainers to create a new release of the project.
## Prerequisites
- You must have maintainer permissions on the repo to create a new release.
## Steps
1. **Determine the new version number**:
- We use semantic versioning (major.minor.patch).
- Increment the major version for breaking changes, minor version for new features, patch version for bug fixes only.
- If unsure, discuss with the maintainers to determine if it should be a major/minor version bump or new patch version.
2. **Bump the package version**:
- Update `version` in `backend/chainlit/version.py`.
- Update `version` in `libs/*/package.json` if there were any changes in the corresponding directories.
3. **Update the changelog**:
- Create a pull request to update the CHANGELOG.md file with the changes for the new release.
- Mark any breaking changes clearly.
- Get the changelog update PR reviewed and merged.
4. **Create a new release**:
- In the GitHub repo, go to the "Releases" page and click "Draft a new release".
- Input the new version number as the tag (e.g. 4.0.4).
- Use the "Generate release notes" button to auto-populate the release notes from the changelog.
- Review the release notes, make any needed edits for clarity.
- If this is a full release after an RC, remove any "-rc" suffix from the version number.
- Publish the release.
5. **Update any associated documentation and examples**:
- If needed, create PRs to update the version referenced in the docs and example code to match the newly released version.
- Especially important for documented breaking changes.
## RC (Release Candidate) Releases
- We create RC releases to allow testing before a full stable release
- Append "-rc" to the version number (e.g. 4.0.4-rc)
- Normally only bug fixes, no new features, between an RC and the final release version
Ping @dokterbob or @willydouhard for any questions or issues with the release process. Happy releasing!
================================================
FILE: backend/build.py
================================================
"""Build script gets called on uv/pip build."""
import pathlib
import shutil
import subprocess
import sys
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
class BuildError(Exception):
"""Custom exception for build failures"""
pass
def run_subprocess(cmd: list[str], cwd: pathlib.Path) -> None:
"""
Run a subprocess, allowing natural signal propagation.
Args:
cmd: Command and arguments as a list of strings
cwd: Working directory for the subprocess
"""
print(f"-- Running: {' '.join(cmd)}")
subprocess.run(cmd, cwd=cwd, check=True)
def pnpm_install(project_root: pathlib.Path, pnpm_path: str):
run_subprocess([pnpm_path, "install", "--frozen-lockfile"], project_root)
def pnpm_buildui(project_root: pathlib.Path, pnpm_path: str):
run_subprocess([pnpm_path, "buildUi"], project_root)
def copy_directory(src: pathlib.Path, dst: pathlib.Path, description: str):
"""Copy directory with proper error handling"""
print(f"Copying {description} from {src} to {dst}")
try:
if dst.exists():
shutil.rmtree(dst)
dst.mkdir(parents=True)
shutil.copytree(src, dst, dirs_exist_ok=True)
except KeyboardInterrupt:
print("\nInterrupt received during copy operation...")
# Clean up partial copies
if dst.exists():
shutil.rmtree(dst)
raise
except Exception as e:
raise BuildError(f"Failed to copy {src} to {dst}: {e!s}")
def copy_frontend(project_root: pathlib.Path):
"""Copy the frontend dist directory to the backend for inclusion in the package."""
backend_frontend_dir = project_root / "backend" / "chainlit" / "frontend" / "dist"
frontend_dist = project_root / "frontend" / "dist"
copy_directory(frontend_dist, backend_frontend_dir, "frontend assets")
def copy_copilot(project_root: pathlib.Path):
"""Copy the copilot dist directory to the backend for inclusion in the package."""
backend_copilot_dir = project_root / "backend" / "chainlit" / "copilot" / "dist"
copilot_dist = project_root / "libs" / "copilot" / "dist"
copy_directory(copilot_dist, backend_copilot_dir, "copilot assets")
def build():
"""Main build function with proper error handling"""
print(
"\n-- Building frontend, this might take a while!\n\n"
" If you don't need to build the frontend and just want dependencies installed, use:\n"
" `uv sync --no-install-project --no-editable`\n"
)
try:
# Find directory containing this file
backend_dir = pathlib.Path(__file__).resolve().parent
project_root = backend_dir.parent
# Dirty hack to distinguish between building wheel from sdist and from source code
if not (project_root / "package.json").exists():
return
pnpm = shutil.which("pnpm")
if not pnpm:
raise BuildError("pnpm not found!")
pnpm_install(project_root, pnpm)
pnpm_buildui(project_root, pnpm)
copy_frontend(project_root)
copy_copilot(project_root)
except KeyboardInterrupt:
print("\nBuild interrupted by user")
sys.exit(1)
except BuildError as e:
print(f"\nBuild failed: {e!s}")
sys.exit(1)
except Exception as e:
print(f"\nUnexpected error: {e!s}")
sys.exit(1)
class CustomBuildHook(BuildHookInterface):
def initialize(self, _, __):
build()
================================================
FILE: backend/chainlit/__init__.py
================================================
import os
from dotenv import load_dotenv
# ruff: noqa: E402
# Keep this here to ensure imports have environment available.
env_file = os.getenv("CHAINLIT_ENV_FILE", ".env")
env_found = load_dotenv(dotenv_path=os.path.join(os.getcwd(), env_file))
from chainlit.logger import logger
if env_found:
logger.info(f"Loaded {env_file} file")
import asyncio
from typing import TYPE_CHECKING, Any, Dict
from literalai import ChatGeneration, CompletionGeneration, GenerationMessage
from pydantic.dataclasses import dataclass
import chainlit.input_widget as input_widget
from chainlit.action import Action
from chainlit.cache import cache
from chainlit.chat_context import chat_context
from chainlit.chat_settings import ChatSettings
from chainlit.context import context
from chainlit.element import (
Audio,
CustomElement,
Dataframe,
File,
Image,
Pdf,
Plotly,
Pyplot,
Task,
TaskList,
TaskStatus,
Text,
Video,
)
from chainlit.message import (
AskActionMessage,
AskElementMessage,
AskFileMessage,
AskUserMessage,
ErrorMessage,
Message,
)
from chainlit.mode import Mode, ModeOption
from chainlit.sidebar import ElementSidebar
from chainlit.step import Step, step
from chainlit.sync import make_async, run_sync
from chainlit.types import (
ChatProfile,
InputAudioChunk,
OutputAudioChunk,
Starter,
StarterCategory,
)
from chainlit.user import PersistedUser, User
from chainlit.user_session import user_session
from chainlit.utils import make_module_getattr
from chainlit.version import __version__
from .callbacks import (
action_callback,
author_rename,
data_layer,
header_auth_callback,
oauth_callback,
on_app_shutdown,
on_app_startup,
on_audio_chunk,
on_audio_end,
on_audio_start,
on_chat_end,
on_chat_resume,
on_chat_start,
on_feedback,
on_logout,
on_mcp_connect,
on_mcp_disconnect,
on_message,
on_settings_edit,
on_settings_update,
on_shared_thread_view,
on_slack_reaction_added,
on_stop,
on_window_message,
password_auth_callback,
send_window_message,
set_chat_profiles,
set_starter_categories,
set_starters,
)
if TYPE_CHECKING:
from chainlit.langchain.callbacks import (
AsyncLangchainCallbackHandler,
LangchainCallbackHandler,
)
from chainlit.llama_index.callbacks import LlamaIndexCallbackHandler
from chainlit.mistralai import instrument_mistralai
from chainlit.openai import instrument_openai
from chainlit.semantic_kernel import SemanticKernelFilter
def sleep(duration: int):
"""
Sleep for a given duration.
Args:
duration (int): The duration in seconds.
"""
return asyncio.sleep(duration)
@dataclass()
class CopilotFunction:
name: str
args: Dict[str, Any]
def acall(self):
return context.emitter.send_call_fn(self.name, self.args)
__getattr__ = make_module_getattr(
{
"LangchainCallbackHandler": "chainlit.langchain.callbacks",
"AsyncLangchainCallbackHandler": "chainlit.langchain.callbacks",
"LlamaIndexCallbackHandler": "chainlit.llama_index.callbacks",
"instrument_openai": "chainlit.openai",
"instrument_mistralai": "chainlit.mistralai",
"SemanticKernelFilter": "chainlit.semantic_kernel",
"server": "chainlit.server",
}
)
__all__ = [
"Action",
"AskActionMessage",
"AskElementMessage",
"AskFileMessage",
"AskUserMessage",
"AsyncLangchainCallbackHandler",
"Audio",
"ChatGeneration",
"ChatProfile",
"ChatSettings",
"CompletionGeneration",
"CopilotFunction",
"CustomElement",
"Dataframe",
"ElementSidebar",
"ErrorMessage",
"File",
"GenerationMessage",
"Image",
"InputAudioChunk",
"LangchainCallbackHandler",
"LlamaIndexCallbackHandler",
"Message",
"Mode",
"ModeOption",
"OutputAudioChunk",
"Pdf",
"PersistedUser",
"Plotly",
"Pyplot",
"SemanticKernelFilter",
"Starter",
"StarterCategory",
"Step",
"Task",
"TaskList",
"TaskStatus",
"Text",
"User",
"Video",
"__version__",
"action_callback",
"author_rename",
"cache",
"chat_context",
"context",
"data_layer",
"header_auth_callback",
"input_widget",
"instrument_mistralai",
"instrument_openai",
"make_async",
"oauth_callback",
"on_app_shutdown",
"on_app_startup",
"on_audio_chunk",
"on_audio_end",
"on_audio_start",
"on_chat_end",
"on_chat_resume",
"on_chat_start",
"on_feedback",
"on_logout",
"on_mcp_connect",
"on_mcp_disconnect",
"on_message",
"on_settings_edit",
"on_settings_update",
"on_shared_thread_view",
"on_slack_reaction_added",
"on_stop",
"on_window_message",
"password_auth_callback",
"run_sync",
"send_window_message",
"set_chat_profiles",
"set_starter_categories",
"set_starters",
"sleep",
"step",
"user_session",
]
def __dir__():
return __all__
================================================
FILE: backend/chainlit/__main__.py
================================================
from chainlit.cli import cli
if __name__ == "__main__":
cli(prog_name="chainlit")
================================================
FILE: backend/chainlit/_utils.py
================================================
"""Util functions which are explicitly not part of the public API."""
from pathlib import Path
def is_path_inside(child_path: Path, parent_path: Path) -> bool:
"""Check if the child path is inside the parent path."""
return parent_path.resolve() in child_path.resolve().parents
================================================
FILE: backend/chainlit/action.py
================================================
import uuid
from typing import Dict, Optional
from dataclasses_json import DataClassJsonMixin
from pydantic import Field
from pydantic.dataclasses import dataclass
from chainlit.context import context
@dataclass
class Action(DataClassJsonMixin):
# Name of the action, this should be used in the action_callback
name: str
# The parameters to call this action with.
payload: Dict
# The label of the action. This is what the user will see.
label: str = ""
# The tooltip of the action button. This is what the user will see when they hover the action.
tooltip: str = ""
# The lucid icon name for this action.
icon: Optional[str] = None
# This should not be set manually, only used internally.
forId: Optional[str] = None
# The ID of the action
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
async def send(self, for_id: str):
self.forId = for_id
await context.emitter.emit("action", self.to_dict())
async def remove(self):
await context.emitter.emit("remove_action", self.to_dict())
================================================
FILE: backend/chainlit/auth/__init__.py
================================================
import os
from fastapi import Depends, HTTPException
from chainlit.config import config
from chainlit.data import get_data_layer
from chainlit.logger import logger
from chainlit.oauth_providers import get_configured_oauth_providers
from .cookie import (
OAuth2PasswordBearerWithCookie,
clear_auth_cookie,
get_token_from_cookies,
set_auth_cookie,
)
from .jwt import create_jwt, decode_jwt, get_jwt_secret
reuseable_oauth = OAuth2PasswordBearerWithCookie(tokenUrl="/login", auto_error=False)
def ensure_jwt_secret():
if require_login() and get_jwt_secret() is None:
raise ValueError(
"You must provide a JWT secret in the environment to use authentication. Run `chainlit create-secret` to generate one."
)
def is_oauth_enabled():
return config.code.oauth_callback and len(get_configured_oauth_providers()) > 0
def require_login():
return (
bool(os.environ.get("CHAINLIT_CUSTOM_AUTH"))
or config.code.password_auth_callback is not None
or config.code.header_auth_callback is not None
or is_oauth_enabled()
)
def get_configuration():
return {
"requireLogin": require_login(),
"passwordAuth": config.code.password_auth_callback is not None,
"headerAuth": config.code.header_auth_callback is not None,
"oauthProviders": (
get_configured_oauth_providers() if is_oauth_enabled() else []
),
"default_theme": config.ui.default_theme,
"ui": {
"login_page_image": config.ui.login_page_image,
"login_page_image_filter": config.ui.login_page_image_filter,
"login_page_image_dark_filter": config.ui.login_page_image_dark_filter,
},
}
async def authenticate_user(token: str = Depends(reuseable_oauth)):
try:
user = decode_jwt(token)
except Exception as e:
raise HTTPException(
status_code=401, detail="Invalid authentication token"
) from e
if data_layer := get_data_layer():
# Get or create persistent user if we've a data layer available.
try:
persisted_user = await data_layer.get_user(user.identifier)
if persisted_user is None:
persisted_user = await data_layer.create_user(user)
assert persisted_user
except Exception as e:
logger.exception("Unable to get persisted_user from data layer: %s", e)
return user
if user and user.display_name:
# Copy ephemeral display_name from authenticated user to persistent user.
persisted_user.display_name = user.display_name
return persisted_user
return user
async def get_current_user(token: str = Depends(reuseable_oauth)):
if not require_login():
return None
return await authenticate_user(token)
__all__ = [
"clear_auth_cookie",
"create_jwt",
"get_configuration",
"get_current_user",
"get_token_from_cookies",
"set_auth_cookie",
]
================================================
FILE: backend/chainlit/auth/cookie.py
================================================
import os
from typing import Literal, Optional, cast
from fastapi import Request, Response
from fastapi.exceptions import HTTPException
from fastapi.security.base import SecurityBase
from fastapi.security.utils import get_authorization_scheme_param
from starlette.status import HTTP_401_UNAUTHORIZED
from chainlit.config import config
""" Module level cookie settings. """
_cookie_samesite = cast(
Literal["lax", "strict", "none"],
os.environ.get("CHAINLIT_COOKIE_SAMESITE", "lax"),
)
assert _cookie_samesite in [
"lax",
"strict",
"none",
], (
"Invalid value for CHAINLIT_COOKIE_SAMESITE. Must be one of 'lax', 'strict' or 'none'."
)
_cookie_secure = _cookie_samesite == "none"
if _cookie_root_path := os.environ.get("CHAINLIT_ROOT_PATH", None):
_cookie_path = os.environ.get(_cookie_root_path, "/")
else:
_cookie_path = os.environ.get("CHAINLIT_AUTH_COOKIE_PATH", "/")
_state_cookie_lifetime = int(
os.environ.get("CHAINLIT_STATE_COOKIE_LIFETIME", str(3 * 60))
)
_auth_cookie_name = os.environ.get("CHAINLIT_AUTH_COOKIE_NAME", "access_token")
_state_cookie_name = "oauth_state"
class OAuth2PasswordBearerWithCookie(SecurityBase):
"""
OAuth2 password flow with cookie support with fallback to bearer token.
"""
def __init__(
self,
tokenUrl: str,
scheme_name: Optional[str] = None,
auto_error: bool = True,
):
self.tokenUrl = tokenUrl
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
async def __call__(self, request: Request) -> Optional[str]:
# First try to get the token from the cookie
token = get_token_from_cookies(request.cookies)
# If no cookie, try the Authorization header as fallback
if not token:
# TODO: Only bother to check if cookie auth is explicitly disabled.
authorization = request.headers.get("Authorization")
if authorization:
scheme, token = get_authorization_scheme_param(authorization)
if scheme.lower() != "bearer":
if self.auto_error:
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
else:
return None
else:
if self.auto_error:
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"},
)
else:
return None
return token
def _get_chunked_cookie(cookies: dict[str, str], name: str) -> Optional[str]:
# Gather all auth_chunk_i cookies, sorted by their index
chunk_parts = []
i = 0
while True:
cookie_key = f"{_auth_cookie_name}_{i}"
if cookie_key not in cookies:
break
chunk_parts.append(cookies[cookie_key])
i += 1
joined = "".join(chunk_parts)
return joined if joined != "" else None
def get_token_from_cookies(cookies: dict[str, str]) -> Optional[str]:
"""
Read all chunk cookies and reconstruct the token
"""
# Default/unchunked cookies
if value := cookies.get(_auth_cookie_name):
return value
return _get_chunked_cookie(cookies, _auth_cookie_name)
def set_auth_cookie(request: Request, response: Response, token: str):
"""
Helper function to set the authentication cookie with secure parameters
and remove any leftover chunks from a previously larger token.
"""
_chunk_size = 3000
existing_cookies = {
k for k in request.cookies.keys() if k.startswith(_auth_cookie_name)
}
if len(token) > _chunk_size:
chunks = [token[i : i + _chunk_size] for i in range(0, len(token), _chunk_size)]
for i, chunk in enumerate(chunks):
k = f"{_auth_cookie_name}_{i}"
response.set_cookie(
key=k,
value=chunk,
httponly=True,
secure=_cookie_secure,
samesite=_cookie_samesite,
max_age=config.project.user_session_timeout,
)
existing_cookies.discard(k)
else:
# Default (shorter cookies)
response.set_cookie(
key=_auth_cookie_name,
value=token,
httponly=True,
secure=_cookie_secure,
samesite=_cookie_samesite,
max_age=config.project.user_session_timeout,
)
existing_cookies.discard(_auth_cookie_name)
# Delete remaining prior cookies/cookie chunks
for k in existing_cookies:
response.delete_cookie(
key=k, path=_cookie_path, secure=_cookie_secure, samesite=_cookie_samesite
)
def clear_auth_cookie(request: Request, response: Response):
"""
Helper function to clear the authentication cookie
"""
existing_cookies = {
k for k in request.cookies.keys() if k.startswith(_auth_cookie_name)
}
for k in existing_cookies:
response.delete_cookie(
key=k, path=_cookie_path, secure=_cookie_secure, samesite=_cookie_samesite
)
def set_oauth_state_cookie(response: Response, token: str):
response.set_cookie(
_state_cookie_name,
token,
httponly=True,
samesite=_cookie_samesite,
secure=_cookie_secure,
max_age=_state_cookie_lifetime,
)
def validate_oauth_state_cookie(request: Request, state: str):
"""Check the state from the oauth provider against the browser cookie."""
oauth_state = request.cookies.get(_state_cookie_name)
if oauth_state != state:
raise Exception("oauth state does not correspond")
def clear_oauth_state_cookie(response: Response):
"""Oauth complete, delete state token."""
response.delete_cookie(_state_cookie_name) # Do we set path here?
================================================
FILE: backend/chainlit/auth/jwt.py
================================================
import os
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, Optional
import jwt as pyjwt
from chainlit.config import config
from chainlit.user import User
def get_jwt_secret() -> Optional[str]:
return os.environ.get("CHAINLIT_AUTH_SECRET")
def create_jwt(data: User) -> str:
to_encode: Dict[str, Any] = data.to_dict()
to_encode.update(
{
"exp": datetime.now(timezone.utc)
+ timedelta(seconds=config.project.user_session_timeout),
"iat": datetime.now(timezone.utc), # Add issued at time
}
)
secret = get_jwt_secret()
assert secret
encoded_jwt = pyjwt.encode(to_encode, secret, algorithm="HS256")
return encoded_jwt
def decode_jwt(token: str) -> User:
secret = get_jwt_secret()
assert secret
dict = pyjwt.decode(
token,
secret,
algorithms=["HS256"],
options={"verify_signature": True},
)
del dict["exp"]
return User(**dict)
================================================
FILE: backend/chainlit/cache.py
================================================
import importlib.util
import os
import threading
from typing import Any
from chainlit.config import config
from chainlit.logger import logger
def init_lc_cache():
use_cache = config.project.cache is True and config.run.no_cache is False
if use_cache and importlib.util.find_spec("langchain") is not None:
from langchain.cache import SQLiteCache
from langchain.globals import set_llm_cache
if config.project.lc_cache_path is not None:
set_llm_cache(SQLiteCache(database_path=config.project.lc_cache_path))
if not os.path.exists(config.project.lc_cache_path):
logger.info(
f"LangChain cache created at: {config.project.lc_cache_path}"
)
_cache: dict[tuple, Any] = {}
_cache_lock = threading.Lock()
def cache(func):
def wrapper(*args, **kwargs):
# Create a cache key based on the function name, arguments, and keyword arguments
cache_key = (
(func.__name__,) + args + tuple((k, v) for k, v in sorted(kwargs.items()))
)
with _cache_lock:
# Check if the result is already in the cache
if cache_key not in _cache:
# If not, call the function and store the result in the cache
_cache[cache_key] = func(*args, **kwargs)
return _cache[cache_key]
return wrapper
================================================
FILE: backend/chainlit/callbacks.py
================================================
import inspect
from typing import Any, Awaitable, Callable, Dict, List, Optional, Union, overload
from fastapi import Request, Response
from mcp import ClientSession
from starlette.datastructures import Headers
from chainlit.action import Action
from chainlit.config import config
from chainlit.context import context
from chainlit.data.base import BaseDataLayer
from chainlit.mcp import McpConnection
from chainlit.message import Message
from chainlit.oauth_providers import get_configured_oauth_providers
from chainlit.step import Step, step
from chainlit.types import ChatProfile, Starter, StarterCategory, ThreadDict
from chainlit.user import User
from chainlit.utils import wrap_user_function
def on_app_startup(func: Callable[[], Union[None, Awaitable[None]]]) -> Callable:
"""
Hook to run code when the Chainlit application starts.
Useful for initializing resources, loading models, setting up database connections, etc.
The function can be synchronous or asynchronous.
Args:
func (Callable[[], Union[None, Awaitable[None]]]): The startup hook to execute. Takes no arguments.
Example:
@cl.on_app_startup
async def startup():
print("Application is starting!")
# Initialize resources here
Returns:
Callable[[], Union[None, Awaitable[None]]]: The decorated startup hook.
"""
config.code.on_app_startup = wrap_user_function(func, with_task=False)
return func
def on_app_shutdown(func: Callable[[], Union[None, Awaitable[None]]]) -> Callable:
"""
Hook to run code when the Chainlit application shuts down.
Useful for cleaning up resources, closing connections, saving state, etc.
The function can be synchronous or asynchronous.
Args:
func (Callable[[], Union[None, Awaitable[None]]]): The shutdown hook to execute. Takes no arguments.
Example:
@cl.on_app_shutdown
async def shutdown():
print("Application is shutting down!")
# Clean up resources here
Returns:
Callable[[], Union[None, Awaitable[None]]]: The decorated shutdown hook.
"""
config.code.on_app_shutdown = wrap_user_function(func, with_task=False)
return func
def password_auth_callback(
func: Callable[[str, str], Awaitable[Optional[User]]],
) -> Callable:
"""
Framework agnostic decorator to authenticate the user.
Args:
func (Callable[[str, str], Awaitable[Optional[User]]]): The authentication callback to execute. Takes the email and password as parameters.
Example:
@cl.password_auth_callback
async def password_auth_callback(username: str, password: str) -> Optional[User]:
Returns:
Callable[[str, str], Awaitable[Optional[User]]]: The decorated authentication callback.
"""
config.code.password_auth_callback = wrap_user_function(func)
return func
def header_auth_callback(
func: Callable[[Headers], Awaitable[Optional[User]]],
) -> Callable:
"""
Framework agnostic decorator to authenticate the user via a header
Args:
func (Callable[[Headers], Awaitable[Optional[User]]]): The authentication callback to execute.
Example:
@cl.header_auth_callback
async def header_auth_callback(headers: Headers) -> Optional[User]:
Returns:
Callable[[Headers], Awaitable[Optional[User]]]: The decorated authentication callback.
"""
config.code.header_auth_callback = wrap_user_function(func)
return func
def oauth_callback(
func: Callable[
[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]
],
) -> Callable:
"""
Framework agnostic decorator to authenticate the user via oauth
Args:
func (Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]): The authentication callback to execute.
Example:
@cl.oauth_callback
async def oauth_callback(provider_id: str, token: str, raw_user_data: Dict[str, str], default_app_user: User, id_token: Optional[str]) -> Optional[User]:
Returns:
Callable[[str, str, Dict[str, str], User, Optional[str]], Awaitable[Optional[User]]]: The decorated authentication callback.
"""
if len(get_configured_oauth_providers()) == 0:
raise ValueError(
"You must set the environment variable for at least one oauth provider to use oauth authentication."
)
config.code.oauth_callback = wrap_user_function(func)
return func
def on_logout(func: Callable[[Request, Response], Any]) -> Callable:
"""
Function called when the user logs out.
Takes the FastAPI request and response as parameters.
"""
config.code.on_logout = wrap_user_function(func)
return func
def on_message(func: Callable) -> Callable:
"""
Framework agnostic decorator to react to messages coming from the UI.
The decorated function is called every time a new message is received.
Args:
func (Callable[[Message], Any]): The function to be called when a new message is received. Takes a cl.Message.
Returns:
Callable[[str], Any]: The decorated on_message function.
"""
async def with_parent_id(message: Message):
async with Step(name="on_message", type="run", parent_id=message.id) as s:
s.input = message.content
if len(inspect.signature(func).parameters) > 0:
await func(message)
else:
await func()
config.code.on_message = wrap_user_function(with_parent_id)
return func
async def send_window_message(data: Any):
"""
Send custom data to the host window via a window.postMessage event.
Args:
data (Any): The data to send with the event.
"""
await context.emitter.send_window_message(data)
def on_window_message(func: Callable[[str], Any]) -> Callable:
"""
Hook to react to javascript postMessage events coming from the UI.
Args:
func (Callable[[str], Any]): The function to be called when a window message is received.
Takes the message content as a string parameter.
Returns:
Callable[[str], Any]: The decorated on_window_message function.
"""
config.code.on_window_message = wrap_user_function(func)
return func
def on_chat_start(func: Callable) -> Callable:
"""
Hook to react to the user websocket connection event.
Args:
func (Callable[], Any]): The connection hook to execute.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_chat_start = wrap_user_function(
step(func, name="on_chat_start", type="run"), with_task=True
)
return func
def on_chat_resume(func: Callable[[ThreadDict], Any]) -> Callable:
"""
Hook to react to resume websocket connection event.
Args:
func (Callable[], Any]): The connection hook to execute.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_chat_resume = wrap_user_function(func, with_task=True)
return func
@overload
def set_chat_profiles(
func: Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]],
) -> Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]: ...
@overload
def set_chat_profiles(
func: Callable[[Optional["User"], Optional["str"]], Awaitable[List["ChatProfile"]]],
) -> Callable[[Optional["User"], Optional["str"]], Awaitable[List["ChatProfile"]]]: ...
def set_chat_profiles(func):
"""
Programmatic declaration of the available chat profiles (can depend on the User from the session if authentication is setup).
Args:
func (Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]): The function declaring the chat profiles.
Returns:
Callable[[Optional["User"]], Awaitable[List["ChatProfile"]]]: The decorated function.
"""
config.code.set_chat_profiles = wrap_user_function(func)
return func
@overload
def set_starters(
func: Callable[[Optional["User"]], Awaitable[List["Starter"]]],
) -> Callable[[Optional["User"]], Awaitable[List["Starter"]]]: ...
@overload
def set_starters(
func: Callable[[Optional["User"], Optional["str"]], Awaitable[List["Starter"]]],
) -> Callable[[Optional["User"], Optional["str"]], Awaitable[List["Starter"]]]: ...
def set_starters(func):
"""
Programmatic declaration of the available starter (can depend on the User from the session if authentication is setup).
Args:
func (Callable[[Optional["User"], Optional["str"]], Awaitable[List["Starter"]]]): The function declaring the starters with optional user and language arguments.
Returns:
Callable[[Optional["User"], Optional["str"]], Awaitable[List["Starter"]]]: The decorated function.
"""
config.code.set_starters = wrap_user_function(func)
return func
@overload
def set_starter_categories(
func: Callable[[Optional["User"]], Awaitable[List["StarterCategory"]]],
) -> Callable[[Optional["User"]], Awaitable[List["StarterCategory"]]]: ...
@overload
def set_starter_categories(
func: Callable[
[Optional["User"], Optional["str"]], Awaitable[List["StarterCategory"]]
],
) -> Callable[
[Optional["User"], Optional["str"]], Awaitable[List["StarterCategory"]]
]: ...
def set_starter_categories(func):
"""
Programmatic declaration of starter categories with grouped starters.
Args:
func (Callable[[Optional["User"], Optional["str"]], Awaitable[List["StarterCategory"]]]): The function declaring the starter categories with optional user and language arguments.
Returns:
Callable[[Optional["User"], Optional["str"]], Awaitable[List["StarterCategory"]]]: The decorated function.
"""
config.code.set_starter_categories = wrap_user_function(func)
return func
def on_chat_end(func: Callable) -> Callable:
"""
Hook to react to the user websocket disconnect event.
Args:
func (Callable[], Any]): The disconnect hook to execute.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_chat_end = wrap_user_function(func, with_task=True)
return func
def on_audio_start(func: Callable) -> Callable:
"""
Hook to react to the user initiating audio.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_audio_start = wrap_user_function(func, with_task=False)
return func
def on_audio_chunk(func: Callable) -> Callable:
"""
Hook to react to the audio chunks being sent.
Args:
chunk (InputAudioChunk): The audio chunk being sent.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_audio_chunk = wrap_user_function(func, with_task=False)
return func
def on_audio_end(func: Callable) -> Callable:
"""
Hook to react to the audio stream ending. This is called after the last audio chunk is sent.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_audio_end = wrap_user_function(
step(func, name="on_audio_end", type="run"), with_task=True
)
return func
def author_rename(
func: Callable[[str], Awaitable[str]],
) -> Callable[[str], Awaitable[str]]:
"""
Useful to rename the author of message to display more friendly author names in the UI.
Args:
func (Callable[[str], Awaitable[str]]): The function to be called to rename an author. Takes the original author name as parameter.
Returns:
Callable[[Any, str], Awaitable[Any]]: The decorated function.
"""
config.code.author_rename = wrap_user_function(func)
return func
def on_mcp_connect(
func: Callable[[McpConnection, ClientSession], Awaitable[None]],
) -> Callable[[McpConnection, ClientSession], Awaitable[None]]:
"""
Called everytime an MCP is connected
"""
config.code.on_mcp_connect = wrap_user_function(func)
return func
def on_mcp_disconnect(
func: Callable[[str, ClientSession], Awaitable[None]],
) -> Callable[[str, ClientSession], Awaitable[None]]:
"""
Called everytime an MCP is disconnected
"""
config.code.on_mcp_disconnect = wrap_user_function(func)
return func
def on_stop(func: Callable) -> Callable:
"""
Hook to react to the user stopping a thread.
Args:
func (Callable[[], Any]): The stop hook to execute.
Returns:
Callable[[], Any]: The decorated stop hook.
"""
config.code.on_stop = wrap_user_function(func)
return func
def action_callback(name: str) -> Callable:
"""
Callback to call when an action is clicked in the UI.
Args:
func (Callable[[Action], Any]): The action callback to execute. First parameter is the action.
"""
def decorator(func: Callable[[Action], Any]):
config.code.action_callbacks[name] = wrap_user_function(func, with_task=False)
return func
return decorator
def on_settings_update(
func: Callable[[Dict[str, Any]], Any],
) -> Callable[[Dict[str, Any]], Any]:
"""
Hook to react to the user changing any settings.
Args:
func (Callable[], Any]): The hook to execute after settings were changed.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_settings_update = wrap_user_function(func, with_task=True)
return func
def on_settings_edit(
func: Callable[[Dict[str, Any]], Any],
) -> Callable[[Dict[str, Any]], Any]:
"""
Hook to react to the user editing any settings (on the fly).
Args:
func (Callable[], Any]): The hook to execute while settings are being edited.
Returns:
Callable[], Any]: The decorated hook.
"""
config.code.on_settings_edit = wrap_user_function(func, with_task=True)
return func
def data_layer(
func: Callable[[], BaseDataLayer],
) -> Callable[[], BaseDataLayer]:
"""
Hook to configure custom data layer.
"""
# We don't use wrap_user_function here because:
# 1. We don't need to support async here and;
# 2. We don't want to change the API for get_data_layer() to be async, everywhere (at this point).
config.code.data_layer = func
return func
def on_feedback(func: Callable) -> Callable:
"""
Hook to react to user feedback events from the UI.
The decorated function is called every time feedback is received.
Args:
func (Callable[[Feedback], Any]): The function to be called when feedback is received. Takes a cl.Feedback object.
Example:
@cl.on_feedback
async def on_feedback(feedback: Feedback):
print(f"Received feedback: {feedback.value} for step {feedback.forId}")
# Handle feedback here
Returns:
Callable[[Feedback], Any]: The decorated on_feedback function.
"""
config.code.on_feedback = wrap_user_function(func)
return func
def on_slack_reaction_added(func: Callable[[Dict[str, Any]], Any]) -> Callable:
"""
Hook to react to Slack reaction_added events.
The decorated function is called every time a user adds a reaction to a message in Slack.
Args:
func (Callable[[Dict[str, Any]], Any]): The function to be called when a reaction is added.
Takes a Slack event dictionary containing:
- reaction: The emoji reaction name (e.g., "thumbsup")
- user: The user ID who added the reaction
- item: Dictionary with type, ts, and channel of the reacted item
Example:
@cl.on_slack_reaction_added
async def handle_reaction(event: Dict[str, Any]):
reaction = event.get("reaction")
user_id = event.get("user")
print(f"User {user_id} added reaction {reaction}")
# Handle reaction here
Returns:
Callable[[Dict[str, Any]], Any]: The decorated on_slack_reaction_added function.
"""
config.code.on_slack_reaction_added = wrap_user_function(func)
return func
def on_shared_thread_view(
func: Callable[[ThreadDict, Optional[User]], Awaitable[bool]],
) -> Callable[[ThreadDict, Optional[User]], Awaitable[bool]]:
"""Hook to authorize viewing a shared thread.
Users must implement and return True to allow a non-author to view a thread.
Thread metadata contains "is_shared" boolean flag and "shared_at" timestamp for custom thread sharing.
Signature: async (thread: ThreadDict, viewer: Optional[User]) -> bool
"""
config.code.on_shared_thread_view = wrap_user_function(func)
return func
================================================
FILE: backend/chainlit/chat_context.py
================================================
from typing import TYPE_CHECKING, Dict, List
from chainlit.context import context
if TYPE_CHECKING:
from chainlit.message import Message
chat_contexts: Dict[str, List["Message"]] = {}
class ChatContext:
def get(self) -> List["Message"]:
if not context.session:
return []
if context.session.id not in chat_contexts:
# Create a new chat context
chat_contexts[context.session.id] = []
return chat_contexts[context.session.id].copy()
def add(self, message: "Message"):
if not context.session:
return
if context.session.id not in chat_contexts:
chat_contexts[context.session.id] = []
if message not in chat_contexts[context.session.id]:
chat_contexts[context.session.id].append(message)
return message
def remove(self, message: "Message") -> bool:
if not context.session:
return False
if context.session.id not in chat_contexts:
return False
if message in chat_contexts[context.session.id]:
chat_contexts[context.session.id].remove(message)
return True
return False
def clear(self) -> None:
if context.session and context.session.id in chat_contexts:
chat_contexts[context.session.id] = []
def to_openai(self):
messages = []
for message in self.get():
if message.type == "assistant_message":
messages.append({"role": "assistant", "content": message.content})
elif message.type == "user_message":
messages.append({"role": "user", "content": message.content})
else:
messages.append({"role": "system", "content": message.content})
return messages
chat_context = ChatContext()
================================================
FILE: backend/chainlit/chat_settings.py
================================================
from typing import Any, List
from pydantic import Field
from pydantic.dataclasses import dataclass
from chainlit.context import context
from chainlit.input_widget import InputWidget, Tab
@dataclass
class ChatSettings:
"""Useful to create chat settings that the user can change."""
inputs: List[InputWidget] | List[Tab] = Field(default_factory=list, exclude=True)
def __init__(
self,
inputs: List[InputWidget] | List[Tab],
) -> None:
self.inputs = inputs
def settings(self):
def collect_settings(
values: dict[str, Any], inputs: List[InputWidget] | List[Tab]
) -> None:
for input in inputs:
if isinstance(input, Tab):
collect_settings(values, input.inputs)
else:
values[input.id] = input.initial
settings: dict[str, Any] = {}
collect_settings(settings, self.inputs)
return settings
async def send(self):
settings = self.settings()
context.emitter.set_chat_settings(settings)
inputs_content = [input_widget.to_dict() for input_widget in self.inputs]
await context.emitter.emit("chat_settings", inputs_content)
return settings
================================================
FILE: backend/chainlit/cli/__init__.py
================================================
import asyncio
import logging
import os
import sys
import click
import nest_asyncio
import uvicorn
# Not sure if it is necessary to call nest_asyncio.apply() before the other imports
nest_asyncio.apply()
# ruff: noqa: E402
from chainlit.auth import ensure_jwt_secret
from chainlit.cache import init_lc_cache
from chainlit.config import (
BACKEND_ROOT,
DEFAULT_HOST,
DEFAULT_PORT,
DEFAULT_ROOT_PATH,
config,
init_config,
lint_translations,
load_module,
)
from chainlit.logger import logger
from chainlit.markdown import init_markdown
from chainlit.secret import random_secret
from chainlit.utils import check_file
logging.basicConfig(
level=logging.INFO,
stream=sys.stdout,
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
def assert_app():
if (
not config.code.on_chat_start
and not config.code.on_message
and not config.code.on_audio_chunk
):
raise Exception(
"You need to configure at least one of on_chat_start, on_message or on_audio_chunk callback"
)
# Create the main command group for Chainlit CLI
@click.group(context_settings={"auto_envvar_prefix": "CHAINLIT"})
@click.version_option(prog_name="Chainlit")
def cli():
return
# Define the function to run Chainlit with provided options
def run_chainlit(target: str):
host = os.environ.get("CHAINLIT_HOST", DEFAULT_HOST)
port = int(os.environ.get("CHAINLIT_PORT", DEFAULT_PORT))
root_path = os.environ.get("CHAINLIT_ROOT_PATH", DEFAULT_ROOT_PATH)
ssl_certfile = os.environ.get("CHAINLIT_SSL_CERT", None)
ssl_keyfile = os.environ.get("CHAINLIT_SSL_KEY", None)
ws_per_message_deflate_env = os.environ.get(
"UVICORN_WS_PER_MESSAGE_DEFLATE", "true"
)
ws_per_message_deflate = ws_per_message_deflate_env.lower() in [
"true",
"1",
"yes",
] # Convert to boolean
ws_protocol = os.environ.get("UVICORN_WS_PROTOCOL", "auto")
config.run.host = host
config.run.port = port
config.run.root_path = root_path
from chainlit.server import app
check_file(target)
# Load the module provided by the user
config.run.module_name = target
load_module(config.run.module_name)
ensure_jwt_secret()
assert_app()
# Create the chainlit.md file if it doesn't exist
init_markdown(config.root)
# Initialize the LangChain cache if installed and enabled
init_lc_cache()
log_level = "debug" if config.run.debug else "error"
# Start the server
async def start():
config = uvicorn.Config(
app,
host=host,
port=port,
ws=ws_protocol,
log_level=log_level,
ws_per_message_deflate=ws_per_message_deflate,
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
)
server = uvicorn.Server(config)
await server.serve()
# Run the asyncio event loop instead of uvloop to enable re entrance
asyncio.run(start())
# uvicorn.run(app, host=host, port=port, log_level=log_level)
# Define the "run" command for Chainlit CLI
@cli.command("run")
@click.argument("target", required=True, envvar="RUN_TARGET")
@click.option(
"-w",
"--watch",
default=False,
is_flag=True,
envvar="WATCH",
help="Reload the app when the module changes",
)
@click.option(
"-h",
"--headless",
default=False,
is_flag=True,
envvar="HEADLESS",
help="Will prevent to auto open the app in the browser",
)
@click.option(
"-d",
"--debug",
default=False,
is_flag=True,
envvar="DEBUG",
help="Set the log level to debug",
)
@click.option(
"-c",
"--ci",
default=False,
is_flag=True,
envvar="CI",
help="Flag to run in CI mode",
)
@click.option(
"--no-cache",
default=False,
is_flag=True,
envvar="NO_CACHE",
help="Useful to disable third parties cache, such as langchain.",
)
@click.option(
"--ssl-cert",
default=None,
envvar="CHAINLIT_SSL_CERT",
help="Specify the file path for the SSL certificate.",
)
@click.option(
"--ssl-key",
default=None,
envvar="CHAINLIT_SSL_KEY",
help="Specify the file path for the SSL key",
)
@click.option("--host", help="Specify a different host to run the server on")
@click.option("--port", help="Specify a different port to run the server on")
@click.option("--root-path", help="Specify a different root path to run the server on")
def chainlit_run(
target,
watch,
headless,
debug,
ci,
no_cache,
ssl_cert,
ssl_key,
host,
port,
root_path,
):
if host:
os.environ["CHAINLIT_HOST"] = host
if port:
os.environ["CHAINLIT_PORT"] = port
if bool(ssl_cert) != bool(ssl_key):
raise click.UsageError(
"Both --ssl-cert and --ssl-key must be provided together."
)
if ssl_cert:
os.environ["CHAINLIT_SSL_CERT"] = ssl_cert
os.environ["CHAINLIT_SSL_KEY"] = ssl_key
if root_path:
os.environ["CHAINLIT_ROOT_PATH"] = root_path
if ci:
logger.info("Running in CI mode")
no_cache = True
# This is required to have OpenAI LLM providers available for the CI run
os.environ["OPENAI_API_KEY"] = "sk-FAKE-OPENAI-API-KEY"
config.run.headless = headless
config.run.debug = debug
config.run.no_cache = no_cache
config.run.ci = ci
config.run.watch = watch
config.run.ssl_cert = ssl_cert
config.run.ssl_key = ssl_key
run_chainlit(target)
@cli.command("hello")
@click.argument("args", nargs=-1)
def chainlit_hello(args=None, **kwargs):
hello_path = os.path.join(BACKEND_ROOT, "sample", "hello.py")
run_chainlit(hello_path)
@cli.command("init")
@click.argument("args", nargs=-1)
def chainlit_init(args=None, **kwargs):
init_config(log=True)
@cli.command("create-secret")
@click.argument("args", nargs=-1)
def chainlit_create_secret(args=None, **kwargs):
print(
f'Copy the following secret into your .env file. Once it is set, changing it will logout all users with active sessions.\nCHAINLIT_AUTH_SECRET="{random_secret()}"'
)
@cli.command("lint-translations")
@click.argument("args", nargs=-1)
def chainlit_lint_translations(args=None, **kwargs):
lint_translations()
================================================
FILE: backend/chainlit/config.py
================================================
import json
import os
import site
import sys
from importlib import util
from pathlib import Path
from typing import (
TYPE_CHECKING,
Any,
Awaitable,
Callable,
Dict,
List,
Literal,
Optional,
Union,
)
import tomli
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings
from starlette.datastructures import Headers
from chainlit.data.base import BaseDataLayer
from chainlit.logger import logger
from chainlit.translations import lint_translation_json
from chainlit.version import __version__
from ._utils import is_path_inside
if TYPE_CHECKING:
from fastapi import Request, Response
from chainlit.action import Action
from chainlit.message import Message
from chainlit.types import (
ChatProfile,
Feedback,
InputAudioChunk,
Starter,
StarterCategory,
ThreadDict,
)
from chainlit.user import User
else:
# Pydantic needs to resolve forward annotations. Because all of these are used
# within `typing.Callable`, alias to `Any` as Pydantic does not perform validation
# of callable argument/return types anyway.
Request = Response = Action = Message = ChatProfile = InputAudioChunk = Starter = StarterCategory = ThreadDict = User = Feedback = Any # fmt: off
BACKEND_ROOT = os.path.dirname(__file__)
PACKAGE_ROOT = os.path.dirname(os.path.dirname(BACKEND_ROOT))
TRANSLATIONS_DIR = os.path.join(BACKEND_ROOT, "translations")
# Get the directory the script is running from
APP_ROOT = os.getenv("CHAINLIT_APP_ROOT", os.getcwd())
# Create the directory to store the uploaded files
FILES_DIRECTORY = Path(APP_ROOT) / ".files"
FILES_DIRECTORY.mkdir(exist_ok=True)
config_dir = os.path.join(APP_ROOT, ".chainlit")
public_dir = os.path.join(APP_ROOT, "public")
config_file = os.path.join(config_dir, "config.toml")
config_translation_dir = os.path.join(config_dir, "translations")
# Default config file created if none exists
DEFAULT_CONFIG_STR = f"""[project]
# List of environment variables to be provided by each user to use the app.
user_env = []
# 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
# Whether to persist user environment variables (API keys) to the database
# Set to true to store user env vars in DB, false to exclude them for security
persist_user_env = false
# Whether to mask user environment variables (API keys) in the UI with password type
# Set to true to show API keys as ***, false to show them as plain text
mask_user_env = false
# Authorized origins
allow_origins = ["*"]
[features]
# Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript)
unsafe_allow_html = false
# Process and display mathematical expressions. This can clash with "$" characters in messages.
latex = false
# Enable rendering of user messages markdown
user_message_markdown = true
# Autoscroll new user messages at the top of the window
user_message_autoscroll = true
# Autoscroll new assistant messages
assistant_message_autoscroll = true
# Automatically tag threads with the current chat profile (if a chat profile is used)
auto_tag_thread = true
# Allow users to edit their own messages
edit_message = true
# Allow users to share threads (backend + UI). Requires an app-defined on_shared_thread_view callback.
allow_thread_sharing = false
# Enable favorite messages
favorites = false
[features.slack]
# Add emoji reaction when message is received (requires reactions:write OAuth scope)
reaction_on_message_received = false
# Authorize users to spontaneously upload files with messages
[features.spontaneous_file_upload]
enabled = true
# Define accepted file types using MIME types
# Examples:
# 1. For specific file types:
# accept = ["image/jpeg", "image/png", "application/pdf"]
# 2. For all files of certain type:
# accept = ["image/*", "audio/*", "video/*"]
# 3. For specific file extensions:
# accept = {{ "application/octet-stream" = [".xyz", ".pdb"] }}
# Note: Using "*/*" is not recommended as it may cause browser warnings
accept = ["*/*"]
max_files = 20
max_size_mb = 500
[features.audio]
# Enable audio features
enabled = false
# Sample rate of the audio
sample_rate = 24000
[features.mcp]
# Enable Model Context Protocol (MCP) features
enabled = false
[features.mcp.sse]
enabled = true
[features.mcp.streamable-http]
enabled = true
[features.mcp.stdio]
enabled = true
# Only the executables in the allow list can be used for MCP stdio server.
# Only need the base name of the executable, e.g. "npx", not "/usr/bin/npx".
# Please don't comment this line for now, we need it to parse the executable name.
allowed_executables = [ "npx", "uvx" ]
[UI]
# Name of the assistant.
name = "Assistant"
# default_theme = "dark"
# Force a specific language for all users (e.g., "en-US", "he-IL", "fr-FR")
# If not set, the browser's language will be used
# language = "en-US"
# layout = "wide"
# default_sidebar_state = "open" # Options: "open", "closed", "hidden"
# Chat settings display location: "message_composer" (default) or "sidebar" (header)
# chat_settings_location = "message_composer"
# Default state of chat settings sidebar when location is "sidebar"
# default_chat_settings_open = false
# Whether to prompt user confirmation on clicking 'New Chat'
confirm_new_chat = true
# Description of the assistant. This is used for HTML tags.
# description = ""
# Chain of Thought (CoT) display mode. Can be "hidden", "tool_call" or "full".
cot = "full"
# Specify a CSS file that can be used to customize the user interface.
# The CSS file can be served from the public directory or via an external link.
# custom_css = "/public/test.css"
# Specify additional attributes for a custom CSS file
# custom_css_attributes = "media=\\\"print\\\""
# Specify a JavaScript file that can be used to customize the user interface.
# The JavaScript file can be served from the public directory.
# custom_js = "/public/test.js"
# The style of alert boxes. Can be "classic" or "modern".
alert_style = "classic"
# Specify additional attributes for custom JS file
# custom_js_attributes = "async type = \\\"module\\\""
# Custom login page image, relative to public directory or external URL
# login_page_image = "/public/custom-background.jpg"
# Custom login page image filter (Tailwind internal filters, no dark/light variants)
# login_page_image_filter = "brightness-50 grayscale"
# login_page_image_dark_filter = "contrast-200 blur-sm"
# Specify a custom meta URL (used for meta tags like og:url)
# custom_meta_url = "https://github.com/Chainlit/chainlit"
# Specify a custom meta image url.
# custom_meta_image_url = "https://chainlit-cloud.s3.eu-west-3.amazonaws.com/logo/chainlit_banner.png"
# Load assistant logo directly from URL.
logo_file_url = ""
# Load assistant avatar image directly from URL.
default_avatar_file_url = ""
# Avatar size in pixels (default: 20).
# avatar_size = 20
# Specify a custom build directory for the frontend.
# This can be used to customize the frontend code.
# Be careful: If this is a relative path, it should not start with a slash.
# custom_build = "./public/build"
# Specify optional one or more custom links in the header.
# [[UI.header_links]]
# name = "Issues"
# display_name = "Report Issue"
# icon_url = "https://avatars.githubusercontent.com/u/128686189?s=200&v=4"
# url = "https://github.com/Chainlit/chainlit/issues"
# target = "_blank" (default) # Optional: "_self", "_parent", "_top".
[meta]
generated_by = "{__version__}"
"""
DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 8000
DEFAULT_ROOT_PATH = ""
class RunSettings(BaseModel):
# Name of the module (python file) used in the run command
module_name: Optional[str] = None
host: str = DEFAULT_HOST
port: int = DEFAULT_PORT
ssl_cert: Optional[str] = None
ssl_key: Optional[str] = None
root_path: str = DEFAULT_ROOT_PATH
headless: bool = False
watch: bool = False
no_cache: bool = False
debug: bool = False
ci: bool = False
class PaletteOptions(BaseModel):
main: Optional[str] = ""
light: Optional[str] = ""
dark: Optional[str] = ""
class TextOptions(BaseModel):
primary: Optional[str] = ""
secondary: Optional[str] = ""
class Palette(BaseModel):
primary: Optional[PaletteOptions] = None
background: Optional[str] = ""
paper: Optional[str] = ""
text: Optional[TextOptions] = None
class SpontaneousFileUploadFeature(BaseModel):
enabled: Optional[bool] = None
accept: Optional[Union[List[str], Dict[str, List[str]]]] = None
max_files: Optional[int] = None
max_size_mb: Optional[int] = None
class AudioFeature(BaseModel):
sample_rate: int = 24000
enabled: bool = False
class McpSseFeature(BaseModel):
enabled: bool = True
class McpStreamableHttpFeature(BaseModel):
enabled: bool = True
class McpStdioFeature(BaseModel):
enabled: bool = True
allowed_executables: Optional[list[str]] = None
class SlackFeature(BaseModel):
reaction_on_message_received: bool = False
class McpFeature(BaseModel):
enabled: bool = False
sse: McpSseFeature = Field(default_factory=McpSseFeature)
streamable_http: McpStreamableHttpFeature = Field(
default_factory=McpStreamableHttpFeature
)
stdio: McpStdioFeature = Field(default_factory=McpStdioFeature)
class FeaturesSettings(BaseModel):
spontaneous_file_upload: Optional[SpontaneousFileUploadFeature] = None
audio: Optional[AudioFeature] = Field(default_factory=AudioFeature)
mcp: McpFeature = Field(default_factory=McpFeature)
slack: SlackFeature = Field(default_factory=SlackFeature)
latex: bool = False
user_message_markdown: bool = True
user_message_autoscroll: bool = True
assistant_message_autoscroll: bool = True
unsafe_allow_html: bool = False
auto_tag_thread: bool = True
edit_message: bool = True
allow_thread_sharing: bool = False
favorites: bool = False
class HeaderLink(BaseModel):
name: str
icon_url: str
url: str
display_name: Optional[str] = None
target: Optional[Literal["_blank", "_self", "_parent", "_top"]] = None
class UISettings(BaseModel):
name: str
description: str = ""
cot: Literal["hidden", "tool_call", "full"] = "full"
default_theme: Optional[Literal["light", "dark"]] = "dark"
language: Optional[str] = None
layout: Optional[Literal["default", "wide"]] = "default"
default_sidebar_state: Optional[Literal["open", "closed", "hidden"]] = "open"
chat_settings_location: Optional[Literal["message_composer", "sidebar"]] = (
"message_composer"
)
default_chat_settings_open: bool = False
confirm_new_chat: bool = True
github: Optional[str] = None
custom_css: Optional[str] = None
custom_css_attributes: Optional[str] = ""
custom_js: Optional[str] = None
alert_style: Optional[Literal["classic", "modern"]] = "classic"
custom_js_attributes: Optional[str] = "defer"
login_page_image: Optional[str] = None
login_page_image_filter: Optional[str] = None
login_page_image_dark_filter: Optional[str] = None
custom_meta_url: Optional[str] = None
custom_meta_image_url: Optional[str] = None
logo_file_url: Optional[str] = None
default_avatar_file_url: Optional[str] = None
avatar_size: Optional[int] = None
custom_build: Optional[str] = None
header_links: Optional[List[HeaderLink]] = None
class CodeSettings(BaseModel):
# App action functions
action_callbacks: Dict[str, Callable[["Action"], Any]]
# Module object loaded from the module_name
module: Any = None
# App life cycle callbacks
on_app_startup: Optional[Callable[[], Union[None, Awaitable[None]]]] = None
on_app_shutdown: Optional[Callable[[], Union[None, Awaitable[None]]]] = None
# Session life cycle callbacks
on_logout: Optional[Callable[["Request", "Response"], Any]] = None
on_stop: Optional[Callable[[], Any]] = None
on_chat_start: Optional[Callable[[], Any]] = None
on_chat_end: Optional[Callable[[], Any]] = None
on_chat_resume: Optional[Callable[["ThreadDict"], Any]] = None
on_message: Optional[Callable[["Message"], Any]] = None
on_feedback: Optional[Callable[["Feedback"], Any]] = None
on_slack_reaction_added: Optional[Callable[[Dict[str, Any]], Any]] = None
on_audio_start: Optional[Callable[[], Any]] = None
on_audio_chunk: Optional[Callable[["InputAudioChunk"], Any]] = None
on_audio_end: Optional[Callable[[], Any]] = None
on_mcp_connect: Optional[Callable] = None
on_mcp_disconnect: Optional[Callable] = None
on_settings_edit: Optional[Callable[[Dict[str, Any]], Any]] = None
on_settings_update: Optional[Callable[[Dict[str, Any]], Any]] = None
set_chat_profiles: Optional[
Callable[[Optional["User"], Optional["str"]], Awaitable[List["ChatProfile"]]]
] = None
set_starters: Optional[
Callable[[Optional["User"], Optional["str"]], Awaitable[List["Starter"]]]
] = None
set_starter_categories: Optional[
Callable[
[Optional["User"], Optional["str"]], Awaitable[List["StarterCategory"]]
]
] = None
on_shared_thread_view: Optional[
Callable[["ThreadDict", Optional["User"]], Awaitable[bool]]
] = None
# Auth callbacks
password_auth_callback: Optional[
Callable[[str, str], Awaitable[Optional["User"]]]
] = None
header_auth_callback: Optional[Callable[[Headers], Awaitable[Optional["User"]]]] = (
None
)
oauth_callback: Optional[
Callable[[str, str, Dict[str, str], "User"], Awaitable[Optional["User"]]]
] = None
# Helpers
on_window_message: Optional[Callable[[str], Any]] = None
author_rename: Optional[Callable[[str], Awaitable[str]]] = None
data_layer: Optional[Callable[[], BaseDataLayer]] = None
class ProjectSettings(BaseModel):
allow_origins: List[str] = Field(default_factory=lambda: ["*"])
# Socket.io client transports option
transports: Optional[List[str]] = None
# List of environment variables to be provided by each user to use the app. If empty, no environment variables will be asked to the user.
user_env: Optional[List[str]] = None
# Path to the local langchain cache database
lc_cache_path: Optional[str] = None
# Path to the local chat db
# Duration (in seconds) during which the session is saved when the connection is lost
session_timeout: int = 300
# 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
# Whether to persist user environment variables (API keys) to the database
persist_user_env: Optional[bool] = False
# Whether to mask user environment variables (API keys) in the UI with password type
mask_user_env: Optional[bool] = False
class ChainlitConfigOverrides(BaseModel):
"""Configuration overrides that can be applied to specific chat profiles."""
ui: Optional[UISettings] = None
features: Optional[FeaturesSettings] = None
project: Optional[ProjectSettings] = None
class ChainlitConfig(BaseSettings):
root: str = APP_ROOT
chainlit_server: str = Field(default="")
run: RunSettings = Field(default_factory=RunSettings)
features: FeaturesSettings
ui: UISettings
project: ProjectSettings
code: CodeSettings
def load_translation(self, language: str):
translation = {}
default_language = "en-US"
# fallback to root language (ex: `de` when `de-DE` is not found)
parent_language = language.split("-")[0]
translation_dir = Path(config_translation_dir)
translation_lib_file_path = translation_dir / f"{language}.json"
translation_lib_parent_language_file_path = (
translation_dir / f"{parent_language}.json"
)
default_translation_lib_file_path = translation_dir / f"{default_language}.json"
if (
is_path_inside(translation_lib_file_path, translation_dir)
and translation_lib_file_path.is_file()
):
translation = json.loads(
translation_lib_file_path.read_text(encoding="utf-8")
)
elif (
is_path_inside(translation_lib_parent_language_file_path, translation_dir)
and translation_lib_parent_language_file_path.is_file()
):
logger.warning(
f"Translation file for {language} not found. Using parent translation {parent_language}."
)
translation = json.loads(
translation_lib_parent_language_file_path.read_text(encoding="utf-8")
)
elif (
is_path_inside(default_translation_lib_file_path, translation_dir)
and default_translation_lib_file_path.is_file()
):
logger.warning(
f"Translation file for {language} not found. Using default translation {default_language}."
)
translation = json.loads(
default_translation_lib_file_path.read_text(encoding="utf-8")
)
return translation
def with_overrides(
self, overrides: "ChainlitConfigOverrides | None"
) -> "ChainlitConfig":
base = self.model_dump()
patch = overrides.model_dump(exclude_unset=True) if overrides else {}
def _merge(a, b):
if isinstance(a, dict) and isinstance(b, dict):
out = dict(a)
for k, v in b.items():
out[k] = _merge(out.get(k), v)
return out
return b
merged = _merge(base, patch) if patch else base
return type(self).model_validate(merged)
def init_config(log: bool = False):
"""Initialize the configuration file if it doesn't exist."""
if not os.path.exists(config_file):
os.makedirs(config_dir, exist_ok=True)
with open(config_file, "w", encoding="utf-8") as f:
f.write(DEFAULT_CONFIG_STR)
logger.info(f"Created default config file at {config_file}")
elif log:
logger.info(f"Config file already exists at {config_file}")
if not os.path.exists(config_translation_dir):
os.makedirs(config_translation_dir, exist_ok=True)
logger.info(
f"Created default translation directory at {config_translation_dir}"
)
for file in os.listdir(TRANSLATIONS_DIR):
if file.endswith(".json"):
dst = os.path.join(config_translation_dir, file)
if not os.path.exists(dst):
src = os.path.join(TRANSLATIONS_DIR, file)
with open(src, encoding="utf-8") as f:
translation = json.load(f)
with open(dst, "w", encoding="utf-8") as f:
json.dump(translation, f, indent=4)
logger.info(f"Created default translation file at {dst}")
def load_module(target: str, force_refresh: bool = False):
"""Load the specified module."""
# Get the target's directory
target_dir = os.path.dirname(os.path.abspath(target))
# Add the target's directory to the Python path
sys.path.insert(0, target_dir)
if force_refresh:
# Get current site packages dirs
site_package_dirs = site.getsitepackages()
# Clear the modules related to the app from sys.modules
for module_name, module in list(sys.modules.items()):
if (
hasattr(module, "__file__")
and module.__file__
and module.__file__.startswith(target_dir)
and not any(module.__file__.startswith(p) for p in site_package_dirs)
):
sys.modules.pop(module_name, None)
spec = util.spec_from_file_location(target, target)
if not spec or not spec.loader:
sys.path.pop(0)
return
module = util.module_from_spec(spec)
if not module:
sys.path.pop(0)
return
spec.loader.exec_module(module)
sys.modules[target] = module
# Remove the target's directory from the Python path
sys.path.pop(0)
def load_settings():
with open(config_file, "rb") as f:
toml_dict = tomli.load(f)
# Load project settings
project_config = toml_dict.get("project", {})
features_settings = toml_dict.get("features", {})
ui_settings = toml_dict.get("UI", {})
meta = toml_dict.get("meta")
if not meta or meta.get("generated_by") <= "0.3.0":
raise ValueError(
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")
project_settings = ProjectSettings(
lc_cache_path=lc_cache_path,
**project_config,
)
features_settings = FeaturesSettings(**features_settings)
ui_settings = UISettings(**ui_settings)
code_settings = CodeSettings(action_callbacks={})
return {
"features": features_settings,
"ui": ui_settings,
"project": project_settings,
"code": code_settings,
}
def reload_config():
"""Reload the configuration from the config file."""
global config
if config is None:
return
# Preserve the module_name during config reload to ensure hot reload works
original_module_name = config.run.module_name if config.run else None
new_cfg = ChainlitConfig(**load_settings())
config.root = new_cfg.root
config.chainlit_server = new_cfg.chainlit_server
config.run = new_cfg.run
config.features = new_cfg.features
config.ui = new_cfg.ui
# Restore the preserved module_name
if original_module_name and config.run:
config.run.module_name = original_module_name
config.project = new_cfg.project
config.code = new_cfg.code
def load_config():
"""Load the configuration from the config file."""
init_config()
settings = load_settings()
return ChainlitConfig(**settings)
def lint_translations():
# Load the ground truth (en-US.json file from chainlit source code)
src = os.path.join(TRANSLATIONS_DIR, "en-US.json")
with open(src, encoding="utf-8") as f:
truth = json.load(f)
# Find the local app translations
for file in os.listdir(config_translation_dir):
if file.endswith(".json"):
# Load the translation file
to_lint = os.path.join(config_translation_dir, file)
with open(to_lint, encoding="utf-8") as f2:
translation = json.load(f2)
# Lint the translation file
lint_translation_json(file, truth, translation)
config = load_config()
================================================
FILE: backend/chainlit/context.py
================================================
import asyncio
import uuid
from contextvars import ContextVar
from typing import TYPE_CHECKING, Dict, List, Optional, Union
from lazify import LazyProxy
from chainlit.session import ClientType, HTTPSession, WebsocketSession
if TYPE_CHECKING:
from chainlit.emitter import BaseChainlitEmitter
from chainlit.step import Step
from chainlit.user import PersistedUser, User
CL_RUN_NAMES = ["on_chat_start", "on_message", "on_audio_end"]
class ChainlitContextException(Exception):
def __init__(self, msg="Chainlit context not found", *args, **kwargs):
super().__init__(msg, *args, **kwargs)
class ChainlitContext:
loop: asyncio.AbstractEventLoop
emitter: "BaseChainlitEmitter"
session: Union["HTTPSession", "WebsocketSession"]
@property
def current_step(self):
if previous_steps := local_steps.get():
return previous_steps[-1]
@property
def current_run(self):
if previous_steps := local_steps.get():
return next(
(step for step in previous_steps if step.name in CL_RUN_NAMES), None
)
def __init__(
self,
session: Union["HTTPSession", "WebsocketSession"],
emitter: Optional["BaseChainlitEmitter"] = None,
):
from chainlit.emitter import BaseChainlitEmitter, ChainlitEmitter
self.loop = asyncio.get_running_loop()
self.session = session
if emitter:
self.emitter = emitter
elif isinstance(self.session, HTTPSession):
self.emitter = BaseChainlitEmitter(self.session)
elif isinstance(self.session, WebsocketSession):
self.emitter = ChainlitEmitter(self.session)
context_var: ContextVar[ChainlitContext] = ContextVar("chainlit")
local_steps: ContextVar[Optional[List["Step"]]] = ContextVar(
"local_steps", default=None
)
def init_ws_context(session_or_sid: Union[WebsocketSession, str]) -> ChainlitContext:
if not isinstance(session_or_sid, WebsocketSession):
session = WebsocketSession.require(session_or_sid)
else:
session = session_or_sid
context = ChainlitContext(session)
context_var.set(context)
return context
def init_http_context(
thread_id: Optional[str] = None,
user: Optional[Union["User", "PersistedUser"]] = None,
auth_token: Optional[str] = None,
user_env: Optional[Dict[str, str]] = None,
client_type: ClientType = "webapp",
) -> ChainlitContext:
from chainlit.data import get_data_layer
session_id = str(uuid.uuid4())
thread_id = thread_id or str(uuid.uuid4())
session = HTTPSession(
id=session_id,
thread_id=thread_id,
token=auth_token,
user=user,
client_type=client_type,
user_env=user_env,
)
context = ChainlitContext(session)
context_var.set(context)
if data_layer := get_data_layer():
if user_id := getattr(user, "id", None):
asyncio.create_task(
data_layer.update_thread(thread_id=thread_id, user_id=user_id)
)
return context
def get_context() -> ChainlitContext:
try:
return context_var.get()
except LookupError as e:
raise ChainlitContextException from e
context: ChainlitContext = LazyProxy(get_context, enable_cache=False)
================================================
FILE: backend/chainlit/data/__init__.py
================================================
import os
import warnings
from typing import Optional
from .base import BaseDataLayer
from .utils import (
queue_until_user_message as queue_until_user_message, # TODO: Consider deprecating re-export.; Redundant alias tells type checkers to STFU.
)
_data_layer: Optional[BaseDataLayer] = None
_data_layer_initialized = False
def get_data_layer():
global _data_layer, _data_layer_initialized
if not _data_layer_initialized:
if _data_layer:
# Data layer manually set, warn user that this is deprecated.
warnings.warn(
"Setting data layer manually is deprecated. Use @data_layer instead.",
DeprecationWarning,
)
else:
from chainlit.config import config
if config.code.data_layer:
# When @data_layer is configured, call it to get data layer.
_data_layer = config.code.data_layer()
elif database_url := os.environ.get("DATABASE_URL"):
from .chainlit_data_layer import ChainlitDataLayer
if os.environ.get("LITERAL_API_KEY"):
warnings.warn(
"Both LITERAL_API_KEY and DATABASE_URL specified. Ignoring Literal AI data layer and relying on data layer pointing to DATABASE_URL."
)
bucket_name = os.environ.get("BUCKET_NAME")
# AWS S3
aws_region = os.getenv("APP_AWS_REGION")
aws_access_key = os.getenv("APP_AWS_ACCESS_KEY")
aws_secret_key = os.getenv("APP_AWS_SECRET_KEY")
dev_aws_endpoint = os.getenv("DEV_AWS_ENDPOINT")
is_using_s3 = bool(aws_access_key and aws_secret_key and aws_region)
# Google Cloud Storage
gcs_project_id = os.getenv("APP_GCS_PROJECT_ID")
gcs_client_email = os.getenv("APP_GCS_CLIENT_EMAIL")
gcs_private_key = os.getenv("APP_GCS_PRIVATE_KEY")
is_using_gcs = bool(gcs_project_id)
# Azure Storage
azure_storage_account = os.getenv("APP_AZURE_STORAGE_ACCOUNT")
azure_storage_key = os.getenv("APP_AZURE_STORAGE_ACCESS_KEY")
is_using_azure = bool(azure_storage_account and azure_storage_key)
storage_client = None
if sum([is_using_s3, is_using_gcs, is_using_azure]) > 1:
warnings.warn(
"Multiple storage configurations detected. Please use only one."
)
elif is_using_s3:
from chainlit.data.storage_clients.s3 import S3StorageClient
storage_client = S3StorageClient(
bucket=bucket_name,
region_name=aws_region,
aws_access_key_id=aws_access_key,
aws_secret_access_key=aws_secret_key,
endpoint_url=dev_aws_endpoint,
)
elif is_using_gcs:
from chainlit.data.storage_clients.gcs import GCSStorageClient
storage_client = GCSStorageClient(
project_id=gcs_project_id,
client_email=gcs_client_email,
private_key=gcs_private_key,
bucket_name=bucket_name,
)
elif is_using_azure:
from chainlit.data.storage_clients.azure_blob import (
AzureBlobStorageClient,
)
storage_client = AzureBlobStorageClient(
container_name=bucket_name,
storage_account=azure_storage_account,
storage_key=azure_storage_key,
)
_data_layer = ChainlitDataLayer(
database_url=database_url, storage_client=storage_client
)
elif api_key := os.environ.get("LITERAL_API_KEY"):
# When LITERAL_API_KEY is defined, use Literal AI data layer
from .literalai import LiteralDataLayer
# support legacy LITERAL_SERVER variable as fallback
server = os.environ.get("LITERAL_API_URL") or os.environ.get(
"LITERAL_SERVER"
)
_data_layer = LiteralDataLayer(api_key=api_key, server=server)
_data_layer_initialized = True
return _data_layer
================================================
FILE: backend/chainlit/data/acl.py
================================================
from fastapi import HTTPException
from chainlit.data import get_data_layer
async def is_thread_author(username: str, thread_id: str):
data_layer = get_data_layer()
if not data_layer:
raise HTTPException(status_code=400, detail="Data layer not initialized")
thread_author = await data_layer.get_thread_author(thread_id)
if not thread_author:
raise HTTPException(status_code=404, detail="Thread not found")
if thread_author != username:
raise HTTPException(status_code=401, detail="Unauthorized")
else:
return True
================================================
FILE: backend/chainlit/data/base.py
================================================
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Dict, List, Optional
from chainlit.types import (
Feedback,
PaginatedResponse,
Pagination,
ThreadDict,
ThreadFilter,
)
from .utils import queue_until_user_message
if TYPE_CHECKING:
from chainlit.element import Element, ElementDict
from chainlit.step import StepDict
from chainlit.user import PersistedUser, User
class BaseDataLayer(ABC):
"""Base class for data persistence."""
@abstractmethod
async def get_user(self, identifier: str) -> Optional["PersistedUser"]:
pass
@abstractmethod
async def create_user(self, user: "User") -> Optional["PersistedUser"]:
pass
@abstractmethod
async def delete_feedback(
self,
feedback_id: str,
) -> bool:
pass
@abstractmethod
async def upsert_feedback(
self,
feedback: Feedback,
) -> str:
pass
@queue_until_user_message()
@abstractmethod
async def create_element(self, element: "Element"):
pass
@abstractmethod
async def get_element(
self, thread_id: str, element_id: str
) -> Optional["ElementDict"]:
pass
@queue_until_user_message()
@abstractmethod
async def delete_element(self, element_id: str, thread_id: Optional[str] = None):
pass
@queue_until_user_message()
@abstractmethod
async def create_step(self, step_dict: "StepDict"):
pass
@queue_until_user_message()
@abstractmethod
async def update_step(self, step_dict: "StepDict"):
pass
@queue_until_user_message()
@abstractmethod
async def delete_step(self, step_id: str):
pass
@abstractmethod
async def get_thread_author(self, thread_id: str) -> str:
return ""
@abstractmethod
async def delete_thread(self, thread_id: str):
pass
@abstractmethod
async def list_threads(
self, pagination: "Pagination", filters: "ThreadFilter"
) -> "PaginatedResponse[ThreadDict]":
pass
@abstractmethod
async def get_thread(self, thread_id: str) -> "Optional[ThreadDict]":
pass
@abstractmethod
async def update_thread(
self,
thread_id: str,
name: Optional[str] = None,
user_id: Optional[str] = None,
metadata: Optional[Dict] = None,
tags: Optional[List[str]] = None,
):
pass
@abstractmethod
async def build_debug_url(self) -> str:
pass
@abstractmethod
async def close(self) -> None:
pass
@abstractmethod
async def get_favorite_steps(self, user_id: str) -> List["StepDict"]:
pass
async def set_step_favorite(
self, step_dict: "StepDict", favorite: bool
) -> "StepDict":
metadata = step_dict.get("metadata") or {}
metadata["favorite"] = favorite
step_dict["metadata"] = metadata
await self.update_step(step_dict)
return step_dict
================================================
FILE: backend/chainlit/data/chainlit_data_layer.py
================================================
import json
import uuid
from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
import aiofiles
import asyncpg # type: ignore
from chainlit.data.base import BaseDataLayer
from chainlit.data.storage_clients.base import BaseStorageClient
from chainlit.data.utils import queue_until_user_message
from chainlit.element import ElementDict
from chainlit.logger import logger
from chainlit.step import StepDict
from chainlit.types import (
Feedback,
FeedbackDict,
PageInfo,
PaginatedResponse,
Pagination,
ThreadDict,
ThreadFilter,
)
from chainlit.user import PersistedUser, User
# Import for runtime usage (isinstance checks)
try:
from chainlit.data.storage_clients.gcs import GCSStorageClient
except ImportError:
GCSStorageClient = None # type: ignore[assignment,misc]
if TYPE_CHECKING:
from chainlit.data.storage_clients.gcs import GCSStorageClient
from chainlit.element import Element, ElementDict
from chainlit.step import StepDict
ISO_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
class ChainlitDataLayer(BaseDataLayer):
def __init__(
self,
database_url: str,
storage_client: Optional[BaseStorageClient] = None,
show_logger: bool = False,
):
self.database_url = database_url
self.pool: Optional[asyncpg.Pool] = None
self.storage_client = storage_client
self.show_logger = show_logger
async def connect(self):
if not self.pool:
self.pool = await asyncpg.create_pool(self.database_url)
async def get_current_timestamp(self) -> datetime:
return datetime.now()
async def execute_query(
self, query: str, params: Union[Dict, None] = None
) -> List[Dict[str, Any]]:
if not self.pool:
await self.connect()
try:
async with self.pool.acquire() as connection: # type: ignore
try:
if params:
records = await connection.fetch(query, *params.values())
else:
records = await connection.fetch(query)
return [dict(record) for record in records]
except Exception as e:
logger.error(f"Database error: {e!s}")
raise
except (
asyncpg.exceptions.ConnectionDoesNotExistError,
asyncpg.exceptions.InterfaceError,
) as e:
# Handle connection issues by cleaning up and rethrowing
logger.error(f"Connection error: {e!s}")
await self.cleanup()
raise
async def get_user(self, identifier: str) -> Optional[PersistedUser]:
query = """
SELECT * FROM "User"
WHERE identifier = $1
"""
result = await self.execute_query(query, {"identifier": identifier})
if not result or len(result) == 0:
return None
row = result[0]
return PersistedUser(
id=str(row.get("id")),
identifier=str(row.get("identifier")),
createdAt=row.get("createdAt").isoformat(), # type: ignore
metadata=json.loads(row.get("metadata", "{}")),
)
async def create_user(self, user: User) -> Optional[PersistedUser]:
query = """
INSERT INTO "User" (id, identifier, metadata, "createdAt", "updatedAt")
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (identifier) DO UPDATE
SET metadata = $3
RETURNING *
"""
now = await self.get_current_timestamp()
params = {
"id": str(uuid.uuid4()),
"identifier": user.identifier,
"metadata": json.dumps(user.metadata),
"created_at": now,
"updated_at": now,
}
result = await self.execute_query(query, params)
row = result[0]
return PersistedUser(
id=str(row.get("id")),
identifier=str(row.get("identifier")),
createdAt=row.get("createdAt").isoformat(), # type: ignore
metadata=json.loads(row.get("metadata", "{}")),
)
async def delete_feedback(self, feedback_id: str) -> bool:
query = """
DELETE FROM "Feedback" WHERE id = $1
"""
await self.execute_query(query, {"feedback_id": feedback_id})
return True
async def upsert_feedback(self, feedback: Feedback) -> str:
query = """
INSERT INTO "Feedback" (id, "stepId", name, value, comment)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (id) DO UPDATE
SET value = $4, comment = $5
RETURNING id
"""
feedback_id = feedback.id or str(uuid.uuid4())
params = {
"id": feedback_id,
"step_id": feedback.forId,
"name": "user_feedback",
"value": float(feedback.value),
"comment": feedback.comment,
}
results = await self.execute_query(query, params)
return str(results[0]["id"])
@queue_until_user_message()
async def create_element(self, element: "Element"):
if not element.for_id:
return
if element.thread_id:
query = 'SELECT id FROM "Thread" WHERE id = $1'
results = await self.execute_query(query, {"thread_id": element.thread_id})
if not results:
await self.update_thread(thread_id=element.thread_id)
if element.for_id:
query = 'SELECT id FROM "Step" WHERE id = $1'
results = await self.execute_query(query, {"step_id": element.for_id})
if not results:
await self.create_step(
{
"id": element.for_id,
"metadata": {},
"type": "run",
"start_time": await self.get_current_timestamp(),
"end_time": await self.get_current_timestamp(),
}
)
# Handle file uploads only if storage_client is configured
path = None
if self.storage_client:
content: Optional[Union[bytes, str]] = None
if element.path:
async with aiofiles.open(element.path, "rb") as f:
content = await f.read()
elif element.content:
content = element.content
elif not element.url:
raise ValueError("Element url, path or content must be provided")
if content is not None:
if element.thread_id:
path = f"threads/{element.thread_id}/files/{element.id}"
else:
path = f"files/{element.id}"
content_disposition = (
f'attachment; filename="{element.name}"'
if not (
GCSStorageClient is not None
and isinstance(self.storage_client, GCSStorageClient)
)
else None
)
await self.storage_client.upload_file(
object_key=path,
data=content,
mime=element.mime or "application/octet-stream",
overwrite=True,
content_disposition=content_disposition,
)
else:
# Log warning only if element has file content that needs uploading
if element.path or element.url or element.content:
logger.warning(
"Data Layer: No storage client configured. "
"File will not be uploaded."
)
# Always persist element metadata to database
query = """
INSERT INTO "Element" (
id, "threadId", "stepId", metadata, mime, name, "objectKey", url,
"chainlitKey", display, size, language, page, props
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14
)
ON CONFLICT (id) DO UPDATE SET
props = EXCLUDED.props
"""
params = {
"id": element.id,
"thread_id": element.thread_id,
"step_id": element.for_id,
"metadata": json.dumps(
{
"size": element.size,
"language": element.language,
"display": element.display,
"type": element.type,
"page": getattr(element, "page", None),
}
),
"mime": element.mime,
"name": element.name,
"object_key": path,
"url": element.url,
"chainlit_key": element.chainlit_key,
"display": element.display,
"size": element.size,
"language": element.language,
"page": getattr(element, "page", None),
"props": json.dumps(getattr(element, "props", {})),
}
await self.execute_query(query, params)
async def get_element(
self, thread_id: str, element_id: str
) -> Optional[ElementDict]:
query = """
SELECT * FROM "Element"
WHERE id = $1 AND "threadId" = $2
"""
results = await self.execute_query(
query, {"element_id": element_id, "thread_id": thread_id}
)
if not results:
return None
row = results[0]
metadata = json.loads(row.get("metadata", "{}"))
return ElementDict(
id=str(row["id"]),
threadId=str(row["threadId"]),
type=metadata.get("type", "file"),
url=str(row["url"]),
name=str(row["name"]),
mime=str(row["mime"]),
objectKey=str(row["objectKey"]),
forId=str(row["stepId"]),
chainlitKey=row.get("chainlitKey"),
display=row["display"],
size=row["size"],
language=row["language"],
page=row["page"],
autoPlay=row.get("autoPlay"),
playerConfig=row.get("playerConfig"),
props=json.loads(row.get("props", "{}")),
)
@queue_until_user_message()
async def delete_element(self, element_id: str, thread_id: Optional[str] = None):
query = """
SELECT * FROM "Element"
WHERE id = $1
"""
elements = await self.execute_query(query, {"id": element_id})
if self.storage_client is not None and len(elements) > 0:
if elements[0]["objectKey"]:
await self.storage_client.delete_file(
object_key=elements[0]["objectKey"]
)
query = """
DELETE FROM "Element"
WHERE id = $1
"""
params = {"id": element_id}
if thread_id:
query += ' AND "threadId" = $2'
params["thread_id"] = thread_id
await self.execute_query(query, params)
@queue_until_user_message()
async def create_step(self, step_dict: StepDict):
if step_dict.get("threadId"):
thread_query = 'SELECT id FROM "Thread" WHERE id = $1'
thread_results = await self.execute_query(
thread_query, {"thread_id": step_dict["threadId"]}
)
if not thread_results:
await self.update_thread(thread_id=step_dict["threadId"])
if step_dict.get("parentId"):
parent_query = 'SELECT id FROM "Step" WHERE id = $1'
parent_results = await self.execute_query(
parent_query, {"parent_id": step_dict["parentId"]}
)
if not parent_results:
await self.create_step(
{
"id": step_dict["parentId"],
"metadata": {},
"type": "run",
"createdAt": step_dict.get("createdAt"),
}
)
query = """
INSERT INTO "Step" (
id, "threadId", "parentId", input, metadata, name, output,
type, "startTime", "endTime", "showInput", "isError"
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
)
ON CONFLICT (id) DO UPDATE SET
"parentId" = COALESCE(EXCLUDED."parentId", "Step"."parentId"),
input = COALESCE(NULLIF(EXCLUDED.input, ''), "Step".input),
metadata = CASE
WHEN EXCLUDED.metadata <> '{}' THEN EXCLUDED.metadata
ELSE "Step".metadata
END,
name = COALESCE(EXCLUDED.name, "Step".name),
output = COALESCE(NULLIF(EXCLUDED.output, ''), "Step".output),
type = CASE
WHEN EXCLUDED.type = 'run' THEN "Step".type
ELSE EXCLUDED.type
END,
"threadId" = COALESCE(EXCLUDED."threadId", "Step"."threadId"),
"endTime" = COALESCE(EXCLUDED."endTime", "Step"."endTime"),
"startTime" = LEAST(EXCLUDED."startTime", "Step"."startTime"),
"showInput" = COALESCE(EXCLUDED."showInput", "Step"."showInput"),
"isError" = COALESCE(EXCLUDED."isError", "Step"."isError")
"""
timestamp = await self.get_current_timestamp()
created_at = step_dict.get("createdAt")
if created_at:
timestamp = datetime.strptime(created_at, ISO_FORMAT)
params = {
"id": step_dict["id"],
"thread_id": step_dict.get("threadId"),
"parent_id": step_dict.get("parentId"),
"input": step_dict.get("input"),
"metadata": json.dumps(step_dict.get("metadata", {})),
"name": step_dict.get("name"),
"output": step_dict.get("output"),
"type": step_dict["type"],
"start_time": timestamp,
"end_time": timestamp,
"show_input": str(step_dict.get("showInput", "json")),
"is_error": step_dict.get("isError", False),
}
await self.execute_query(query, params)
@queue_until_user_message()
async def update_step(self, step_dict: StepDict):
await self.create_step(step_dict)
@queu
gitextract_rcugvcbq/ ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── actions/ │ │ ├── pnpm-node-install/ │ │ │ └── action.yaml │ │ └── uv-python-install/ │ │ └── action.yaml │ ├── copilot-instructions.md │ └── workflows/ │ ├── ci.yaml │ ├── close_stale.yml │ ├── copilot-setup-steps.yaml │ ├── e2e-tests.yaml │ ├── lint-backend.yaml │ ├── lint-ui.yaml │ ├── publish-libs.yaml │ ├── publish.yaml │ └── pytest.yaml ├── .gitignore ├── .husky/ │ └── pre-commit ├── .npmrc ├── .prettierrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── PRIVACY_POLICY.md ├── RELENG.md ├── backend/ │ ├── build.py │ ├── chainlit/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _utils.py │ │ ├── action.py │ │ ├── auth/ │ │ │ ├── __init__.py │ │ │ ├── cookie.py │ │ │ └── jwt.py │ │ ├── cache.py │ │ ├── callbacks.py │ │ ├── chat_context.py │ │ ├── chat_settings.py │ │ ├── cli/ │ │ │ └── __init__.py │ │ ├── config.py │ │ ├── context.py │ │ ├── data/ │ │ │ ├── __init__.py │ │ │ ├── acl.py │ │ │ ├── base.py │ │ │ ├── chainlit_data_layer.py │ │ │ ├── dynamodb.py │ │ │ ├── literalai.py │ │ │ ├── sql_alchemy.py │ │ │ ├── storage_clients/ │ │ │ │ ├── __init__.py │ │ │ │ ├── azure.py │ │ │ │ ├── azure_blob.py │ │ │ │ ├── base.py │ │ │ │ ├── gcs.py │ │ │ │ └── s3.py │ │ │ └── utils.py │ │ ├── discord/ │ │ │ ├── __init__.py │ │ │ └── app.py │ │ ├── element.py │ │ ├── emitter.py │ │ ├── input_widget.py │ │ ├── langchain/ │ │ │ ├── __init__.py │ │ │ └── callbacks.py │ │ ├── langflow/ │ │ │ └── __init__.py │ │ ├── llama_index/ │ │ │ ├── __init__.py │ │ │ └── callbacks.py │ │ ├── logger.py │ │ ├── markdown.py │ │ ├── mcp.py │ │ ├── message.py │ │ ├── mistralai/ │ │ │ └── __init__.py │ │ ├── mode.py │ │ ├── oauth_providers.py │ │ ├── openai/ │ │ │ └── __init__.py │ │ ├── py.typed │ │ ├── sample/ │ │ │ ├── hello.py │ │ │ └── starters_demo.py │ │ ├── secret.py │ │ ├── semantic_kernel/ │ │ │ └── __init__.py │ │ ├── server.py │ │ ├── session.py │ │ ├── sidebar.py │ │ ├── slack/ │ │ │ ├── __init__.py │ │ │ └── app.py │ │ ├── socket.py │ │ ├── step.py │ │ ├── sync.py │ │ ├── teams/ │ │ │ ├── __init__.py │ │ │ └── app.py │ │ ├── translations/ │ │ │ ├── ar-SA.json │ │ │ ├── bn.json │ │ │ ├── da-DK.json │ │ │ ├── de-DE.json │ │ │ ├── el-GR.json │ │ │ ├── en-US.json │ │ │ ├── es.json │ │ │ ├── fr-FR.json │ │ │ ├── gu.json │ │ │ ├── he-IL.json │ │ │ ├── hi.json │ │ │ ├── it.json │ │ │ ├── ja.json │ │ │ ├── kn.json │ │ │ ├── ko.json │ │ │ ├── ml.json │ │ │ ├── mr.json │ │ │ ├── nl.json │ │ │ ├── ta.json │ │ │ ├── te.json │ │ │ ├── zh-CN.json │ │ │ └── zh-TW.json │ │ ├── translations.py │ │ ├── types.py │ │ ├── user.py │ │ ├── user_session.py │ │ ├── utils.py │ │ └── version.py │ ├── pyproject.toml │ └── tests/ │ ├── __init__.py │ ├── auth/ │ │ ├── __init__.py │ │ └── test_cookie.py │ ├── conftest.py │ ├── data/ │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── storage_clients/ │ │ │ ├── test_gcs.py │ │ │ └── test_s3.py │ │ ├── test_chainlit_data_layer.py │ │ ├── test_get_data_layer.py │ │ ├── test_literalai.py │ │ └── test_sql_alchemy.py │ ├── langchain/ │ │ ├── __init__.py │ │ ├── test_async_callback.py │ │ ├── test_chain_types.py │ │ └── test_sync_callback.py │ ├── llama_index/ │ │ └── test_callbacks.py │ ├── test_action.py │ ├── test_cache.py │ ├── test_callbacks.py │ ├── test_chat_context.py │ ├── test_chat_settings.py │ ├── test_context.py │ ├── test_element.py │ ├── test_emitter.py │ ├── test_input_widget.py │ ├── test_markdown.py │ ├── test_mcp.py │ ├── test_message.py │ ├── test_modes.py │ ├── test_oauth_providers.py │ ├── test_server.py │ ├── test_session.py │ ├── test_sidebar.py │ ├── test_slack_socket_mode.py │ ├── test_socket.py │ ├── test_step.py │ ├── test_translations.py │ ├── test_user_session.py │ └── test_utils.py ├── cypress/ │ ├── e2e/ │ │ ├── action/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── ask_custom_element/ │ │ │ ├── main.py │ │ │ ├── public/ │ │ │ │ └── elements/ │ │ │ │ └── JiraTicket.jsx │ │ │ └── spec.cy.ts │ │ ├── ask_file/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── ask_multiple_files/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── ask_user/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── audio_element/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── auth/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── blinking_cursor/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── chat_context/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── chat_prefill/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── chat_profiles/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── chat_settings/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── command/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── config_overrides/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── context/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── copilot/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── custom_build/ │ │ │ ├── .gitignore │ │ │ ├── main.py │ │ │ ├── public/ │ │ │ │ ├── .gitignore │ │ │ │ └── build/ │ │ │ │ ├── assets/ │ │ │ │ │ └── .PLACEHOLDER │ │ │ │ └── index.html │ │ │ └── spec.cy.ts │ │ ├── custom_data_layer/ │ │ │ └── sql_alchemy.py │ │ ├── custom_element/ │ │ │ ├── main.py │ │ │ ├── public/ │ │ │ │ └── elements/ │ │ │ │ └── Counter.jsx │ │ │ └── spec.cy.ts │ │ ├── custom_element_auth/ │ │ │ ├── main.py │ │ │ ├── spec.cy.ts │ │ │ └── test.txt │ │ ├── custom_element_command/ │ │ │ ├── main.py │ │ │ ├── public/ │ │ │ │ └── elements/ │ │ │ │ └── Commander.jsx │ │ │ └── spec.cy.ts │ │ ├── custom_theme/ │ │ │ ├── main.py │ │ │ ├── public/ │ │ │ │ └── theme.json │ │ │ └── spec.cy.ts │ │ ├── data_layer/ │ │ │ ├── .gitignore │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── dataframe/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── edit_message/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── elements/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── error_handling/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── file_element/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── header_auth/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── llama_index_cb/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── modes/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── on_chat_start/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── password_auth/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── plotly/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── pyplot/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── readme/ │ │ │ ├── chainlit_pt-BR.md │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── remove_elements/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── remove_step/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── sidebar/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── starters/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── starters_categories/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── step/ │ │ │ ├── async-spec.cy.ts │ │ │ ├── main_async.py │ │ │ ├── main_sync.py │ │ │ ├── sync-spec.cy.ts │ │ │ └── tests.ts │ │ ├── stop_task/ │ │ │ ├── async-spec.cy.ts │ │ │ ├── main_async.py │ │ │ ├── main_sync.py │ │ │ ├── sync-spec.cy.ts │ │ │ └── tests.ts │ │ ├── streaming/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── tasklist/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── thread_resume/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── update_step/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── upload_attachments/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── user_env/ │ │ │ ├── .gitignore │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ ├── user_session/ │ │ │ ├── main.py │ │ │ └── spec.cy.ts │ │ └── window_message/ │ │ ├── main.py │ │ ├── public/ │ │ │ └── iframe.html │ │ └── spec.cy.ts │ ├── fixtures/ │ │ ├── hello.cpp │ │ ├── hello.py │ │ └── state_of_the_union.txt │ └── support/ │ ├── e2e.ts │ ├── run.ts │ └── testUtils.ts ├── cypress.config.ts ├── frontend/ │ ├── .eslintignore │ ├── .gitignore │ ├── components.json │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── src/ │ │ ├── App.tsx │ │ ├── AppWrapper.tsx │ │ ├── api/ │ │ │ └── index.ts │ │ ├── components/ │ │ │ ├── Alert.tsx │ │ │ ├── AudioPresence.tsx │ │ │ ├── AutoResizeTextarea.tsx │ │ │ ├── AutoResumeThread.tsx │ │ │ ├── BlinkingCursor.tsx │ │ │ ├── ButtonLink.tsx │ │ │ ├── ChatSettings/ │ │ │ │ ├── ChatSettingsSidebar.tsx │ │ │ │ ├── CheckboxInput.tsx │ │ │ │ ├── DatePickerInput.tsx │ │ │ │ ├── FormInput.tsx │ │ │ │ ├── InputLabel.tsx │ │ │ │ ├── InputStateHandler.tsx │ │ │ │ ├── MultiSelectInput.tsx │ │ │ │ ├── NotificationCount.tsx │ │ │ │ ├── RadioButtonGroup.tsx │ │ │ │ ├── SelectInput.tsx │ │ │ │ ├── SliderInput.tsx │ │ │ │ ├── SwitchInput.tsx │ │ │ │ ├── TagsInput.tsx │ │ │ │ ├── TextInput.tsx │ │ │ │ └── index.tsx │ │ │ ├── CodeSnippet.tsx │ │ │ ├── CopyButton.tsx │ │ │ ├── ElementSideView.tsx │ │ │ ├── ElementView.tsx │ │ │ ├── Elements/ │ │ │ │ ├── Audio.tsx │ │ │ │ ├── CustomElement/ │ │ │ │ │ ├── Imports.ts │ │ │ │ │ ├── Renderer.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Dataframe.tsx │ │ │ │ ├── ElementRef.tsx │ │ │ │ ├── File.tsx │ │ │ │ ├── Image.tsx │ │ │ │ ├── LazyDataframe.tsx │ │ │ │ ├── PDF.tsx │ │ │ │ ├── Plotly.tsx │ │ │ │ ├── Text.tsx │ │ │ │ ├── Video.tsx │ │ │ │ └── index.tsx │ │ │ ├── ErrorBoundary.tsx │ │ │ ├── Icon.tsx │ │ │ ├── Kbd.tsx │ │ │ ├── LeftSidebar/ │ │ │ │ ├── Search.tsx │ │ │ │ ├── ThreadHistory.tsx │ │ │ │ ├── ThreadList.tsx │ │ │ │ ├── ThreadOptions.tsx │ │ │ │ └── index.tsx │ │ │ ├── Loader.tsx │ │ │ ├── LoginForm.tsx │ │ │ ├── Logo.tsx │ │ │ ├── Markdown.tsx │ │ │ ├── MarkdownAlert.tsx │ │ │ ├── ProviderButton.tsx │ │ │ ├── QuiltedGrid.tsx │ │ │ ├── ReadOnlyThread.tsx │ │ │ ├── Tasklist/ │ │ │ │ ├── Task.tsx │ │ │ │ ├── TaskStatusIcon.tsx │ │ │ │ └── index.tsx │ │ │ ├── ThemeProvider.tsx │ │ │ ├── WaterMark.tsx │ │ │ ├── chat/ │ │ │ │ ├── Footer.tsx │ │ │ │ ├── MessageComposer/ │ │ │ │ │ ├── Attachment.tsx │ │ │ │ │ ├── Attachments.tsx │ │ │ │ │ ├── CommandButtons.tsx │ │ │ │ │ ├── CommandPopoverButton.tsx │ │ │ │ │ ├── FavoriteButton.tsx │ │ │ │ │ ├── Input.tsx │ │ │ │ │ ├── Mcp/ │ │ │ │ │ │ ├── AddForm.tsx │ │ │ │ │ │ ├── AnimatedPlugIcon.tsx │ │ │ │ │ │ ├── List.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ModePicker.tsx │ │ │ │ │ ├── SubmitButton.tsx │ │ │ │ │ ├── UploadButton.tsx │ │ │ │ │ ├── VoiceButton.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Messages/ │ │ │ │ │ ├── Message/ │ │ │ │ │ │ ├── AskActionButtons.tsx │ │ │ │ │ │ ├── AskFileButton.tsx │ │ │ │ │ │ ├── Avatar.tsx │ │ │ │ │ │ ├── Buttons/ │ │ │ │ │ │ │ ├── Actions/ │ │ │ │ │ │ │ │ ├── ActionButton.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── DebugButton.tsx │ │ │ │ │ │ │ ├── FeedbackButtons.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Content/ │ │ │ │ │ │ │ ├── InlinedElements/ │ │ │ │ │ │ │ │ ├── InlineCustomElementList.tsx │ │ │ │ │ │ │ │ ├── InlinedAudioList.tsx │ │ │ │ │ │ │ │ ├── InlinedDataframeList.tsx │ │ │ │ │ │ │ │ ├── InlinedFileList.tsx │ │ │ │ │ │ │ │ ├── InlinedImageList.tsx │ │ │ │ │ │ │ │ ├── InlinedPDFList.tsx │ │ │ │ │ │ │ │ ├── InlinedPlotlyList.tsx │ │ │ │ │ │ │ │ ├── InlinedTextList.tsx │ │ │ │ │ │ │ │ ├── InlinedVideoList.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Step.tsx │ │ │ │ │ │ ├── UserMessage.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── MessagesContainer/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ScrollContainer.tsx │ │ │ │ ├── ScrollDownButton.tsx │ │ │ │ ├── Starter.tsx │ │ │ │ ├── StarterCategory.tsx │ │ │ │ ├── Starters.tsx │ │ │ │ ├── WelcomeScreen.tsx │ │ │ │ └── index.tsx │ │ │ ├── header/ │ │ │ │ ├── ApiKeys.tsx │ │ │ │ ├── ChatProfiles.tsx │ │ │ │ ├── NewChat.tsx │ │ │ │ ├── Readme.tsx │ │ │ │ ├── Share.tsx │ │ │ │ ├── SidebarTrigger.tsx │ │ │ │ ├── ThemeToggle.tsx │ │ │ │ ├── UserNav.tsx │ │ │ │ └── index.tsx │ │ │ ├── i18n/ │ │ │ │ ├── Translator.tsx │ │ │ │ └── index.ts │ │ │ ├── icons/ │ │ │ │ ├── Auth0.tsx │ │ │ │ ├── Cognito.tsx │ │ │ │ ├── Descope.tsx │ │ │ │ ├── EditSquare.tsx │ │ │ │ ├── Github.tsx │ │ │ │ ├── Gitlab.tsx │ │ │ │ ├── Google.tsx │ │ │ │ ├── Microsoft.tsx │ │ │ │ ├── Okta.tsx │ │ │ │ ├── PaperClip.tsx │ │ │ │ ├── Pencil.tsx │ │ │ │ ├── Search.tsx │ │ │ │ ├── Send.tsx │ │ │ │ ├── Settings.tsx │ │ │ │ ├── Sidebar.tsx │ │ │ │ ├── Stop.tsx │ │ │ │ ├── ToolBox.tsx │ │ │ │ └── VoiceLines.tsx │ │ │ ├── share/ │ │ │ │ └── ShareDialog.tsx │ │ │ └── ui/ │ │ │ ├── accordion.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── aspect-ratio.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ ├── calendar.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── command.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── form.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── pagination.tsx │ │ │ ├── popover.tsx │ │ │ ├── progress.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── sidebar.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── slider.tsx │ │ │ ├── sonner.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ └── tooltip.tsx │ │ ├── contexts/ │ │ │ └── MessageContext.tsx │ │ ├── hooks/ │ │ │ ├── query.ts │ │ │ ├── use-mobile.tsx │ │ │ ├── useCommandNavigation.tsx │ │ │ ├── useFetch.tsx │ │ │ ├── useLayoutMaxWidth.tsx │ │ │ ├── usePlatform.ts │ │ │ └── useUpload.tsx │ │ ├── i18n/ │ │ │ ├── dateLocale.ts │ │ │ └── index.ts │ │ ├── index.css │ │ ├── index.d.ts │ │ ├── lib/ │ │ │ ├── message.ts │ │ │ ├── router.ts │ │ │ └── utils.ts │ │ ├── main.tsx │ │ ├── pages/ │ │ │ ├── AuthCallback.tsx │ │ │ ├── Element.tsx │ │ │ ├── Env.tsx │ │ │ ├── Home.tsx │ │ │ ├── Login.tsx │ │ │ ├── Page.tsx │ │ │ └── Thread.tsx │ │ ├── router.tsx │ │ ├── state/ │ │ │ ├── chat.ts │ │ │ ├── project.ts │ │ │ └── user.ts │ │ ├── types/ │ │ │ ├── Input.ts │ │ │ ├── NotificationCount.tsx │ │ │ ├── chat.ts │ │ │ ├── index.ts │ │ │ └── messageContext.ts │ │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tests/ │ │ ├── FavoriteButton.spec.tsx │ │ ├── NewChat.spec.tsx │ │ ├── content.spec.tsx │ │ ├── icon.spec.tsx │ │ ├── setup-tests.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.ts │ └── vitest.config.ts ├── libs/ │ ├── copilot/ │ │ ├── .storybook/ │ │ │ ├── main.ts │ │ │ └── preview.ts │ │ ├── components.json │ │ ├── index.tsx │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── sonner.css │ │ ├── src/ │ │ │ ├── ThemeProvider.tsx │ │ │ ├── api.ts │ │ │ ├── app.tsx │ │ │ ├── appWrapper.tsx │ │ │ ├── chat/ │ │ │ │ ├── body.tsx │ │ │ │ └── index.tsx │ │ │ ├── components/ │ │ │ │ ├── ElementSideView.tsx │ │ │ │ ├── Header.tsx │ │ │ │ └── WelcomeScreen.tsx │ │ │ ├── hooks/ │ │ │ │ ├── index.ts │ │ │ │ └── useCopilotInteract.ts │ │ │ ├── index.css │ │ │ ├── lib/ │ │ │ │ └── utils.ts │ │ │ ├── state.ts │ │ │ ├── types.ts │ │ │ └── widget.tsx │ │ ├── stories/ │ │ │ └── App.stories.ts │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── react-client/ │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── api/ │ │ │ ├── hooks/ │ │ │ │ ├── api.ts │ │ │ │ └── auth/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ ├── sessionManagement.ts │ │ │ │ ├── state.ts │ │ │ │ ├── types.ts │ │ │ │ └── userManagement.ts │ │ │ └── index.tsx │ │ ├── context.ts │ │ ├── index.ts │ │ ├── state.ts │ │ ├── types/ │ │ │ ├── action.ts │ │ │ ├── audio.ts │ │ │ ├── command.ts │ │ │ ├── config.ts │ │ │ ├── element.ts │ │ │ ├── feedback.ts │ │ │ ├── file.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ ├── mcp.ts │ │ │ ├── mode.ts │ │ │ ├── step.ts │ │ │ ├── thread.ts │ │ │ └── user.ts │ │ ├── useAudio.ts │ │ ├── useChatData.ts │ │ ├── useChatInteract.ts │ │ ├── useChatMessages.ts │ │ ├── useChatSession.ts │ │ ├── useConfig.ts │ │ ├── utils/ │ │ │ ├── group.ts │ │ │ └── message.ts │ │ └── wavtools/ │ │ ├── analysis/ │ │ │ ├── audio_analysis.js │ │ │ └── constants.js │ │ ├── index.ts │ │ ├── wav_packer.js │ │ ├── wav_recorder.js │ │ ├── wav_renderer.ts │ │ ├── wav_stream_player.js │ │ └── worklets/ │ │ ├── audio_processor.js │ │ └── stream_processor.js │ ├── tsconfig.build.json │ └── tsconfig.json ├── lint-staged.config.js ├── package.json ├── pnpm-workspace.yaml └── tsconfig.json
Showing preview only (208K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2285 symbols across 341 files)
FILE: backend/build.py
class BuildError (line 11) | class BuildError(Exception):
function run_subprocess (line 17) | def run_subprocess(cmd: list[str], cwd: pathlib.Path) -> None:
function pnpm_install (line 30) | def pnpm_install(project_root: pathlib.Path, pnpm_path: str):
function pnpm_buildui (line 34) | def pnpm_buildui(project_root: pathlib.Path, pnpm_path: str):
function copy_directory (line 38) | def copy_directory(src: pathlib.Path, dst: pathlib.Path, description: str):
function copy_frontend (line 56) | def copy_frontend(project_root: pathlib.Path):
function copy_copilot (line 63) | def copy_copilot(project_root: pathlib.Path):
function build (line 70) | def build():
class CustomBuildHook (line 108) | class CustomBuildHook(BuildHookInterface):
method initialize (line 109) | def initialize(self, _, __):
FILE: backend/chainlit/__init__.py
function sleep (line 109) | def sleep(duration: int):
class CopilotFunction (line 119) | class CopilotFunction:
method acall (line 123) | def acall(self):
function __dir__ (line 224) | def __dir__():
FILE: backend/chainlit/_utils.py
function is_path_inside (line 6) | def is_path_inside(child_path: Path, parent_path: Path) -> bool:
FILE: backend/chainlit/action.py
class Action (line 12) | class Action(DataClassJsonMixin):
method send (line 28) | async def send(self, for_id: str):
method remove (line 32) | async def remove(self):
FILE: backend/chainlit/auth/__init__.py
function ensure_jwt_secret (line 21) | def ensure_jwt_secret():
function is_oauth_enabled (line 28) | def is_oauth_enabled():
function require_login (line 32) | def require_login():
function get_configuration (line 41) | def get_configuration():
function authenticate_user (line 58) | async def authenticate_user(token: str = Depends(reuseable_oauth)):
function get_current_user (line 86) | async def get_current_user(token: str = Depends(reuseable_oauth)):
FILE: backend/chainlit/auth/cookie.py
class OAuth2PasswordBearerWithCookie (line 37) | class OAuth2PasswordBearerWithCookie(SecurityBase):
method __init__ (line 42) | def __init__(
method __call__ (line 52) | async def __call__(self, request: Request) -> Optional[str]:
function _get_chunked_cookie (line 84) | def _get_chunked_cookie(cookies: dict[str, str], name: str) -> Optional[...
function get_token_from_cookies (line 102) | def get_token_from_cookies(cookies: dict[str, str]) -> Optional[str]:
function set_auth_cookie (line 114) | def set_auth_cookie(request: Request, response: Response, token: str):
function clear_auth_cookie (line 162) | def clear_auth_cookie(request: Request, response: Response):
function set_oauth_state_cookie (line 177) | def set_oauth_state_cookie(response: Response, token: str):
function validate_oauth_state_cookie (line 188) | def validate_oauth_state_cookie(request: Request, state: str):
function clear_oauth_state_cookie (line 197) | def clear_oauth_state_cookie(response: Response):
FILE: backend/chainlit/auth/jwt.py
function get_jwt_secret (line 11) | def get_jwt_secret() -> Optional[str]:
function create_jwt (line 15) | def create_jwt(data: User) -> str:
function decode_jwt (line 31) | def decode_jwt(token: str) -> User:
FILE: backend/chainlit/cache.py
function init_lc_cache (line 10) | def init_lc_cache():
function cache (line 30) | def cache(func):
FILE: backend/chainlit/callbacks.py
function on_app_startup (line 21) | def on_app_startup(func: Callable[[], Union[None, Awaitable[None]]]) -> ...
function on_app_shutdown (line 43) | def on_app_shutdown(func: Callable[[], Union[None, Awaitable[None]]]) ->...
function password_auth_callback (line 65) | def password_auth_callback(
function header_auth_callback (line 86) | def header_auth_callback(
function oauth_callback (line 107) | def oauth_callback(
function on_logout (line 135) | def on_logout(func: Callable[[Request, Response], Any]) -> Callable:
function on_message (line 145) | def on_message(func: Callable) -> Callable:
function send_window_message (line 169) | async def send_window_message(data: Any):
function on_window_message (line 179) | def on_window_message(func: Callable[[str], Any]) -> Callable:
function on_chat_start (line 194) | def on_chat_start(func: Callable) -> Callable:
function on_chat_resume (line 211) | def on_chat_resume(func: Callable[[ThreadDict], Any]) -> Callable:
function set_chat_profiles (line 227) | def set_chat_profiles(
function set_chat_profiles (line 233) | def set_chat_profiles(
function set_chat_profiles (line 238) | def set_chat_profiles(func):
function set_starters (line 254) | def set_starters(
function set_starters (line 260) | def set_starters(
function set_starters (line 265) | def set_starters(func):
function set_starter_categories (line 281) | def set_starter_categories(
function set_starter_categories (line 287) | def set_starter_categories(
function set_starter_categories (line 296) | def set_starter_categories(func):
function on_chat_end (line 311) | def on_chat_end(func: Callable) -> Callable:
function on_audio_start (line 326) | def on_audio_start(func: Callable) -> Callable:
function on_audio_chunk (line 338) | def on_audio_chunk(func: Callable) -> Callable:
function on_audio_end (line 353) | def on_audio_end(func: Callable) -> Callable:
function author_rename (line 367) | def author_rename(
function on_mcp_connect (line 383) | def on_mcp_connect(
function on_mcp_disconnect (line 394) | def on_mcp_disconnect(
function on_stop (line 405) | def on_stop(func: Callable) -> Callable:
function action_callback (line 420) | def action_callback(name: str) -> Callable:
function on_settings_update (line 435) | def on_settings_update(
function on_settings_edit (line 452) | def on_settings_edit(
function data_layer (line 469) | def data_layer(
function on_feedback (line 483) | def on_feedback(func: Callable) -> Callable:
function on_slack_reaction_added (line 504) | def on_slack_reaction_added(func: Callable[[Dict[str, Any]], Any]) -> Ca...
function on_shared_thread_view (line 531) | def on_shared_thread_view(
FILE: backend/chainlit/chat_context.py
class ChatContext (line 11) | class ChatContext:
method get (line 12) | def get(self) -> List["Message"]:
method add (line 22) | def add(self, message: "Message"):
method remove (line 34) | def remove(self, message: "Message") -> bool:
method clear (line 47) | def clear(self) -> None:
method to_openai (line 51) | def to_openai(self):
FILE: backend/chainlit/chat_settings.py
class ChatSettings (line 11) | class ChatSettings:
method __init__ (line 16) | def __init__(
method settings (line 22) | def settings(self):
method send (line 36) | async def send(self):
FILE: backend/chainlit/cli/__init__.py
function assert_app (line 39) | def assert_app():
function cli (line 53) | def cli():
function run_chainlit (line 58) | def run_chainlit(target: str):
function chainlit_run (line 176) | def chainlit_run(
function chainlit_hello (line 222) | def chainlit_hello(args=None, **kwargs):
function chainlit_init (line 229) | def chainlit_init(args=None, **kwargs):
function chainlit_create_secret (line 235) | def chainlit_create_secret(args=None, **kwargs):
function chainlit_lint_translations (line 243) | def chainlit_lint_translations(args=None, **kwargs):
FILE: backend/chainlit/config.py
class RunSettings (line 255) | class RunSettings(BaseModel):
class PaletteOptions (line 270) | class PaletteOptions(BaseModel):
class TextOptions (line 276) | class TextOptions(BaseModel):
class Palette (line 281) | class Palette(BaseModel):
class SpontaneousFileUploadFeature (line 288) | class SpontaneousFileUploadFeature(BaseModel):
class AudioFeature (line 295) | class AudioFeature(BaseModel):
class McpSseFeature (line 300) | class McpSseFeature(BaseModel):
class McpStreamableHttpFeature (line 304) | class McpStreamableHttpFeature(BaseModel):
class McpStdioFeature (line 308) | class McpStdioFeature(BaseModel):
class SlackFeature (line 313) | class SlackFeature(BaseModel):
class McpFeature (line 317) | class McpFeature(BaseModel):
class FeaturesSettings (line 326) | class FeaturesSettings(BaseModel):
class HeaderLink (line 342) | class HeaderLink(BaseModel):
class UISettings (line 350) | class UISettings(BaseModel):
class CodeSettings (line 383) | class CodeSettings(BaseModel):
class ProjectSettings (line 441) | class ProjectSettings(BaseModel):
class ChainlitConfigOverrides (line 462) | class ChainlitConfigOverrides(BaseModel):
class ChainlitConfig (line 470) | class ChainlitConfig(BaseSettings):
method load_translation (line 479) | def load_translation(self, language: str):
method with_overrides (line 523) | def with_overrides(
function init_config (line 541) | def init_config(log: bool = False):
function load_module (line 569) | def load_module(target: str, force_refresh: bool = False):
function load_settings (line 610) | def load_settings():
function reload_config (line 645) | def reload_config():
function load_config (line 668) | def load_config():
function lint_translations (line 675) | def lint_translations():
FILE: backend/chainlit/context.py
class ChainlitContextException (line 18) | class ChainlitContextException(Exception):
method __init__ (line 19) | def __init__(self, msg="Chainlit context not found", *args, **kwargs):
class ChainlitContext (line 23) | class ChainlitContext:
method current_step (line 29) | def current_step(self):
method current_run (line 34) | def current_run(self):
method __init__ (line 40) | def __init__(
function init_ws_context (line 64) | def init_ws_context(session_or_sid: Union[WebsocketSession, str]) -> Cha...
function init_http_context (line 74) | def init_http_context(
function get_context (line 105) | def get_context() -> ChainlitContext:
FILE: backend/chainlit/data/__init__.py
function get_data_layer (line 14) | def get_data_layer():
FILE: backend/chainlit/data/acl.py
function is_thread_author (line 6) | async def is_thread_author(username: str, thread_id: str):
FILE: backend/chainlit/data/base.py
class BaseDataLayer (line 20) | class BaseDataLayer(ABC):
method get_user (line 24) | async def get_user(self, identifier: str) -> Optional["PersistedUser"]:
method create_user (line 28) | async def create_user(self, user: "User") -> Optional["PersistedUser"]:
method delete_feedback (line 32) | async def delete_feedback(
method upsert_feedback (line 39) | async def upsert_feedback(
method create_element (line 47) | async def create_element(self, element: "Element"):
method get_element (line 51) | async def get_element(
method delete_element (line 58) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method create_step (line 63) | async def create_step(self, step_dict: "StepDict"):
method update_step (line 68) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 73) | async def delete_step(self, step_id: str):
method get_thread_author (line 77) | async def get_thread_author(self, thread_id: str) -> str:
method delete_thread (line 81) | async def delete_thread(self, thread_id: str):
method list_threads (line 85) | async def list_threads(
method get_thread (line 91) | async def get_thread(self, thread_id: str) -> "Optional[ThreadDict]":
method update_thread (line 95) | async def update_thread(
method build_debug_url (line 106) | async def build_debug_url(self) -> str:
method close (line 110) | async def close(self) -> None:
method get_favorite_steps (line 114) | async def get_favorite_steps(self, user_id: str) -> List["StepDict"]:
method set_step_favorite (line 117) | async def set_step_favorite(
FILE: backend/chainlit/data/chainlit_data_layer.py
class ChainlitDataLayer (line 40) | class ChainlitDataLayer(BaseDataLayer):
method __init__ (line 41) | def __init__(
method connect (line 52) | async def connect(self):
method get_current_timestamp (line 56) | async def get_current_timestamp(self) -> datetime:
method execute_query (line 59) | async def execute_query(
method get_user (line 85) | async def get_user(self, identifier: str) -> Optional[PersistedUser]:
method create_user (line 102) | async def create_user(self, user: User) -> Optional[PersistedUser]:
method delete_feedback (line 128) | async def delete_feedback(self, feedback_id: str) -> bool:
method upsert_feedback (line 135) | async def upsert_feedback(self, feedback: Feedback) -> str:
method create_element (line 155) | async def create_element(self, element: "Element"):
method get_element (line 259) | async def get_element(
method delete_element (line 296) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method create_step (line 321) | async def create_step(self, step_dict: StepDict):
method update_step (line 394) | async def update_step(self, step_dict: StepDict):
method delete_step (line 398) | async def delete_step(self, step_id: str):
method get_step (line 411) | async def get_step(self, step_id: str) -> Optional[StepDict]:
method get_thread_author (line 426) | async def get_thread_author(self, thread_id: str) -> str:
method delete_thread (line 438) | async def delete_thread(self, thread_id: str):
method list_threads (line 456) | async def list_threads(
method get_thread (line 520) | async def get_thread(self, thread_id: str) -> Optional[ThreadDict]:
method update_thread (line 576) | async def update_thread(
method get_favorite_steps (line 652) | async def get_favorite_steps(self, user_id: str) -> List[StepDict]:
method _extract_feedback_dict_from_step_row (line 664) | def _extract_feedback_dict_from_step_row(self, row: Dict) -> Optional[...
method _convert_step_row_to_dict (line 674) | def _convert_step_row_to_dict(self, row: Dict) -> StepDict:
method _convert_element_row_to_dict (line 692) | def _convert_element_row_to_dict(self, row: Dict) -> ElementDict:
method build_debug_url (line 713) | async def build_debug_url(self) -> str:
method cleanup (line 716) | async def cleanup(self):
method close (line 723) | async def close(self) -> None:
function truncate (line 729) | def truncate(text: Optional[str], max_length: int = 255) -> Optional[str]:
FILE: backend/chainlit/data/dynamodb.py
class DynamoDBDataLayer (line 43) | class DynamoDBDataLayer(BaseDataLayer):
method __init__ (line 44) | def __init__(
method _get_current_timestamp (line 64) | def _get_current_timestamp(self) -> str:
method _serialize_item (line 67) | def _serialize_item(self, item: dict[str, Any]) -> dict[str, Any]:
method _deserialize_item (line 83) | def _deserialize_item(self, item: dict[str, Any]) -> dict[str, Any]:
method _update_item (line 99) | def _update_item(self, key: Dict[str, Any], updates: Dict[str, Any]):
method context (line 122) | def context(self):
method get_user (line 125) | async def get_user(self, identifier: str) -> Optional["PersistedUser"]:
method create_user (line 148) | async def create_user(self, user: "User") -> Optional["PersistedUser"]:
method delete_feedback (line 175) | async def delete_feedback(self, feedback_id: str) -> bool:
method upsert_feedback (line 195) | async def upsert_feedback(self, feedback: Feedback) -> str:
method create_element (line 225) | async def create_element(self, element: "Element"):
method get_element (line 303) | async def get_element(
method delete_element (line 324) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method create_step (line 339) | async def create_step(self, step_dict: "StepDict"):
method update_step (line 362) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 380) | async def delete_step(self, step_id: str):
method get_thread_author (line 392) | async def get_thread_author(self, thread_id: str) -> str:
method delete_thread (line 410) | async def delete_thread(self, thread_id: str):
method list_threads (line 455) | async def list_threads(
method get_thread (line 511) | async def get_thread(self, thread_id: str) -> "Optional[ThreadDict]":
method update_thread (line 575) | async def update_thread(
method get_favorite_steps (line 615) | async def get_favorite_steps(self, user_id: str) -> List["StepDict"]:
method build_debug_url (line 678) | async def build_debug_url(self) -> str:
method close (line 681) | async def close(self) -> None:
FILE: backend/chainlit/data/literalai.py
function _show_deprecation_warning (line 43) | def _show_deprecation_warning():
class LiteralToChainlitConverter (line 55) | class LiteralToChainlitConverter:
method steptype_to_steptype (line 57) | def steptype_to_steptype(cls, step_type: Optional[StepType]) -> TrueSt...
method score_to_feedbackdict (line 61) | def score_to_feedbackdict(
method step_to_stepdict (line 75) | def step_to_stepdict(cls, step: LiteralStep) -> "StepDict":
method attachment_to_elementdict (line 117) | def attachment_to_elementdict(cls, attachment: LiteralAttachment) -> E...
method attachment_to_element (line 139) | def attachment_to_element(
method step_to_step (line 171) | def step_to_step(cls, step: LiteralStep) -> Step:
method thread_to_threaddict (line 198) | def thread_to_threaddict(cls, thread: LiteralThread) -> ThreadDict:
class LiteralDataLayer (line 220) | class LiteralDataLayer(BaseDataLayer):
method __init__ (line 221) | def __init__(self, api_key: str, server: Optional[str]):
method build_debug_url (line 227) | async def build_debug_url(self) -> str:
method get_user (line 235) | async def get_user(self, identifier: str) -> Optional[PersistedUser]:
method create_user (line 246) | async def create_user(self, user: User) -> Optional[PersistedUser]:
method delete_feedback (line 261) | async def delete_feedback(
method upsert_feedback (line 272) | async def upsert_feedback(
method safely_send_steps (line 295) | async def safely_send_steps(self, steps):
method create_element (line 304) | async def create_element(self, element: "Element"):
method get_element (line 351) | async def get_element(
method delete_element (line 360) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method create_step (line 364) | async def create_step(self, step_dict: "StepDict"):
method update_step (line 395) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 399) | async def delete_step(self, step_id: str):
method get_thread_author (line 402) | async def get_thread_author(self, thread_id: str) -> str:
method delete_thread (line 412) | async def delete_thread(self, thread_id: str):
method list_threads (line 415) | async def list_threads(
method get_thread (line 469) | async def get_thread(self, thread_id: str) -> Optional[ThreadDict]:
method update_thread (line 503) | async def update_thread(
method get_favorite_steps (line 519) | async def get_favorite_steps(self, user_id: str) -> List[StepDict]:
method close (line 523) | async def close(self):
FILE: backend/chainlit/data/sql_alchemy.py
class SQLAlchemyDataLayer (line 37) | class SQLAlchemyDataLayer(BaseDataLayer):
method __init__ (line 38) | def __init__(
method build_debug_url (line 74) | async def build_debug_url(self) -> str:
method execute_sql (line 78) | async def execute_sql(
method get_current_timestamp (line 105) | async def get_current_timestamp(self) -> str:
method clean_result (line 108) | def clean_result(self, obj):
method get_user (line 119) | async def get_user(self, identifier: str) -> Optional[PersistedUser]:
method _get_user_identifer_by_id (line 146) | async def _get_user_identifer_by_id(self, user_id: str) -> str:
method _get_user_id_by_thread (line 158) | async def _get_user_id_by_thread(self, thread_id: str) -> Optional[str]:
method create_user (line 170) | async def create_user(self, user: User) -> Optional[PersistedUser]:
method get_thread_author (line 195) | async def get_thread_author(self, thread_id: str) -> str:
method get_thread (line 207) | async def get_thread(self, thread_id: str) -> Optional[ThreadDict]:
method update_thread (line 218) | async def update_thread(
method delete_thread (line 283) | async def delete_thread(self, thread_id: str):
method list_threads (line 305) | async def list_threads(
method create_step (line 368) | async def create_step(self, step_dict: "StepDict"):
method update_step (line 400) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 406) | async def delete_step(self, step_id: str):
method get_step (line 418) | async def get_step(self, step_id: str) -> Optional["StepDict"]:
method upsert_feedback (line 495) | async def upsert_feedback(self, feedback: Feedback) -> str:
method delete_feedback (line 518) | async def delete_feedback(self, feedback_id: str) -> bool:
method get_element (line 527) | async def get_element(
method create_element (line 563) | async def create_element(self, element: "Element"):
method delete_element (line 630) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method get_all_user_threads (line 650) | async def get_all_user_threads(
method get_favorite_steps (line 856) | async def get_favorite_steps(self, user_id: str) -> List[StepDict]:
method close (line 934) | async def close(self) -> None:
FILE: backend/chainlit/data/storage_clients/azure.py
class AzureStorageClient (line 21) | class AzureStorageClient(BaseStorageClient):
method __init__ (line 31) | def __init__(
method upload_file (line 58) | async def upload_file(
method close (line 86) | async def close(self) -> None:
FILE: backend/chainlit/data/storage_clients/azure_blob.py
class AzureBlobStorageClient (line 11) | class AzureBlobStorageClient(BaseStorageClient):
method __init__ (line 12) | def __init__(self, container_name: str, storage_account: str, storage_...
method get_read_url (line 30) | async def get_read_url(self, object_key: str) -> str:
method upload_file (line 50) | async def upload_file(
method delete_file (line 87) | async def delete_file(self, object_key: str) -> bool:
method close (line 96) | async def close(self) -> None:
FILE: backend/chainlit/data/storage_clients/base.py
class BaseStorageClient (line 8) | class BaseStorageClient(ABC):
method upload_file (line 12) | async def upload_file(
method delete_file (line 23) | async def delete_file(self, object_key: str) -> bool:
method get_read_url (line 27) | async def get_read_url(self, object_key: str) -> str:
method close (line 31) | async def close(self) -> None:
FILE: backend/chainlit/data/storage_clients/gcs.py
class GCSStorageClient (line 12) | class GCSStorageClient(BaseStorageClient):
method __init__ (line 13) | def __init__(
method sync_get_read_url (line 43) | def sync_get_read_url(self, object_key: str) -> str:
method get_read_url (line 48) | async def get_read_url(self, object_key: str) -> str:
method sync_upload_file (line 51) | def sync_upload_file(
method upload_file (line 80) | async def upload_file(
method sync_delete_file (line 92) | def sync_delete_file(self, object_key: str) -> bool:
method delete_file (line 100) | async def delete_file(self, object_key: str) -> bool:
method close (line 103) | async def close(self) -> None:
FILE: backend/chainlit/data/storage_clients/s3.py
class S3StorageClient (line 11) | class S3StorageClient(BaseStorageClient):
method __init__ (line 16) | def __init__(self, bucket: str, **kwargs: Any):
method sync_get_read_url (line 24) | def sync_get_read_url(self, object_key: str) -> str:
method get_read_url (line 36) | async def get_read_url(self, object_key: str) -> str:
method sync_upload_file (line 39) | def sync_upload_file(
method upload_file (line 67) | async def upload_file(
method sync_delete_file (line 79) | def sync_delete_file(self, object_key: str) -> bool:
method delete_file (line 87) | async def delete_file(self, object_key: str) -> bool:
method close (line 90) | async def close(self) -> None:
FILE: backend/chainlit/data/utils.py
function queue_until_user_message (line 8) | def queue_until_user_message():
FILE: backend/chainlit/discord/app.py
class FeedbackView (line 29) | class FeedbackView(View):
method __init__ (line 30) | def __init__(self, step_id: str):
method thumbs_down (line 35) | async def thumbs_down(self, interaction: discord.Interaction, button: ...
method thumbs_up (line 47) | async def thumbs_up(self, interaction: discord.Interaction, button: Bu...
class DiscordEmitter (line 59) | class DiscordEmitter(BaseChainlitEmitter):
method __init__ (line 60) | def __init__(self, session: HTTPSession, channel: "MessageableChannel"):
method send_element (line 64) | async def send_element(self, element_dict: ElementDict):
method send_step (line 95) | async def send_step(self, step_dict: StepDict):
method update_step (line 120) | async def update_step(self, step_dict: StepDict):
function init_discord_context (line 133) | def init_discord_context(
function get_user (line 151) | async def get_user(discord_user: Union[discord.User, discord.Member]):
function download_discord_file (line 174) | async def download_discord_file(url: str):
function download_discord_files (line 183) | async def download_discord_files(
function clean_content (line 221) | def clean_content(message: discord.Message):
function process_discord_message (line 231) | async def process_discord_message(
function on_ready (line 297) | async def on_ready():
function on_message (line 302) | async def on_message(message: discord.Message):
FILE: backend/chainlit/element.py
class ElementDict (line 49) | class ElementDict(TypedDict, total=False):
class Element (line 70) | class Element:
method __post_init__ (line 100) | def __post_init__(self) -> None:
method to_dict (line 107) | def to_dict(self) -> ElementDict:
method from_dict (line 131) | def from_dict(cls, e_dict: ElementDict):
method infer_type_from_mime (line 189) | def infer_type_from_mime(cls, mime_type: str):
method _create (line 206) | async def _create(self, persist=True) -> bool:
method remove (line 228) | async def remove(self):
method send (line 234) | async def send(self, for_id: str, persist=True):
class Image (line 259) | class Image(Element):
class Text (line 266) | class Text(Element):
class Pdf (line 274) | class Pdf(Element):
class Pyplot (line 283) | class Pyplot(Element):
method __post_init__ (line 294) | def __post_init__(self) -> None:
class TaskStatus (line 309) | class TaskStatus(Enum):
class Task (line 317) | class Task:
method __init__ (line 322) | def __init__(
class TaskList (line 334) | class TaskList(Element):
method __post_init__ (line 341) | def __post_init__(self) -> None:
method add_task (line 345) | async def add_task(self, task: Task):
method update (line 348) | async def update(self):
method send (line 351) | async def send(self):
method preprocess_content (line 355) | async def preprocess_content(self):
class Audio (line 374) | class Audio(Element):
class Video (line 380) | class Video(Element):
class File (line 390) | class File(Element):
class Plotly (line 395) | class Plotly(Element):
method __post_init__ (line 406) | def __post_init__(self) -> None:
class Dataframe (line 422) | class Dataframe(Element):
method __post_init__ (line 429) | def __post_init__(self) -> None:
class CustomElement (line 441) | class CustomElement(Element):
method __post_init__ (line 448) | def __post_init__(self) -> None:
method update (line 453) | async def update(self):
FILE: backend/chainlit/emitter.py
class BaseChainlitEmitter (line 33) | class BaseChainlitEmitter:
method __init__ (line 42) | def __init__(self, session: BaseSession) -> None:
method emit (line 46) | async def emit(self, event: str, data: Any):
method emit_call (line 50) | async def emit_call(self):
method resume_thread (line 54) | async def resume_thread(self, thread_dict: ThreadDict):
method send_resume_thread_error (line 58) | async def send_resume_thread_error(self, error: str):
method send_element (line 62) | async def send_element(self, element_dict: ElementDict):
method update_audio_connection (line 66) | async def update_audio_connection(self, state: Literal["on", "off"]):
method send_audio_chunk (line 70) | async def send_audio_chunk(self, chunk: OutputAudioChunk):
method send_audio_interrupt (line 74) | async def send_audio_interrupt(self):
method send_step (line 78) | async def send_step(self, step_dict: StepDict):
method update_step (line 82) | async def update_step(self, step_dict: StepDict):
method delete_step (line 86) | async def delete_step(self, step_dict: StepDict):
method send_timeout (line 90) | def send_timeout(self, event: Literal["ask_timeout", "call_fn_timeout"]):
method clear (line 94) | def clear(self, event: Literal["clear_ask", "clear_call_fn"]):
method init_thread (line 97) | async def init_thread(self, interaction: str):
method process_message (line 100) | async def process_message(self, payload: MessagePayload) -> Message:
method send_ask_user (line 104) | async def send_ask_user(
method send_call_fn (line 112) | async def send_call_fn(
method update_token_count (line 118) | async def update_token_count(self, count: int):
method task_start (line 122) | async def task_start(self):
method task_end (line 126) | async def task_end(self):
method stream_start (line 130) | async def stream_start(self, step_dict: StepDict):
method send_token (line 134) | async def send_token(self, id: str, token: str, is_sequence=False, is_...
method set_chat_settings (line 138) | async def set_chat_settings(self, settings: dict):
method set_commands (line 142) | async def set_commands(self, commands: List[CommandDict]):
method set_modes (line 146) | async def set_modes(self, modes: List[Mode]):
method send_window_message (line 150) | async def send_window_message(self, data: Any):
method send_toast (line 154) | def send_toast(self, message: str, type: Optional[ToastType] = "info"):
method set_favorites (line 158) | async def set_favorites(self, steps: List[StepDict]):
class ChainlitEmitter (line 163) | class ChainlitEmitter(BaseChainlitEmitter):
method __init__ (line 171) | def __init__(self, session: WebsocketSession) -> None:
method _get_session_property (line 175) | def _get_session_property(self, property_name: str, raise_error=True):
method emit (line 185) | def emit(self):
method emit_call (line 191) | def emit_call(self):
method resume_thread (line 195) | def resume_thread(self, thread_dict: ThreadDict):
method send_resume_thread_error (line 199) | def send_resume_thread_error(self, error: str):
method update_audio_connection (line 203) | async def update_audio_connection(self, state: Literal["on", "off"]):
method send_audio_chunk (line 207) | async def send_audio_chunk(self, chunk: OutputAudioChunk):
method send_audio_interrupt (line 211) | async def send_audio_interrupt(self):
method send_element (line 215) | async def send_element(self, element_dict: ElementDict):
method send_step (line 219) | def send_step(self, step_dict: StepDict):
method update_step (line 223) | def update_step(self, step_dict: StepDict):
method delete_step (line 227) | def delete_step(self, step_dict: StepDict):
method send_timeout (line 231) | def send_timeout(self, event: Literal["ask_timeout", "call_fn_timeout"]):
method clear (line 234) | def clear(self, event: Literal["clear_ask", "clear_call_fn"]):
method flush_thread_queues (line 237) | async def flush_thread_queues(self, interaction: str):
method init_thread (line 258) | async def init_thread(self, interaction: str):
method process_message (line 268) | async def process_message(self, payload: MessagePayload):
method send_ask_user (line 317) | async def send_ask_user(
method send_call_fn (line 393) | async def send_call_fn(
method update_token_count (line 411) | def update_token_count(self, count: int):
method task_start (line 416) | def task_start(self):
method task_end (line 422) | def task_end(self):
method stream_start (line 426) | def stream_start(self, step_dict: StepDict):
method send_token (line 433) | def send_token(self, id: str, token: str, is_sequence=False, is_input=...
method set_chat_settings (line 440) | def set_chat_settings(self, settings: Dict[str, Any]):
method set_commands (line 443) | def set_commands(self, commands: List[CommandDict]):
method set_modes (line 450) | def set_modes(self, modes: List[Mode]):
method set_favorites (line 457) | def set_favorites(self, steps: List[StepDict]):
method send_window_message (line 464) | def send_window_message(self, data: Any):
method send_toast (line 468) | def send_toast(self, message: str, type: Optional[ToastType] = "info"):
FILE: backend/chainlit/input_widget.py
class InputWidget (line 12) | class InputWidget:
method __post_init__ (line 20) | def __post_init__(
method to_dict (line 27) | def to_dict(self) -> Dict[str, Any]:
class Switch (line 32) | class Switch(InputWidget):
method to_dict (line 38) | def to_dict(self) -> Dict[str, Any]:
class Slider (line 51) | class Slider(InputWidget):
method to_dict (line 60) | def to_dict(self) -> Dict[str, Any]:
class Select (line 76) | class Select(InputWidget):
method __post_init__ (line 86) | def __post_init__(
method to_dict (line 114) | def to_dict(self) -> Dict[str, Any]:
class TextInput (line 130) | class TextInput(InputWidget):
method to_dict (line 138) | def to_dict(self) -> Dict[str, Any]:
class NumberInput (line 153) | class NumberInput(InputWidget):
method to_dict (line 160) | def to_dict(self) -> Dict[str, Any]:
class Tags (line 174) | class Tags(InputWidget):
method to_dict (line 181) | def to_dict(self) -> Dict[str, Any]:
class MultiSelect (line 194) | class MultiSelect(InputWidget):
method __post_init__ (line 202) | def __post_init__(
method to_dict (line 218) | def to_dict(self) -> Dict[str, Any]:
class Checkbox (line 234) | class Checkbox(InputWidget):
method to_dict (line 240) | def to_dict(self) -> Dict[str, Any]:
class RadioGroup (line 253) | class RadioGroup(InputWidget):
method __post_init__ (line 263) | def __post_init__(
method to_dict (line 291) | def to_dict(self) -> Dict[str, Any]:
class Tab (line 307) | class Tab:
method to_dict (line 312) | def to_dict(self) -> dict[str, Any]:
class DatePicker (line 321) | class DatePicker(InputWidget):
method __post_init__ (line 337) | def __post_init__(self) -> None:
method _validate_range (line 378) | def _validate_range(
method _validate_iso_format (line 389) | def _validate_iso_format(
method _format_date (line 401) | def _format_date(date_value: str | date | None) -> str | None:
method to_dict (line 406) | def to_dict(self) -> dict[str, Any]:
FILE: backend/chainlit/langchain/callbacks.py
class FinalStreamHelper (line 22) | class FinalStreamHelper:
method __init__ (line 34) | def __init__(
method _check_if_answer_reached (line 63) | def _check_if_answer_reached(self) -> bool:
method _compare_last_tokens (line 69) | def _compare_last_tokens(self, last_tokens: List[str]):
method _append_to_last_tokens (line 86) | def _append_to_last_tokens(self, token: str) -> None:
class ChatGenerationStart (line 94) | class ChatGenerationStart(TypedDict):
class CompletionGenerationStart (line 101) | class CompletionGenerationStart(TypedDict):
class GenerationHelper (line 108) | class GenerationHelper:
method __init__ (line 113) | def __init__(self) -> None:
method ensure_values_serializable (line 118) | def ensure_values_serializable(self, data):
method _convert_message_role (line 144) | def _convert_message_role(self, role: str):
method _convert_message_dict (line 156) | def _convert_message_dict(
method _convert_message (line 201) | def _convert_message(
method _build_llm_settings (line 256) | def _build_llm_settings(
function process_content (line 298) | def process_content(content: Any) -> Tuple[Dict | str, Optional[str]]:
class LangchainTracer (line 317) | class LangchainTracer(AsyncBaseTracer, GenerationHelper, FinalStreamHelp...
method __init__ (line 322) | def __init__(
method on_chat_model_start (line 364) | async def on_chat_model_start(
method on_llm_start (line 395) | async def on_llm_start(
method on_llm_new_token (line 425) | async def on_llm_new_token(
method _persist_run (line 475) | async def _persist_run(self, run: Run) -> None:
method _get_run_parent_id (line 478) | def _get_run_parent_id(self, run: Run):
method _get_non_ignored_parent_id (line 483) | def _get_non_ignored_parent_id(self, current_parent_id: Optional[str] ...
method _should_ignore_run (line 499) | def _should_ignore_run(self, run: Run):
method _start_trace (line 526) | async def _start_trace(self, run: Run) -> None:
method _on_run_update (line 571) | async def _on_run_update(self, run: Run) -> None:
method _on_error (line 666) | async def _on_error(self, error: BaseException, *, run_id: UUID, **kwa...
FILE: backend/chainlit/langflow/__init__.py
function load_flow (line 13) | async def load_flow(schema: Union[Dict, str], tweaks: Optional[Dict] = N...
FILE: backend/chainlit/llama_index/callbacks.py
class LlamaIndexCallbackHandler (line 23) | class LlamaIndexCallbackHandler(TokenCountingHandler):
method __init__ (line 28) | def __init__(
method _get_parent_id (line 41) | def _get_parent_id(self, event_parent_id: Optional[str] = None) -> Opt...
method on_event_start (line 49) | def on_event_start(
method on_event_end (line 90) | def on_event_end(
method _noop (line 202) | def _noop(self, *args, **kwargs):
FILE: backend/chainlit/markdown.py
function init_markdown (line 27) | def init_markdown(root: str):
function get_markdown_str (line 37) | def get_markdown_str(root: str, language: str) -> Optional[str]:
FILE: backend/chainlit/mcp.py
class StdioMcpConnection (line 9) | class StdioMcpConnection(BaseModel):
class SseMcpConnection (line 16) | class SseMcpConnection(BaseModel):
class HttpMcpConnection (line 23) | class HttpMcpConnection(BaseModel):
function validate_mcp_command (line 33) | def validate_mcp_command(command_string: str):
FILE: backend/chainlit/message.py
class MessageBase (line 31) | class MessageBase(ABC):
method __post_init__ (line 50) | def __post_init__(self) -> None:
method from_dict (line 62) | def from_dict(self, _dict: StepDict):
method to_dict (line 77) | def to_dict(self) -> StepDict:
method update (line 100) | async def update(
method remove (line 126) | async def remove(self):
method _create (line 145) | async def _create(self):
method send (line 159) | async def send(self):
method stream_token (line 177) | async def stream_token(self, token: str, is_sequence=False):
class Message (line 202) | class Message(MessageBase):
method __init__ (line 214) | def __init__(
method send (line 270) | async def send(self):
method update (line 286) | async def update(self):
method remove_actions (line 306) | async def remove_actions(self):
class ErrorMessage (line 311) | class ErrorMessage(MessageBase):
method __init__ (line 321) | def __init__(
method send (line 335) | async def send(self):
class AskMessageBase (line 343) | class AskMessageBase(MessageBase):
method remove (line 344) | async def remove(self):
class AskUserMessage (line 350) | class AskUserMessage(AskMessageBase):
method __init__ (line 363) | def __init__(
method send (line 379) | async def send(self) -> Union[StepDict, None]:
class AskFileMessage (line 408) | class AskFileMessage(AskMessageBase):
method __init__ (line 424) | def __init__(
method send (line 446) | async def send(self) -> Union[List[AskFileResponse], None]:
class AskActionMessage (line 494) | class AskActionMessage(AskMessageBase):
method __init__ (line 500) | def __init__(
method send (line 516) | async def send(self) -> Union[AskActionResponse, None]:
class AskElementMessage (line 565) | class AskElementMessage(AskMessageBase):
method __init__ (line 568) | def __init__(
method send (line 584) | async def send(self) -> Union[AskElementResponse, None]:
FILE: backend/chainlit/mistralai/__init__.py
function instrument_mistralai (line 11) | def instrument_mistralai():
FILE: backend/chainlit/mode.py
class ModeOption (line 15) | class ModeOption(DataClassJsonMixin):
class Mode (line 34) | class Mode(DataClassJsonMixin):
method get_default_option (line 50) | def get_default_option(self) -> Optional[ModeOption]:
method get_option_by_id (line 57) | def get_option_by_id(self, option_id: str) -> Optional[ModeOption]:
FILE: backend/chainlit/oauth_providers.py
class OAuthProvider (line 15) | class OAuthProvider:
method is_configured (line 24) | def is_configured(self):
method get_raw_token_response (line 27) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 30) | async def get_token(self, code: str, url: str) -> str:
method get_user_info (line 33) | async def get_user_info(self, token: str) -> Tuple[Dict[str, str], User]:
method get_env_prefix (line 36) | def get_env_prefix(self) -> str:
method get_prompt (line 41) | def get_prompt(self) -> Optional[str]:
class GithubOAuthProvider (line 52) | class GithubOAuthProvider(OAuthProvider):
method __init__ (line 65) | def __init__(self):
method get_raw_token_response (line 75) | async def get_raw_token_response(self, code: str, url: str) -> Dict[st...
method get_token (line 89) | async def get_token(self, code: str, url: str):
method get_user_info (line 96) | async def get_user_info(self, token: str):
class GoogleOAuthProvider (line 120) | class GoogleOAuthProvider(OAuthProvider):
method __init__ (line 125) | def __init__(self):
method get_raw_token_response (line 137) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 153) | async def get_token(self, code: str, url: str):
method get_user_info (line 160) | async def get_user_info(self, token: str):
class AzureADOAuthProvider (line 175) | class AzureADOAuthProvider(OAuthProvider):
method __init__ (line 193) | def __init__(self):
method get_raw_token_response (line 206) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 222) | async def get_token(self, code: str, url: str):
method get_user_info (line 232) | async def get_user_info(self, token: str):
class AzureADHybridOAuthProvider (line 267) | class AzureADHybridOAuthProvider(OAuthProvider):
method __init__ (line 285) | def __init__(self):
method get_raw_token_response (line 300) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 316) | async def get_token(self, code: str, url: str):
method get_user_info (line 326) | async def get_user_info(self, token: str):
class OktaOAuthProvider (line 361) | class OktaOAuthProvider(OAuthProvider):
method __init__ (line 371) | def __init__(self):
method get_authorization_server_path (line 389) | def get_authorization_server_path(self):
method get_raw_token_response (line 396) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 412) | async def get_token(self, code: str, url: str):
method get_user_info (line 419) | async def get_user_info(self, token: str):
class Auth0OAuthProvider (line 435) | class Auth0OAuthProvider(OAuthProvider):
method __init__ (line 439) | def __init__(self):
method get_raw_token_response (line 461) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 477) | async def get_token(self, code: str, url: str):
method get_user_info (line 484) | async def get_user_info(self, token: str):
class DescopeOAuthProvider (line 502) | class DescopeOAuthProvider(OAuthProvider):
method __init__ (line 510) | def __init__(self):
method get_raw_token_response (line 522) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 538) | async def get_token(self, code: str, url: str):
method get_user_info (line 545) | async def get_user_info(self, token: str):
class AWSCognitoOAuthProvider (line 560) | class AWSCognitoOAuthProvider(OAuthProvider):
method __init__ (line 570) | def __init__(self):
method get_raw_token_response (line 583) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 599) | async def get_token(self, code: str, url: str):
method get_user_info (line 606) | async def get_user_info(self, token: str):
class GitlabOAuthProvider (line 630) | class GitlabOAuthProvider(OAuthProvider):
method __init__ (line 638) | def __init__(self):
method get_raw_token_response (line 654) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 670) | async def get_token(self, code: str, url: str):
method get_user_info (line 677) | async def get_user_info(self, token: str):
class KeycloakOAuthProvider (line 695) | class KeycloakOAuthProvider(OAuthProvider):
method __init__ (line 704) | def __init__(self):
method get_raw_token_response (line 722) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 738) | async def get_token(self, code: str, url: str):
method get_user_info (line 747) | async def get_user_info(self, token: str):
class GenericOAuthProvider (line 762) | class GenericOAuthProvider(OAuthProvider):
method __init__ (line 773) | def __init__(self):
method get_raw_token_response (line 790) | async def get_raw_token_response(self, code: str, url: str) -> dict:
method get_token (line 803) | async def get_token(self, code: str, url: str) -> str:
method get_user_info (line 810) | async def get_user_info(self, token: str):
function get_oauth_provider (line 842) | def get_oauth_provider(provider: str) -> Optional[OAuthProvider]:
function get_configured_oauth_providers (line 849) | def get_configured_oauth_providers():
FILE: backend/chainlit/openai/__init__.py
function instrument_openai (line 11) | def instrument_openai():
FILE: backend/chainlit/sample/hello.py
function main (line 7) | async def main():
FILE: backend/chainlit/sample/starters_demo.py
function starter_categories (line 7) | async def starter_categories(user: Optional[cl.User] = None):
function on_message (line 58) | async def on_message(msg: cl.Message):
FILE: backend/chainlit/secret.py
function random_secret (line 8) | def random_secret(length: int = 64):
FILE: backend/chainlit/semantic_kernel/__init__.py
class SemanticKernelFilter (line 14) | class SemanticKernelFilter(BaseModel):
method __init__ (line 48) | def __init__(
method add_to_kernel (line 61) | def add_to_kernel(self, kernel: "Kernel") -> None:
method parse_arguments (line 69) | def parse_arguments(self, arguments: "KernelArguments") -> dict[str, A...
method _function_invocation_filter (line 90) | async def _function_invocation_filter(
FILE: backend/chainlit/server.py
function lifespan (line 90) | async def lifespan(app: FastAPI):
function get_build_dir (line 197) | def get_build_dir(local_target: str, packaged_target: str) -> str:
class SafariWebSocketsCompatibleGZipMiddleware (line 246) | class SafariWebSocketsCompatibleGZipMiddleware(GZipMiddleware):
method __call__ (line 247) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
function serve_public_file (line 265) | async def serve_public_file(
function serve_asset_file (line 283) | async def serve_asset_file(
function serve_copilot_file (line 301) | async def serve_copilot_file(
function slack_endpoint (line 330) | async def slack_endpoint(req: Request):
function teams_endpoint (line 344) | async def teams_endpoint(req: Request):
function replace_between_tags (line 357) | def replace_between_tags(
function get_html_template (line 366) | def get_html_template(root_path):
function get_user_facing_url (line 438) | def get_user_facing_url(url: URL):
function auth (line 462) | async def auth(request: Request):
function _get_response_dict (line 466) | def _get_response_dict(access_token: str) -> dict:
function _get_auth_response (line 472) | def _get_auth_response(access_token: str, redirect_to_callback: bool) ->...
function _get_oauth_redirect_error (line 493) | def _get_oauth_redirect_error(request: Request, error: str) -> Response:
function _authenticate_user (line 504) | async def _authenticate_user(
function login (line 534) | async def login(
function logout (line 555) | async def logout(request: Request, response: Response):
function jwt_auth (line 566) | async def jwt_auth(request: Request):
function header_auth (line 595) | async def header_auth(request: Request):
function oauth_login (line 609) | async def oauth_login(provider_id: str, request: Request):
function oauth_callback (line 644) | async def oauth_callback(
function oauth_azure_hf_callback (line 703) | async def oauth_azure_hf_callback(
function get_user (line 755) | async def get_user(current_user: UserParam) -> GenericUser:
function set_session_cookie (line 765) | async def set_session_cookie(request: Request, response: Response):
function project_translations (line 784) | async def project_translations(
function project_settings (line 805) | async def project_settings(
function update_feedback (line 882) | async def update_feedback(
function delete_feedback (line 916) | async def delete_feedback(
function get_user_threads (line 935) | async def get_user_threads(
function get_thread (line 963) | async def get_thread(
function get_shared_thread (line 984) | async def get_shared_thread(
function get_thread_element (line 1039) | async def get_thread_element(
function update_thread_element (line 1061) | async def update_thread_element(
function delete_thread_element (line 1097) | async def delete_thread_element(
function _sanitize_custom_element (line 1132) | def _sanitize_custom_element(element_dict: "ElementDict") -> "CustomElem...
function rename_thread (line 1146) | async def rename_thread(
function share_thread (line 1171) | async def share_thread(
function delete_thread (line 1223) | async def delete_thread(
function call_action (line 1247) | async def call_action(
function connect_mcp (line 1290) | async def connect_mcp(
function disconnect_mcp (line 1458) | async def disconnect_mcp(
function upload_file (line 1500) | async def upload_file(
function validate_file_upload (line 1554) | def validate_file_upload(file: UploadFile, spec: Optional[AskFileSpec] =...
function validate_file_mime_type (line 1575) | def validate_file_mime_type(file: UploadFile, spec: Optional[AskFileSpec]):
function validate_file_size (line 1613) | def validate_file_size(file: UploadFile, spec: Optional[AskFileSpec]):
function get_file (line 1636) | async def get_file(
function get_favicon (line 1667) | async def get_favicon():
function get_logo (line 1683) | async def get_logo(theme: Optional[Theme] = Query(Theme.light)):
function get_avatar (line 1713) | async def get_avatar(avatar_id: str):
function status_check (line 1739) | def status_check():
function health_check (line 1745) | def health_check():
function serve (line 1751) | async def serve(request: Request):
FILE: backend/chainlit/session.py
class JSONEncoderIgnoreNonSerializable (line 25) | class JSONEncoderIgnoreNonSerializable(json.JSONEncoder):
method default (line 26) | def default(self, o):
function clean_metadata (line 33) | def clean_metadata(metadata: Dict, max_size: int = 1048576):
class BaseSession (line 48) | class BaseSession:
method __init__ (line 55) | def __init__(
method files_dir (line 92) | def files_dir(self):
method persist_file (line 97) | async def persist_file(
method to_persistable (line 147) | def to_persistable(self) -> Dict:
class HTTPSession (line 166) | class HTTPSession(BaseSession):
method __init__ (line 169) | def __init__(
method delete (line 194) | async def delete(self):
class WebsocketSession (line 203) | class WebsocketSession(BaseSession):
method __init__ (line 219) | def __init__(
method get_config (line 277) | def get_config(self) -> "ChainlitConfig":
method restore (line 310) | def restore(self, new_socket_id: str):
method delete (line 317) | async def delete(self):
method flush_method_queue (line 330) | async def flush_method_queue(self):
method get (line 340) | def get(cls, socket_id: str):
method get_by_id (line 345) | def get_by_id(cls, session_id: str):
method require (line 350) | def require(cls, socket_id: str):
FILE: backend/chainlit/sidebar.py
class ElementSidebar (line 8) | class ElementSidebar:
method set_title (line 13) | async def set_title(title: str):
method set_elements (line 28) | async def set_elements(elements: List[ElementBased], key: Optional[str...
FILE: backend/chainlit/slack/app.py
class SlackEmitter (line 25) | class SlackEmitter(BaseChainlitEmitter):
method __init__ (line 26) | def __init__(
method send_element (line 40) | async def send_element(self, element_dict: ElementDict):
method send_step (line 65) | async def send_step(self, step_dict: StepDict):
method update_step (line 114) | async def update_step(self, step_dict: StepDict):
function start_socket_mode (line 129) | async def start_socket_mode():
function init_slack_context (line 139) | def init_slack_context(
function get_bot_user_id (line 175) | async def get_bot_user_id() -> Optional[str]:
function clean_content (line 192) | def clean_content(message: str):
function get_user (line 197) | async def get_user(slack_user_id: str):
function fetch_message_history (line 220) | async def fetch_message_history(
function download_slack_file (line 238) | async def download_slack_file(url, token):
function download_slack_files (line 248) | async def download_slack_files(session: HTTPSession, files, token):
function add_reaction_if_enabled (line 284) | async def add_reaction_if_enabled(event, emoji: str = "eyes"):
function process_slack_message (line 294) | async def process_slack_message(
function handle_app_home_opened (line 366) | async def handle_app_home_opened(event, say):
function handle_app_mentions (line 371) | async def handle_app_mentions(event, say):
function handle_message (line 379) | async def handle_message(message, say):
function handle_reaction_added (line 393) | async def handle_reaction_added(event):
function thumb_down (line 471) | async def thumb_down(ack, context, body):
function thumb_up (line 499) | async def thumb_up(ack, context, body):
FILE: backend/chainlit/socket.py
class WebSocketSessionAuth (line 33) | class WebSocketSessionAuth(TypedDict):
function restore_existing_session (line 41) | def restore_existing_session(sid, session_id, emit_fn, emit_call_fn, env...
function persist_user_session (line 52) | async def persist_user_session(thread_id: str, metadata: Dict):
function resume_thread (line 57) | async def resume_thread(session: WebsocketSession):
function load_user_env (line 81) | def load_user_env(user_env):
function _get_token_from_cookie (line 97) | def _get_token_from_cookie(environ: WSGIEnvironment) -> Optional[str]:
function _get_token (line 105) | def _get_token(environ: WSGIEnvironment) -> Optional[str]:
function _authenticate_connection (line 110) | async def _authenticate_connection(
function connect (line 122) | async def connect(sid: str, environ: WSGIEnvironment, auth: WebSocketSes...
function connection_successful (line 183) | async def connection_successful(sid):
function clean_session (line 221) | async def clean_session(sid):
function disconnect (line 228) | async def disconnect(sid):
function stop (line 262) | async def stop(sid):
function process_message (line 274) | async def process_message(session: WebsocketSession, payload: MessagePay...
function edit_message (line 296) | async def edit_message(sid, payload: MessagePayload):
function message_favorite (line 326) | async def message_favorite(sid, payload: MessagePayload):
function fetch_favorites (line 371) | async def fetch_favorites(sid):
function message (line 381) | async def message(sid, payload: MessagePayload):
function window_message (line 390) | async def window_message(sid, data):
function audio_start (line 403) | async def audio_start(sid):
function audio_chunk (line 417) | async def audio_chunk(sid, payload: InputAudioChunkPayload):
function audio_end (line 434) | async def audio_end(sid):
function change_settings (line 463) | async def change_settings(sid, settings: Dict[str, Any]):
function edit_settings (line 475) | async def edit_settings(sid, settings: Dict[str, Any]):
FILE: backend/chainlit/step.py
function check_add_step_in_cot (line 22) | def check_add_step_in_cot(step: "Step"):
function stub_step (line 33) | def stub_step(step: "Step") -> "StepDict":
class StepDict (line 45) | class StepDict(TypedDict, total=False):
function flatten_args_kwargs (line 71) | def flatten_args_kwargs(func, args, kwargs):
function step (line 78) | def step(
class Step (line 169) | class Step:
method __init__ (line 195) | def __init__(
method _clean_content (line 237) | def _clean_content(self, content):
method _process_content (line 255) | def _process_content(self, content, set_language=False):
method input (line 282) | def input(self):
method input (line 286) | def input(self, content: Union[Dict, str]):
method output (line 290) | def output(self):
method output (line 294) | def output(self, content: Union[Dict, str]):
method to_dict (line 297) | def to_dict(self) -> StepDict:
method update (line 321) | async def update(self):
method remove (line 349) | async def remove(self):
method send (line 368) | async def send(self):
method stream_token (line 401) | async def stream_token(self, token: str, is_sequence=False, is_input=F...
method __call__ (line 436) | def __call__(self, func):
method __aenter__ (line 447) | async def __aenter__(self):
method __aexit__ (line 459) | async def __aexit__(self, exc_type, exc_val, exc_tb):
method __enter__ (line 473) | def __enter__(self):
method __exit__ (line 487) | def __exit__(self, exc_type, exc_val, exc_tb):
FILE: backend/chainlit/sync.py
function run_sync (line 24) | def run_sync(co: Coroutine[Any, Any, T_Retval]) -> T_Retval:
FILE: backend/chainlit/teams/app.py
class TeamsEmitter (line 44) | class TeamsEmitter(BaseChainlitEmitter):
method __init__ (line 45) | def __init__(self, session: HTTPSession, turn_context: TurnContext):
method send_element (line 49) | async def send_element(self, element_dict: ElementDict):
method send_step (line 83) | async def send_step(self, step_dict: StepDict):
method update_step (line 122) | async def update_step(self, step_dict: StepDict):
function init_teams_context (line 136) | def init_teams_context(
function get_user (line 152) | async def get_user(teams_user: ChannelAccount):
function download_teams_file (line 175) | async def download_teams_file(url: str):
function download_teams_files (line 184) | async def download_teams_files(
function clean_content (line 229) | def clean_content(activity: Activity):
function process_teams_message (line 233) | async def process_teams_message(
function handle_message (line 301) | async def handle_message(turn_context: TurnContext):
function on_turn (line 337) | async def on_turn(turn_context: TurnContext):
class TeamsBot (line 342) | class TeamsBot:
method on_turn (line 343) | async def on_turn(self, turn_context: TurnContext):
FILE: backend/chainlit/translations.py
function compare_json_structures (line 6) | def compare_json_structures(truth, to_compare, path=""):
function lint_translation_json (line 51) | def lint_translation_json(file, truth, to_compare):
FILE: backend/chainlit/types.py
class ThreadDict (line 42) | class ThreadDict(TypedDict):
class Pagination (line 54) | class Pagination(BaseModel):
class ThreadFilter (line 59) | class ThreadFilter(BaseModel):
class PageInfo (line 66) | class PageInfo:
method to_dict (line 71) | def to_dict(self):
method from_dict (line 79) | def from_dict(cls, page_info_dict: Dict) -> "PageInfo":
class HasFromDict (line 91) | class HasFromDict(Protocol[T]):
method from_dict (line 93) | def from_dict(cls, obj_dict: Any) -> T:
class PaginatedResponse (line 98) | class PaginatedResponse(Generic[T]):
method to_dict (line 102) | def to_dict(self):
method from_dict (line 112) | def from_dict(
class FileSpec (line 123) | class FileSpec(DataClassJsonMixin):
class ActionSpec (line 130) | class ActionSpec(DataClassJsonMixin):
class AskSpec (line 135) | class AskSpec(DataClassJsonMixin):
class AskFileSpec (line 144) | class AskFileSpec(FileSpec, AskSpec, DataClassJsonMixin):
class AskActionSpec (line 149) | class AskActionSpec(ActionSpec, AskSpec, DataClassJsonMixin):
class AskElementSpec (line 154) | class AskElementSpec(AskSpec, DataClassJsonMixin):
class FileReference (line 160) | class FileReference(TypedDict):
class FileDict (line 164) | class FileDict(TypedDict):
class MessagePayload (line 172) | class MessagePayload(TypedDict):
class InputAudioChunkPayload (line 177) | class InputAudioChunkPayload(TypedDict):
class InputAudioChunk (line 185) | class InputAudioChunk:
class OutputAudioChunk (line 192) | class OutputAudioChunk(TypedDict):
class AskFileResponse (line 199) | class AskFileResponse:
class AskActionResponse (line 207) | class AskActionResponse(TypedDict):
class AskElementResponse (line 216) | class AskElementResponse(TypedDict, total=False):
class UpdateThreadRequest (line 220) | class UpdateThreadRequest(BaseModel):
class ShareThreadRequest (line 225) | class ShareThreadRequest(BaseModel):
class DeleteThreadRequest (line 230) | class DeleteThreadRequest(BaseModel):
class DeleteFeedbackRequest (line 234) | class DeleteFeedbackRequest(BaseModel):
class GetThreadsRequest (line 238) | class GetThreadsRequest(BaseModel):
class CallActionRequest (line 243) | class CallActionRequest(BaseModel):
class ConnectStdioMCPRequest (line 248) | class ConnectStdioMCPRequest(BaseModel):
class ConnectSseMCPRequest (line 255) | class ConnectSseMCPRequest(BaseModel):
class ConnectStreamableHttpMCPRequest (line 264) | class ConnectStreamableHttpMCPRequest(BaseModel):
class DisconnectMCPRequest (line 278) | class DisconnectMCPRequest(BaseModel):
class ElementRequest (line 283) | class ElementRequest(BaseModel):
class Theme (line 288) | class Theme(str, Enum):
class Starter (line 294) | class Starter(DataClassJsonMixin):
class StarterCategory (line 304) | class StarterCategory(DataClassJsonMixin):
class ChatProfile (line 313) | class ChatProfile(DataClassJsonMixin):
class CommandDict (line 328) | class CommandDict(TypedDict):
class FeedbackDict (line 343) | class FeedbackDict(TypedDict):
class Feedback (line 351) | class Feedback:
class UpdateFeedbackRequest (line 359) | class UpdateFeedbackRequest(BaseModel):
FILE: backend/chainlit/user.py
class UserDict (line 20) | class UserDict(TypedDict):
class User (line 29) | class User(DataClassJsonMixin):
class PersistedUserFields (line 36) | class PersistedUserFields:
class PersistedUser (line 42) | class PersistedUser(User, PersistedUserFields):
FILE: backend/chainlit/user_session.py
class UserSession (line 10) | class UserSession:
method get (line 16) | def get(self, key, default=None):
method set (line 36) | def set(self, key, value):
method create_accessor (line 46) | def create_accessor(
class SessionAccessor (line 92) | class SessionAccessor(Generic[T]):
method __init__ (line 118) | def __init__(
method get (line 125) | def get(self) -> T:
method set (line 131) | def set(self, value: T) -> None:
method reset (line 137) | def reset(self) -> None:
method apply (line 143) | def apply(self) -> T:
FILE: backend/chainlit/utils.py
function utc_now (line 20) | def utc_now():
function timestamp_utc (line 25) | def timestamp_utc(timestamp: float):
function wrap_user_function (line 30) | def wrap_user_function(user_function: Callable, with_task=False) -> Call...
function make_module_getattr (line 77) | def make_module_getattr(registry):
function check_module_version (line 92) | def check_module_version(name, required_version):
function check_file (line 111) | def check_file(target: str):
function mount_chainlit (line 132) | def mount_chainlit(app: FastAPI, target: str, path="/chainlit"):
FILE: backend/tests/auth/test_cookie.py
function test_app (line 18) | def test_app():
function client (line 42) | def client(test_app):
function test_short_token (line 46) | def test_short_token(client):
function test_set_and_read_4kb_token (line 65) | def test_set_and_read_4kb_token(client):
function test_overwrite_shorter_token_chunked (line 88) | def test_overwrite_shorter_token_chunked(client):
function test_overwrite_shorter_token_unchunked (line 112) | def test_overwrite_shorter_token_unchunked(client):
function test_state_cookie_lifetime_default (line 136) | def test_state_cookie_lifetime_default(monkeypatch):
function test_state_cookie_lifetime_custom (line 143) | def test_state_cookie_lifetime_custom(monkeypatch):
function test_clear_auth_cookie (line 150) | def test_clear_auth_cookie(client):
FILE: backend/tests/conftest.py
function persisted_test_user (line 20) | def persisted_test_user():
function mock_session_factory (line 29) | def mock_session_factory(persisted_test_user: PersistedUser) -> Callable...
function mock_session (line 51) | def mock_session(mock_session_factory) -> Mock:
function create_chainlit_context (line 56) | async def create_chainlit_context(mock_session):
function mock_chainlit_context (line 80) | async def mock_chainlit_context(persisted_test_user, mock_session):
function user_session (line 86) | def user_session():
function mock_websocket_session (line 91) | def mock_websocket_session():
function mock_http_session (line 99) | def mock_http_session():
function mock_data_layer (line 104) | def mock_data_layer(monkeypatch: pytest.MonkeyPatch) -> AsyncMock:
function mock_get_data_layer (line 111) | def mock_get_data_layer(mock_data_layer: AsyncMock, test_config: config....
function test_config (line 120) | def test_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
FILE: backend/tests/data/conftest.py
function mock_storage_client (line 10) | def mock_storage_client():
function test_user (line 20) | def test_user() -> User:
FILE: backend/tests/data/storage_clients/test_gcs.py
function mock_gcs_client (line 10) | def mock_gcs_client():
class TestGCSStorageClient (line 40) | class TestGCSStorageClient:
method test_init (line 41) | def test_init(self, mock_gcs_client):
method test_sync_get_read_url (line 72) | def test_sync_get_read_url(self, mock_gcs_client):
method test_get_read_url (line 102) | async def test_get_read_url(self, mock_gcs_client):
method test_sync_upload_file (line 131) | def test_sync_upload_file(self, mock_gcs_client):
method test_sync_upload_file_string_data (line 162) | def test_sync_upload_file_string_data(self, mock_gcs_client):
method test_sync_upload_file_no_overwrite (line 191) | def test_sync_upload_file_no_overwrite(self, mock_gcs_client):
method test_sync_upload_file_error (line 220) | def test_sync_upload_file_error(self, mock_gcs_client):
method test_upload_file (line 246) | async def test_upload_file(self, mock_gcs_client):
method test_sync_delete_file (line 275) | def test_sync_delete_file(self, mock_gcs_client):
method test_sync_delete_file_error (line 295) | def test_sync_delete_file_error(self, mock_gcs_client):
method test_delete_file (line 319) | async def test_delete_file(self, mock_gcs_client):
FILE: backend/tests/data/storage_clients/test_s3.py
function aws_credentials (line 12) | def aws_credentials():
function s3_mock (line 22) | def s3_mock(aws_credentials):
function test_upload_file (line 32) | async def test_upload_file(s3_mock):
FILE: backend/tests/data/test_chainlit_data_layer.py
function test_update_thread_preserves_metadata_when_none (line 10) | async def test_update_thread_preserves_metadata_when_none():
function test_update_thread_merges_metadata_when_provided (line 38) | async def test_update_thread_merges_metadata_when_provided():
function test_update_thread_deletes_keys_with_none_values (line 89) | async def test_update_thread_deletes_keys_with_none_values():
function test_create_step_uses_nullif_for_output_and_input (line 145) | async def test_create_step_uses_nullif_for_output_and_input():
FILE: backend/tests/data/test_get_data_layer.py
function test_get_data_layer (line 6) | async def test_get_data_layer(
FILE: backend/tests/data/test_literalai.py
function mock_literal_client (line 39) | async def mock_literal_client(monkeypatch: pytest.MonkeyPatch):
function literal_data_layer (line 47) | async def literal_data_layer(mock_literal_client):
function test_thread (line 54) | def test_thread():
function test_step_dict (line 69) | def test_step_dict(test_thread) -> StepDict:
function test_step (line 90) | def test_step(test_thread: LiteralThread):
function literal_test_user (line 116) | def literal_test_user(test_user: User):
function test_filters (line 126) | def test_filters() -> ThreadFilter:
function test_pagination (line 131) | def test_pagination() -> Pagination:
function test_attachment (line 136) | def test_attachment(
function test_create_step (line 155) | async def test_create_step(
function test_safely_send_steps_success (line 190) | async def test_safely_send_steps_success(
function test_safely_send_steps_http_status_error (line 203) | async def test_safely_send_steps_http_status_error(
function test_safely_send_steps_request_error (line 221) | async def test_safely_send_steps_request_error(
function test_get_user (line 241) | async def test_get_user(
function test_get_user_not_found (line 258) | async def test_get_user_not_found(
function test_create_user_not_existing (line 271) | async def test_create_user_not_existing(
function test_create_user_update_existing (line 292) | async def test_create_user_update_existing(
function test_create_user_id_none (line 314) | async def test_create_user_id_none(
function test_update_thread (line 336) | async def test_update_thread(
function test_get_thread_author (line 352) | async def test_get_thread_author(
function test_get_thread (line 364) | async def test_get_thread(
function test_get_thread_with_stub_step (line 385) | async def test_get_thread_with_stub_step(
function test_get_thread_with_attachment (line 424) | async def test_get_thread_with_attachment(
function test_get_thread_non_existing (line 462) | async def test_get_thread_non_existing(
function test_delete_thread (line 475) | async def test_delete_thread(
function test_list_threads (line 485) | async def test_list_threads(
function test_create_element (line 540) | async def test_create_element(
function test_get_element (line 591) | async def test_get_element(
function test_upsert_feedback_create (line 622) | async def test_upsert_feedback_create(
function test_upsert_feedback_update (line 641) | async def test_upsert_feedback_update(
function test_delete_feedback (line 664) | async def test_delete_feedback(
function test_delete_feedback_empty_id (line 676) | async def test_delete_feedback_empty_id(
function test_build_debug_url (line 688) | async def test_build_debug_url(
function test_build_debug_url_error (line 704) | async def test_build_debug_url_error(
function test_delete_element (line 718) | async def test_delete_element(
function test_delete_step (line 731) | async def test_delete_step(
function test_update_step (line 744) | async def test_update_step(
function test_steptype_to_steptype (line 779) | def test_steptype_to_steptype():
function test_score_to_feedbackdict (line 796) | def test_score_to_feedbackdict():
function test_step_to_stepdict (line 830) | def test_step_to_stepdict():
function test_attachment_to_elementdict (line 879) | def test_attachment_to_elementdict():
function test_attachment_to_element (line 911) | def test_attachment_to_element():
function test_step_to_step (line 960) | def test_step_to_step():
function test_thread_to_threaddict (line 1010) | def test_thread_to_threaddict():
FILE: backend/tests/data/test_sql_alchemy.py
function data_layer (line 15) | async def data_layer(mock_storage_client: BaseStorageClient, tmp_path: P...
function test_create_and_get_element (line 126) | async def test_create_and_get_element(
function test_get_current_timestamp (line 151) | async def test_get_current_timestamp(data_layer: SQLAlchemyDataLayer):
function test_get_user (line 156) | async def test_get_user(test_user: User, data_layer: SQLAlchemyDataLayer):
function test_create_user (line 170) | async def test_create_user(test_user: User, data_layer: SQLAlchemyDataLa...
function test_update_thread (line 182) | async def test_update_thread(test_user: User, data_layer: SQLAlchemyData...
function test_get_thread_author (line 189) | async def test_get_thread_author(test_user: User, data_layer: SQLAlchemy...
function test_get_thread (line 199) | async def test_get_thread(test_user: User, data_layer: SQLAlchemyDataLay...
function test_delete_thread (line 211) | async def test_delete_thread(test_user: User, data_layer: SQLAlchemyData...
FILE: backend/tests/langchain/test_async_callback.py
function create_mock_run (line 14) | def create_mock_run(**kwargs):
function mock_run (line 33) | def mock_run():
function test_tracer_initialization (line 43) | async def test_tracer_initialization(mock_chainlit_context):
function test_on_llm_start (line 55) | async def test_on_llm_start(mock_chainlit_context):
function test_on_llm_new_token (line 76) | async def test_on_llm_new_token(mock_chainlit_context):
function test_start_trace (line 100) | async def test_start_trace(mock_chainlit_context):
function test_on_run_update (line 131) | async def test_on_run_update(mock_chainlit_context):
function test_error_handling (line 153) | async def test_error_handling(mock_chainlit_context):
FILE: backend/tests/langchain/test_chain_types.py
function create_mock_run (line 11) | def create_mock_run(**kwargs):
function test_different_run_types (line 29) | async def test_different_run_types(mock_chainlit_context):
function test_nested_chain_hierarchy (line 63) | async def test_nested_chain_hierarchy(mock_chainlit_context):
function test_ignored_runs (line 100) | async def test_ignored_runs(mock_chainlit_context):
function test_custom_filtering (line 119) | async def test_custom_filtering(mock_chainlit_context):
FILE: backend/tests/langchain/test_sync_callback.py
function create_mock_run (line 16) | def create_mock_run(**kwargs):
class TestFinalStreamHelper (line 34) | class TestFinalStreamHelper:
method test_initialization (line 37) | def test_initialization(self):
method test_check_if_answer_reached (line 45) | def test_check_if_answer_reached(self):
class TestGenerationHelper (line 56) | class TestGenerationHelper:
method test_initialization (line 59) | def test_initialization(self):
method test_ensure_values_serializable (line 67) | def test_ensure_values_serializable(self):
method test_convert_message (line 79) | def test_convert_message(self):
method test_build_llm_settings (line 95) | def test_build_llm_settings(self):
function test_should_ignore_run (line 115) | async def test_should_ignore_run(mock_chainlit_context):
function test_get_non_ignored_parent_id (line 131) | async def test_get_non_ignored_parent_id(mock_chainlit_context):
FILE: backend/tests/llama_index/test_callbacks.py
function test_on_event_start_for_function_calls (line 10) | async def test_on_event_start_for_function_calls(mock_chainlit_context):
function test_on_event_start_for_function_calls_missing_payload (line 38) | async def test_on_event_start_for_function_calls_missing_payload(mock_ch...
function test_on_event_end_for_function_calls (line 61) | async def test_on_event_end_for_function_calls(mock_chainlit_context):
function test_on_event_end_for_function_calls_missing_payload (line 81) | async def test_on_event_end_for_function_calls_missing_payload(mock_chai...
FILE: backend/tests/test_action.py
class TestAction (line 9) | class TestAction:
method test_action_initialization_with_required_fields (line 12) | async def test_action_initialization_with_required_fields(self):
method test_action_initialization_with_all_fields (line 29) | async def test_action_initialization_with_all_fields(self):
method test_action_id_auto_generation (line 49) | async def test_action_id_auto_generation(self):
method test_action_to_dict (line 59) | async def test_action_to_dict(self):
method test_action_to_dict_with_for_id (line 81) | async def test_action_to_dict_with_for_id(self):
method test_action_send (line 90) | async def test_action_send(self, mock_chainlit_context):
method test_action_send_updates_for_id (line 116) | async def test_action_send_updates_for_id(self, mock_chainlit_context):
method test_action_remove (line 132) | async def test_action_remove(self, mock_chainlit_context):
method test_action_remove_without_for_id (line 154) | async def test_action_remove_without_for_id(self, mock_chainlit_context):
method test_action_with_complex_payload (line 165) | async def test_action_with_complex_payload(self):
method test_action_with_empty_payload (line 184) | async def test_action_with_empty_payload(self):
method test_action_with_empty_strings (line 191) | async def test_action_with_empty_strings(self):
method test_action_serialization_deserialization (line 207) | async def test_action_serialization_deserialization(self):
method test_multiple_actions_with_same_name (line 230) | async def test_multiple_actions_with_same_name(self):
method test_action_send_multiple_times (line 239) | async def test_action_send_multiple_times(self, mock_chainlit_context):
method test_action_with_special_characters_in_payload (line 254) | async def test_action_with_special_characters_in_payload(self):
method test_action_icon_variations (line 269) | async def test_action_icon_variations(self):
FILE: backend/tests/test_cache.py
class TestCacheDecorator (line 13) | class TestCacheDecorator:
method setup_method (line 16) | def setup_method(self):
method teardown_method (line 20) | def teardown_method(self):
method test_cache_basic_function (line 24) | def test_cache_basic_function(self):
method test_cache_different_arguments (line 44) | def test_cache_different_arguments(self):
method test_cache_with_kwargs (line 67) | def test_cache_with_kwargs(self):
method test_cache_kwargs_order_independence (line 91) | def test_cache_kwargs_order_independence(self):
method test_cache_mixed_args_and_kwargs (line 110) | def test_cache_mixed_args_and_kwargs(self):
method test_cache_with_no_arguments (line 132) | def test_cache_with_no_arguments(self):
method test_cache_with_mutable_return_value (line 150) | def test_cache_with_mutable_return_value(self):
method test_cache_thread_safety (line 171) | def test_cache_thread_safety(self):
method test_cache_different_functions_same_args (line 200) | def test_cache_different_functions_same_args(self):
method test_cache_with_none_arguments (line 231) | def test_cache_with_none_arguments(self):
method test_cache_preserves_function_behavior (line 249) | def test_cache_preserves_function_behavior(self):
class TestInitLcCache (line 263) | class TestInitLcCache:
method test_init_lc_cache_disabled_by_config (line 266) | def test_init_lc_cache_disabled_by_config(self):
method test_init_lc_cache_disabled_by_no_cache_flag (line 281) | def test_init_lc_cache_disabled_by_no_cache_flag(self):
method test_init_lc_cache_langchain_not_installed (line 296) | def test_init_lc_cache_langchain_not_installed(self):
method test_init_lc_cache_with_langchain_installed (line 311) | def test_init_lc_cache_with_langchain_installed(self):
method test_init_lc_cache_creates_new_cache_file (line 343) | def test_init_lc_cache_creates_new_cache_file(self):
method test_init_lc_cache_without_cache_path (line 375) | def test_init_lc_cache_without_cache_path(self):
class TestCacheEdgeCases (line 405) | class TestCacheEdgeCases:
method setup_method (line 408) | def setup_method(self):
method teardown_method (line 412) | def teardown_method(self):
method test_cache_with_unhashable_arguments (line 416) | def test_cache_with_unhashable_arguments(self):
method test_cache_with_string_arguments (line 427) | def test_cache_with_string_arguments(self):
method test_cache_with_tuple_arguments (line 445) | def test_cache_with_tuple_arguments(self):
method test_cache_with_boolean_arguments (line 463) | def test_cache_with_boolean_arguments(self):
method test_cache_global_state (line 485) | def test_cache_global_state(self):
FILE: backend/tests/test_callbacks.py
function test_password_auth_callback (line 13) | async def test_password_auth_callback(test_config: config.ChainlitConfig):
function test_header_auth_callback (line 33) | async def test_header_auth_callback(test_config: config.ChainlitConfig):
function test_oauth_callback (line 64) | async def test_oauth_callback(test_config: config.ChainlitConfig):
function test_on_message (line 104) | async def test_on_message(mock_chainlit_context, test_config: config.Cha...
function test_on_stop (line 131) | async def test_on_stop(mock_chainlit_context, test_config: config.Chainl...
function test_action_callback (line 152) | async def test_action_callback(
function test_on_settings_update (line 178) | async def test_on_settings_update(
function test_author_rename (line 202) | async def test_author_rename(test_config: config.ChainlitConfig):
function test_on_app_startup (line 232) | async def test_on_app_startup(test_config: config.ChainlitConfig):
function test_on_app_shutdown (line 277) | async def test_on_app_shutdown(test_config: config.ChainlitConfig):
function test_on_chat_start (line 322) | async def test_on_chat_start(mock_chainlit_context, test_config: config....
function test_on_chat_resume (line 343) | async def test_on_chat_resume(
function test_set_chat_profiles (line 379) | async def test_set_chat_profiles(
function test_set_chat_profiles_language (line 408) | async def test_set_chat_profiles_language(
function test_set_starters (line 444) | async def test_set_starters(mock_chainlit_context, test_config: config.C...
function test_set_starters_language (line 474) | async def test_set_starters_language(
function test_set_starter_categories (line 514) | async def test_set_starter_categories(
function test_on_shared_thread_view_allow (line 566) | async def test_on_shared_thread_view_allow(
function test_on_shared_thread_view_block_and_exception (line 607) | async def test_on_shared_thread_view_block_and_exception(
function test_on_chat_end (line 662) | async def test_on_chat_end(mock_chainlit_context, test_config: config.Ch...
function test_data_layer_config (line 683) | def test_data_layer_config(
function test_chat_profile_with_config_overrides (line 702) | def test_chat_profile_with_config_overrides():
function test_set_chat_profiles_with_config_overrides (line 742) | async def test_set_chat_profiles_with_config_overrides(
FILE: backend/tests/test_chat_context.py
function mock_chainlit_context (line 10) | def mock_chainlit_context(session=None):
class TestChatContext (line 24) | class TestChatContext:
method setup_method (line 27) | def setup_method(self):
method teardown_method (line 31) | def teardown_method(self):
method test_get_without_session (line 35) | def test_get_without_session(self):
method test_get_with_new_session (line 41) | def test_get_with_new_session(self):
method test_get_returns_copy (line 53) | def test_get_returns_copy(self):
method test_get_with_existing_messages (line 68) | def test_get_with_existing_messages(self):
method test_add_without_session (line 84) | def test_add_without_session(self):
method test_add_with_new_session (line 94) | def test_add_with_new_session(self):
method test_add_message_to_existing_context (line 107) | def test_add_message_to_existing_context(self):
method test_add_duplicate_message (line 124) | def test_add_duplicate_message(self):
method test_remove_without_session (line 138) | def test_remove_without_session(self):
method test_remove_with_nonexistent_context (line 147) | def test_remove_with_nonexistent_context(self):
method test_remove_nonexistent_message (line 158) | def test_remove_nonexistent_message(self):
method test_remove_existing_message (line 173) | def test_remove_existing_message(self):
method test_clear_without_session (line 190) | def test_clear_without_session(self):
method test_clear_with_nonexistent_context (line 200) | def test_clear_with_nonexistent_context(self):
method test_clear_existing_context (line 213) | def test_clear_existing_context(self):
method test_to_openai_with_assistant_message (line 228) | def test_to_openai_with_assistant_message(self):
method test_to_openai_with_user_message (line 248) | def test_to_openai_with_user_message(self):
method test_to_openai_with_system_message (line 265) | def test_to_openai_with_system_message(self):
method test_to_openai_with_unknown_message_type (line 285) | def test_to_openai_with_unknown_message_type(self):
method test_to_openai_with_multiple_messages (line 302) | def test_to_openai_with_multiple_messages(self):
method test_to_openai_with_empty_context (line 329) | def test_to_openai_with_empty_context(self):
method test_to_openai_without_session (line 341) | def test_to_openai_without_session(self):
class TestChatContextEdgeCases (line 349) | class TestChatContextEdgeCases:
method setup_method (line 352) | def setup_method(self):
method teardown_method (line 356) | def teardown_method(self):
method test_multiple_sessions_isolated (line 360) | def test_multiple_sessions_isolated(self):
method test_add_then_remove_then_add_again (line 383) | def test_add_then_remove_then_add_again(self):
method test_clear_then_add (line 403) | def test_clear_then_add(self):
method test_to_openai_with_mixed_message_types (line 421) | def test_to_openai_with_mixed_message_types(self):
method test_chat_context_singleton (line 444) | def test_chat_context_singleton(self):
method test_add_returns_message (line 450) | def test_add_returns_message(self):
FILE: backend/tests/test_chat_settings.py
class TestChatSettings (line 16) | class TestChatSettings:
method test_chat_settings_initialization (line 19) | async def test_chat_settings_initialization(self, mock_chainlit_context):
method test_chat_settings_with_empty_inputs (line 31) | async def test_chat_settings_with_empty_inputs(self, mock_chainlit_con...
method test_chat_settings_settings_method (line 38) | async def test_chat_settings_settings_method(self, mock_chainlit_conte...
method test_chat_settings_with_tabs (line 52) | async def test_chat_settings_with_tabs(self, mock_chainlit_context):
method test_chat_settings_settings_with_tabs (line 72) | async def test_chat_settings_settings_with_tabs(self, mock_chainlit_co...
method test_chat_settings_send (line 93) | async def test_chat_settings_send(self, mock_chainlit_context):
method test_chat_settings_send_with_tabs (line 115) | async def test_chat_settings_send_with_tabs(self, mock_chainlit_context):
method test_chat_settings_with_all_widget_types (line 133) | async def test_chat_settings_with_all_widget_types(self, mock_chainlit...
method test_chat_settings_with_nested_tabs (line 160) | async def test_chat_settings_with_nested_tabs(self, mock_chainlit_cont...
method test_chat_settings_only_widgets_or_only_tabs (line 187) | async def test_chat_settings_only_widgets_or_only_tabs(self, mock_chai...
method test_chat_settings_with_none_initial_values (line 216) | async def test_chat_settings_with_none_initial_values(self, mock_chain...
class TestChatSettingsEdgeCases (line 234) | class TestChatSettingsEdgeCases:
method test_chat_settings_empty_tabs (line 237) | async def test_chat_settings_empty_tabs(self, mock_chainlit_context):
method test_chat_settings_duplicate_ids (line 246) | async def test_chat_settings_duplicate_ids(self, mock_chainlit_context):
method test_chat_settings_send_returns_settings (line 258) | async def test_chat_settings_send_returns_settings(self, mock_chainlit...
method test_chat_settings_to_dict_serialization (line 270) | async def test_chat_settings_to_dict_serialization(self, mock_chainlit...
method test_chat_settings_with_complex_tab_structure (line 289) | async def test_chat_settings_with_complex_tab_structure(
FILE: backend/tests/test_context.py
function mock_emitter (line 17) | def mock_emitter():
function test_chainlit_context_init_with_websocket (line 21) | async def test_chainlit_context_init_with_websocket(
function test_chainlit_context_init_with_http (line 29) | async def test_chainlit_context_init_with_http(mock_http_session):
function test_init_ws_context (line 35) | async def test_init_ws_context(mock_websocket_session):
function test_init_http_context (line 42) | async def test_init_http_context():
function test_get_context (line 49) | async def test_get_context():
FILE: backend/tests/test_element.py
class TestElementBase (line 23) | class TestElementBase:
method test_element_initialization_with_url (line 26) | async def test_element_initialization_with_url(self, mock_chainlit_con...
method test_element_initialization_with_content (line 38) | async def test_element_initialization_with_content(self, mock_chainlit...
method test_element_initialization_with_path (line 49) | async def test_element_initialization_with_path(self, mock_chainlit_co...
method test_element_requires_url_path_or_content (line 59) | async def test_element_requires_url_path_or_content(self, mock_chainli...
method test_element_to_dict (line 65) | async def test_element_to_dict(self, mock_chainlit_context):
method test_element_send (line 83) | async def test_element_send(self, mock_chainlit_context):
method test_element_remove (line 93) | async def test_element_remove(self, mock_chainlit_context):
method test_element_display_options (line 104) | async def test_element_display_options(self, mock_chainlit_context):
method test_element_from_dict_file (line 121) | async def test_element_from_dict_file(self, mock_chainlit_context):
method test_element_from_dict_image (line 138) | async def test_element_from_dict_image(self, mock_chainlit_context):
method test_element_infer_type_from_mime (line 155) | async def test_element_infer_type_from_mime(self):
class TestImageElement (line 167) | class TestImageElement:
method test_image_initialization (line 170) | async def test_image_initialization(self, mock_chainlit_context):
method test_image_size_options (line 183) | async def test_image_size_options(self, mock_chainlit_context):
class TestTextElement (line 198) | class TestTextElement:
method test_text_initialization (line 201) | async def test_text_initialization(self, mock_chainlit_context):
method test_text_without_language (line 211) | async def test_text_without_language(self, mock_chainlit_context):
class TestPdfElement (line 220) | class TestPdfElement:
method test_pdf_initialization (line 223) | async def test_pdf_initialization(self, mock_chainlit_context):
method test_pdf_without_page (line 233) | async def test_pdf_without_page(self, mock_chainlit_context):
class TestAudioElement (line 242) | class TestAudioElement:
method test_audio_initialization (line 245) | async def test_audio_initialization(self, mock_chainlit_context):
method test_audio_default_auto_play (line 258) | async def test_audio_default_auto_play(self, mock_chainlit_context):
class TestVideoElement (line 267) | class TestVideoElement:
method test_video_initialization (line 270) | async def test_video_initialization(self, mock_chainlit_context):
method test_video_without_player_config (line 286) | async def test_video_without_player_config(self, mock_chainlit_context):
class TestFileElement (line 295) | class TestFileElement:
method test_file_initialization (line 298) | async def test_file_initialization(self, mock_chainlit_context):
method test_file_with_content (line 306) | async def test_file_with_content(self, mock_chainlit_context):
class TestTaskListElement (line 316) | class TestTaskListElement:
method test_tasklist_initialization (line 319) | async def test_tasklist_initialization(self, mock_chainlit_context):
method test_tasklist_add_task (line 330) | async def test_tasklist_add_task(self, mock_chainlit_context):
method test_tasklist_preprocess_content (line 344) | async def test_tasklist_preprocess_content(self, mock_chainlit_context):
class TestTaskClass (line 360) | class TestTaskClass:
method test_task_initialization (line 363) | def test_task_initialization(self):
method test_task_with_for_id (line 371) | def test_task_with_for_id(self):
method test_task_status_enum (line 377) | def test_task_status_enum(self):
class TestCustomElement (line 386) | class TestCustomElement:
method test_custom_element_initialization (line 389) | async def test_custom_element_initialization(self, mock_chainlit_conte...
method test_custom_element_content_serialization (line 401) | async def test_custom_element_content_serialization(self, mock_chainli...
method test_custom_element_update (line 411) | async def test_custom_element_update(self, mock_chainlit_context):
class TestElementEdgeCases (line 427) | class TestElementEdgeCases:
method test_element_with_custom_id (line 430) | async def test_element_with_custom_id(self, mock_chainlit_context):
method test_element_with_object_key (line 440) | async def test_element_with_object_key(self, mock_chainlit_context):
method test_element_with_chainlit_key (line 451) | async def test_element_with_chainlit_key(self, mock_chainlit_context):
method test_element_send_without_url_or_key_raises_error (line 462) | async def test_element_send_without_url_or_key_raises_error(
method test_element_from_dict_with_missing_fields (line 475) | async def test_element_from_dict_with_missing_fields(self, mock_chainl...
method test_element_id_uniqueness (line 489) | async def test_element_id_uniqueness(self, mock_chainlit_context):
FILE: backend/tests/test_emitter.py
function emitter (line 11) | def emitter(mock_websocket_session):
function test_send_element (line 15) | async def test_send_element(
function test_send_step (line 42) | async def test_send_step(
function test_update_step (line 57) | async def test_update_step(
function test_delete_step (line 72) | async def test_delete_step(
function test_send_timeout (line 87) | async def test_send_timeout(emitter, mock_websocket_session):
function test_clear (line 92) | async def test_clear(emitter, mock_websocket_session):
function test_send_token (line 97) | async def test_send_token(
function test_set_chat_settings (line 107) | async def test_set_chat_settings(emitter, mock_websocket_session):
function test_update_token_count (line 113) | async def test_update_token_count(emitter, mock_websocket_session):
function test_task_start (line 119) | async def test_task_start(emitter, mock_websocket_session):
function test_task_end (line 124) | async def test_task_end(emitter, mock_websocket_session):
function test_stream_start (line 129) | async def test_stream_start(
function test_send_toast (line 142) | async def test_send_toast(
function test_send_toast_with_type (line 152) | async def test_send_toast_with_type(
function test_send_toast_invalid_type (line 162) | async def test_send_toast_invalid_type(emitter: ChainlitEmitter) -> None:
FILE: backend/tests/test_input_widget.py
class TestInputWidgetBase (line 17) | class TestInputWidgetBase:
method test_input_widget_requires_id_and_label (line 20) | def test_input_widget_requires_id_and_label(self):
class TestSwitchWidget (line 29) | class TestSwitchWidget:
method test_switch_initialization (line 32) | def test_switch_initialization(self):
method test_switch_with_initial_value (line 42) | def test_switch_with_initial_value(self):
method test_switch_with_tooltip_and_description (line 48) | def test_switch_with_tooltip_and_description(self):
method test_switch_disabled (line 60) | def test_switch_disabled(self):
method test_switch_to_dict (line 66) | def test_switch_to_dict(self):
class TestSliderWidget (line 88) | class TestSliderWidget:
method test_slider_initialization (line 91) | def test_slider_initialization(self):
method test_slider_with_custom_range (line 103) | def test_slider_with_custom_range(self):
method test_slider_to_dict (line 119) | def test_slider_to_dict(self):
class TestSelectWidget (line 143) | class TestSelectWidget:
method test_select_with_values (line 146) | def test_select_with_values(self):
method test_select_with_items (line 163) | def test_select_with_items(self):
method test_select_with_initial_index (line 170) | def test_select_with_initial_index(self):
method test_select_with_initial_value (line 181) | def test_select_with_initial_value(self):
method test_select_requires_values_or_items (line 192) | def test_select_requires_values_or_items(self):
method test_select_cannot_have_both_values_and_items (line 197) | def test_select_cannot_have_both_values_and_items(self):
method test_select_initial_index_requires_values (line 207) | def test_select_initial_index_requires_values(self):
method test_select_to_dict (line 220) | def test_select_to_dict(self):
class TestTextInputWidget (line 241) | class TestTextInputWidget:
method test_textinput_initialization (line 244) | def test_textinput_initialization(self):
method test_textinput_with_initial_and_placeholder (line 255) | def test_textinput_with_initial_and_placeholder(self):
method test_textinput_multiline (line 267) | def test_textinput_multiline(self):
method test_textinput_to_dict (line 275) | def test_textinput_to_dict(self):
class TestNumberInputWidget (line 297) | class TestNumberInputWidget:
method test_numberinput_initialization (line 300) | def test_numberinput_initialization(self):
method test_numberinput_with_initial (line 310) | def test_numberinput_with_initial(self):
method test_numberinput_to_dict (line 319) | def test_numberinput_to_dict(self):
class TestTagsWidget (line 339) | class TestTagsWidget:
method test_tags_initialization (line 342) | def test_tags_initialization(self):
method test_tags_with_initial_values (line 352) | def test_tags_with_initial_values(self):
method test_tags_to_dict (line 364) | def test_tags_to_dict(self):
class TestMultiSelectWidget (line 382) | class TestMultiSelectWidget:
method test_multiselect_with_values (line 385) | def test_multiselect_with_values(self):
method test_multiselect_with_items (line 402) | def test_multiselect_with_items(self):
method test_multiselect_with_initial (line 411) | def test_multiselect_with_initial(self):
method test_multiselect_requires_values_or_items (line 422) | def test_multiselect_requires_values_or_items(self):
method test_multiselect_cannot_have_both_values_and_items (line 427) | def test_multiselect_cannot_have_both_values_and_items(self):
method test_multiselect_to_dict (line 437) | def test_multiselect_to_dict(self):
class TestCheckboxWidget (line 457) | class TestCheckboxWidget:
method test_checkbox_initialization (line 460) | def test_checkbox_initialization(self):
method test_checkbox_with_initial_value (line 469) | def test_checkbox_with_initial_value(self):
method test_checkbox_to_dict (line 475) | def test_checkbox_to_dict(self):
class TestRadioGroupWidget (line 495) | class TestRadioGroupWidget:
method test_radiogroup_with_values (line 498) | def test_radiogroup_with_values(self):
method test_radiogroup_with_items (line 509) | def test_radiogroup_with_items(self):
method test_radiogroup_with_initial_index (line 516) | def test_radiogroup_with_initial_index(self):
method test_radiogroup_with_initial_value (line 527) | def test_radiogroup_with_initial_value(self):
method test_radiogroup_requires_values_or_items (line 538) | def test_radiogroup_requires_values_or_items(self):
method test_radiogroup_cannot_have_both_values_and_items (line 543) | def test_radiogroup_cannot_have_both_values_and_items(self):
method test_radiogroup_initial_index_requires_values (line 553) | def test_radiogroup_initial_index_requires_values(self):
method test_radiogroup_to_dict (line 563) | def test_radiogroup_to_dict(self):
class TestTabWidget (line 584) | class TestTabWidget:
method test_tab_initialization (line 587) | def test_tab_initialization(self):
method test_tab_with_inputs (line 595) | def test_tab_with_inputs(self):
method test_tab_to_dict (line 605) | def test_tab_to_dict(self):
method test_tab_to_dict_empty_inputs (line 621) | def test_tab_to_dict_empty_inputs(self):
class TestInputWidgetEdgeCases (line 632) | class TestInputWidgetEdgeCases:
method test_all_widgets_have_consistent_common_fields (line 635) | def test_all_widgets_have_consistent_common_fields(self):
method test_select_with_complex_items (line 691) | def test_select_with_complex_items(self):
method test_multiselect_initial_with_multiple_values (line 706) | def test_multiselect_initial_with_multiple_values(self):
method test_slider_with_negative_range (line 720) | def test_slider_with_negative_range(self):
method test_textinput_empty_initial_value (line 728) | def test_textinput_empty_initial_value(self):
FILE: backend/tests/test_markdown.py
class TestInitMarkdown (line 10) | class TestInitMarkdown:
method test_init_markdown_creates_file (line 13) | def test_init_markdown_creates_file(self):
method test_init_markdown_does_not_overwrite_existing (line 26) | def test_init_markdown_does_not_overwrite_existing(self):
method test_init_markdown_with_nonexistent_directory (line 44) | def test_init_markdown_with_nonexistent_directory(self):
method test_init_markdown_creates_utf8_file (line 53) | def test_init_markdown_creates_utf8_file(self):
class TestGetMarkdownStr (line 69) | class TestGetMarkdownStr:
method test_get_markdown_str_returns_default (line 72) | def test_get_markdown_str_returns_default(self):
method test_get_markdown_str_returns_translated (line 84) | def test_get_markdown_str_returns_translated(self):
method test_get_markdown_str_falls_back_to_default (line 102) | def test_get_markdown_str_falls_back_to_default(self):
method test_get_markdown_str_returns_none_when_no_file (line 117) | def test_get_markdown_str_returns_none_when_no_file(self):
method test_get_markdown_str_with_utf8_content (line 123) | def test_get_markdown_str_with_utf8_content(self):
method test_get_markdown_str_prevents_path_traversal (line 135) | def test_get_markdown_str_prevents_path_traversal(self):
method test_get_markdown_str_with_multiple_languages (line 150) | def test_get_markdown_str_with_multiple_languages(self):
method test_get_markdown_str_with_empty_file (line 177) | def test_get_markdown_str_with_empty_file(self):
method test_get_markdown_str_with_large_file (line 187) | def test_get_markdown_str_with_large_file(self):
class TestDefaultMarkdownStr (line 200) | class TestDefaultMarkdownStr:
method test_default_markdown_str_is_string (line 203) | def test_default_markdown_str_is_string(self):
method test_default_markdown_str_not_empty (line 207) | def test_default_markdown_str_not_empty(self):
method test_default_markdown_str_contains_welcome (line 211) | def test_default_markdown_str_contains_welcome(self):
method test_default_markdown_str_contains_links (line 215) | def test_default_markdown_str_contains_links(self):
method test_default_markdown_str_is_valid_markdown (line 221) | def test_default_markdown_str_is_valid_markdown(self):
class TestMarkdownEdgeCases (line 229) | class TestMarkdownEdgeCases:
method test_init_markdown_with_special_characters_in_path (line 232) | def test_init_markdown_with_special_characters_in_path(self):
method test_get_markdown_str_with_symlink (line 243) | def test_get_markdown_str_with_symlink(self):
method test_get_markdown_str_with_relative_path (line 267) | def test_get_markdown_str_with_relative_path(self):
method test_get_markdown_str_language_case_sensitivity (line 283) | def test_get_markdown_str_language_case_sensitivity(self):
method test_init_markdown_concurrent_calls (line 308) | def test_init_markdown_concurrent_calls(self):
FILE: backend/tests/test_mcp.py
class TestStdioMcpConnection (line 15) | class TestStdioMcpConnection:
method test_stdio_connection_initialization (line 18) | def test_stdio_connection_initialization(self):
method test_stdio_connection_with_empty_args (line 29) | def test_stdio_connection_with_empty_args(self):
method test_stdio_connection_requires_name (line 36) | def test_stdio_connection_requires_name(self):
method test_stdio_connection_requires_command (line 41) | def test_stdio_connection_requires_command(self):
method test_stdio_connection_requires_args (line 46) | def test_stdio_connection_requires_args(self):
method test_stdio_connection_client_type_is_literal (line 51) | def test_stdio_connection_client_type_is_literal(self):
method test_stdio_connection_serialization (line 57) | def test_stdio_connection_serialization(self):
class TestSseMcpConnection (line 71) | class TestSseMcpConnection:
method test_sse_connection_initialization (line 74) | def test_sse_connection_initialization(self):
method test_sse_connection_with_headers (line 83) | def test_sse_connection_with_headers(self):
method test_sse_connection_requires_name (line 92) | def test_sse_connection_requires_name(self):
method test_sse_connection_requires_url (line 97) | def test_sse_connection_requires_url(self):
method test_sse_connection_client_type_is_literal (line 102) | def test_sse_connection_client_type_is_literal(self):
method test_sse_connection_serialization (line 108) | def test_sse_connection_serialization(self):
class TestHttpMcpConnection (line 123) | class TestHttpMcpConnection:
method test_http_connection_initialization (line 126) | def test_http_connection_initialization(self):
method test_http_connection_with_headers (line 137) | def test_http_connection_with_headers(self):
method test_http_connection_requires_name (line 149) | def test_http_connection_requires_name(self):
method test_http_connection_requires_url (line 154) | def test_http_connection_requires_url(self):
method test_http_connection_client_type_is_literal (line 159) | def test_http_connection_client_type_is_literal(self):
method test_http_connection_serialization (line 167) | def test_http_connection_serialization(self):
class TestValidateMcpCommand (line 182) | class TestValidateMcpCommand:
method test_validate_simple_command (line 185) | def test_validate_simple_command(self):
method test_validate_command_with_path (line 197) | def test_validate_command_with_path(self):
method test_validate_command_with_windows_path (line 211) | def test_validate_command_with_windows_path(self):
method test_validate_command_with_env_vars (line 226) | def test_validate_command_with_env_vars(self):
method test_validate_command_with_env_var_with_spaces (line 240) | def test_validate_command_with_env_var_with_spaces(self):
method test_validate_command_with_quoted_args (line 254) | def test_validate_command_with_quoted_args(self):
method test_validate_command_with_multiple_args (line 268) | def test_validate_command_with_multiple_args(self):
method test_validate_command_not_in_allowed_list (line 282) | def test_validate_command_not_in_allowed_list(self):
method test_validate_empty_command (line 291) | def test_validate_empty_command(self):
method test_validate_command_with_invalid_syntax (line 300) | def test_validate_command_with_invalid_syntax(self):
method test_validate_command_with_none_allowed_executables (line 309) | def test_validate_command_with_none_allowed_executables(self):
method test_validate_command_with_invalid_env_var_format (line 321) | def test_validate_command_with_invalid_env_var_format(self):
method test_validate_command_with_complex_env_vars (line 330) | def test_validate_command_with_complex_env_vars(self):
method test_validate_command_with_equals_in_arg (line 347) | def test_validate_command_with_equals_in_arg(self):
method test_validate_command_preserves_arg_order (line 361) | def test_validate_command_preserves_arg_order(self):
class TestMcpConnectionEdgeCases (line 374) | class TestMcpConnectionEdgeCases:
method test_stdio_connection_with_complex_args (line 377) | def test_stdio_connection_with_complex_args(self):
method test_sse_connection_with_multiple_headers (line 395) | def test_sse_connection_with_multiple_headers(self):
method test_http_connection_with_localhost_url (line 411) | def test_http_connection_with_localhost_url(self):
method test_connection_names_can_be_descriptive (line 419) | def test_connection_names_can_be_descriptive(self):
method test_validate_command_with_special_characters_in_path (line 435) | def test_validate_command_with_special_characters_in_path(self):
FILE: backend/tests/test_message.py
function mock_chainlit_context (line 22) | def mock_chainlit_context(session=None):
class TestMessageBase (line 38) | class TestMessageBase:
method test_post_init_sets_thread_id (line 41) | def test_post_init_sets_thread_id(self):
method test_post_init_generates_id_if_not_provided (line 47) | def test_post_init_generates_id_if_not_provided(self):
method test_post_init_uses_provided_id (line 54) | def test_post_init_uses_provided_id(self):
method test_from_dict_creates_message (line 60) | def test_from_dict_creates_message(self):
method test_from_dict_with_minimal_data (line 87) | def test_from_dict_with_minimal_data(self):
method test_to_dict_returns_step_dict (line 105) | def test_to_dict_returns_step_dict(self):
method test_update_stops_streaming (line 139) | async def test_update_stops_streaming(self):
method test_update_with_data_layer (line 155) | async def test_update_with_data_layer(self):
method test_remove_from_chat_context (line 172) | async def test_remove_from_chat_context(self):
class TestMessage (line 186) | class TestMessage:
method test_message_with_string_content (line 189) | def test_message_with_string_content(self):
method test_message_with_dict_content (line 197) | def test_message_with_dict_content(self):
method test_message_with_non_serializable_dict (line 207) | def test_message_with_non_serializable_dict(self):
method test_message_with_non_string_content (line 220) | def test_message_with_non_string_content(self):
method test_message_with_custom_author (line 228) | def test_message_with_custom_author(self):
method test_message_with_default_author (line 235) | def test_message_with_default_author(self):
method test_message_with_actions (line 244) | def test_message_with_actions(self):
method test_message_with_elements (line 255) | def test_message_with_elements(self):
method test_message_send (line 267) | async def test_message_send(self):
method test_message_send_with_author_rename (line 286) | async def test_message_send_with_author_rename(self):
method test_message_send_with_actions_and_elements (line 304) | async def test_message_send_with_actions_and_elements(self):
method test_message_update_with_actions (line 322) | async def test_message_update_with_actions(self):
method test_message_remove_actions (line 341) | async def test_message_remove_actions(self):
method test_stream_token_starts_streaming (line 354) | async def test_stream_token_starts_streaming(self):
method test_stream_token_appends_content (line 366) | async def test_stream_token_appends_content(self):
method test_stream_token_with_sequence (line 380) | async def test_stream_token_with_sequence(self):
method test_stream_token_ignores_empty_token (line 394) | async def test_stream_token_ignores_empty_token(self):
class TestErrorMessage (line 405) | class TestErrorMessage:
method test_error_message_initialization (line 408) | def test_error_message_initialization(self):
method test_error_message_with_custom_author (line 419) | def test_error_message_with_custom_author(self):
method test_error_message_with_fail_on_persist (line 426) | def test_error_message_with_fail_on_persist(self):
method test_error_message_send (line 434) | async def test_error_message_send(self):
class TestAskUserMessage (line 450) | class TestAskUserMessage:
method test_ask_user_message_initialization (line 453) | def test_ask_user_message_initialization(self):
method test_ask_user_message_with_custom_timeout (line 463) | def test_ask_user_message_with_custom_timeout(self):
method test_ask_user_message_send (line 471) | async def test_ask_user_message_send(self):
class TestAskFileMessage (line 488) | class TestAskFileMessage:
method test_ask_file_message_initialization (line 491) | def test_ask_file_message_initialization(self):
method test_ask_file_message_with_custom_limits (line 505) | def test_ask_file_message_with_custom_limits(self):
method test_ask_file_message_send_with_response (line 516) | async def test_ask_file_message_send_with_response(self):
method test_ask_file_message_send_with_no_response (line 544) | async def test_ask_file_message_send_with_no_response(self):
class TestAskActionMessage (line 559) | class TestAskActionMessage:
method test_ask_action_message_initialization (line 562) | def test_ask_action_message_initialization(self):
method test_ask_action_message_send_with_response (line 577) | async def test_ask_action_message_send_with_response(self):
method test_ask_action_message_send_timeout (line 600) | async def test_ask_action_message_send_timeout(self):
class TestAskElementMessage (line 619) | class TestAskElementMessage:
method test_ask_element_message_initialization (line 622) | def test_ask_element_message_initialization(self):
method test_ask_element_message_send_submitted (line 634) | async def test_ask_element_message_send_submitted(self):
method test_ask_element_message_send_cancelled (line 657) | async def test_ask_element_message_send_cancelled(self):
method test_ask_element_message_send_timeout (line 676) | async def test_ask_element_message_send_timeout(self):
class TestMessageEdgeCases (line 695) | class TestMessageEdgeCases:
method test_message_with_none_content (line 698) | def test_message_with_none_content(self):
method test_message_language_override (line 704) | def test_message_language_override(self):
method test_message_send_with_none_content (line 712) | async def test_message_send_with_none_content(self):
method test_ask_message_remove_clears_ask (line 728) | async def test_ask_message_remove_clears_ask(self):
method test_message_metadata_and_tags (line 739) | def test_message_metadata_and_tags(self):
method test_message_to_dict_with_none_metadata (line 749) | def test_message_to_dict_with_none_metadata(self):
FILE: backend/tests/test_modes.py
function mock_modes (line 13) | def mock_modes():
class TestModeOption (line 51) | class TestModeOption:
method test_mode_option_required_fields (line 54) | def test_mode_option_required_fields(self):
method test_mode_option_all_fields (line 64) | def test_mode_option_all_fields(self):
method test_mode_option_to_dict (line 80) | def test_mode_option_to_dict(self):
class TestMode (line 100) | class TestMode:
method test_mode_creation (line 103) | def test_mode_creation(self, mock_modes):
method test_mode_to_dict (line 111) | def test_mode_to_dict(self, mock_modes):
method test_mode_default_option (line 121) | def test_mode_default_option(self, mock_modes):
method test_mode_fallback_to_first (line 131) | def test_mode_fallback_to_first(self, mock_modes):
class TestMessageWithModes (line 152) | class TestMessageWithModes:
method test_message_with_modes (line 155) | async def test_message_with_modes(self, mock_chainlit_context):
method test_message_to_dict_includes_modes (line 164) | async def test_message_to_dict_includes_modes(self, mock_chainlit_cont...
method test_message_from_dict_with_modes (line 174) | async def test_message_from_dict_with_modes(self, mock_chainlit_context):
method test_message_without_modes (line 190) | async def test_message_without_modes(self, mock_chainlit_context):
method test_message_send_with_modes (line 199) | async def test_message_send_with_modes(self, mock_chainlit_context):
class TestEmitterSetModes (line 223) | class TestEmitterSetModes:
method test_set_modes (line 226) | async def test_set_modes(
method test_set_modes_empty_list (line 237) | async def test_set_modes_empty_list(
method test_set_modes_single_mode (line 247) | async def test_set_modes_single_mode(
class TestModeExports (line 268) | class TestModeExports:
method test_mode_exported_from_chainlit (line 271) | def test_mode_exported_from_chainlit(self):
method test_mode_option_exported_from_chainlit (line 276) | def test_mode_option_exported_from_chainlit(self):
FILE: backend/tests/test_oauth_providers.py
class TestOAuthProviderBase (line 28) | class TestOAuthProviderBase:
method test_oauth_provider_has_required_methods (line 31) | def test_oauth_provider_has_required_methods(self):
method test_oauth_provider_is_configured_returns_false_when_env_missing (line 43) | def test_oauth_provider_is_configured_returns_false_when_env_missing(s...
method test_oauth_provider_is_configured_returns_true_when_env_present (line 50) | def test_oauth_provider_is_configured_returns_true_when_env_present(se...
method test_oauth_provider_get_env_prefix (line 58) | def test_oauth_provider_get_env_prefix(self):
method test_oauth_provider_get_prompt_returns_provider_specific (line 65) | def test_oauth_provider_get_prompt_returns_provider_specific(self):
method test_oauth_provider_get_prompt_returns_global (line 74) | def test_oauth_provider_get_prompt_returns_global(self):
method test_oauth_provider_get_prompt_returns_default (line 83) | def test_oauth_provider_get_prompt_returns_default(self):
method test_oauth_provider_abstract_methods_raise_not_implemented (line 92) | async def test_oauth_provider_abstract_methods_raise_not_implemented(s...
class TestGithubOAuthProvider (line 106) | class TestGithubOAuthProvider:
method test_github_provider_initialization (line 109) | def test_github_provider_initialization(self):
method test_github_provider_with_custom_urls (line 126) | def test_github_provider_with_custom_urls(self):
method test_github_get_raw_token_response_success (line 154) | async def test_github_get_raw_token_response_success(self):
method test_github_get_token_success (line 182) | async def test_github_get_token_success(self):
method test_github_get_token_missing_access_token (line 207) | async def test_github_get_token_missing_access_token(self):
method test_github_get_user_info_success (line 234) | async def test_github_get_user_info_success(self):
class TestGoogleOAuthProvider (line 275) | class TestGoogleOAuthProvider:
method test_google_provider_initialization (line 278) | def test_google_provider_initialization(self):
method test_google_get_token_success (line 299) | async def test_google_get_token_success(self):
method test_google_get_user_info_success (line 329) | async def test_google_get_user_info_success(self):
class TestAzureADOAuthProvider (line 362) | class TestAzureADOAuthProvider:
method test_azure_ad_provider_initialization (line 365) | def test_azure_ad_provider_initialization(self):
method test_azure_ad_single_tenant_urls (line 383) | def test_azure_ad_single_tenant_urls(self):
method test_azure_ad_get_token_with_refresh_token (line 408) | async def test_azure_ad_get_token_with_refresh_token(self):
method test_azure_ad_get_user_info_with_photo (line 440) | async def test_azure_ad_get_user_info_with_photo(self):
class TestOktaOAuthProvider (line 480) | class TestOktaOAuthProvider:
method test_okta_provider_initialization (line 483) | def test_okta_provider_initialization(self):
method test_okta_authorization_server_path_default (line 506) | def test_okta_authorization_server_path_default(self):
method test_okta_authorization_server_path_custom (line 520) | def test_okta_authorization_server_path_custom(self):
method test_okta_authorization_server_path_false (line 535) | def test_okta_authorization_server_path_false(self):
class TestAuth0OAuthProvider (line 551) | class TestAuth0OAuthProvider:
method test_auth0_provider_initialization (line 554) | def test_auth0_provider_initialization(self):
method test_auth0_with_original_domain (line 570) | def test_auth0_with_original_domain(self):
class TestGenericOAuthProvider (line 587) | class TestGenericOAuthProvider:
method test_generic_provider_initialization (line 590) | def test_generic_provider_initialization(self):
method test_generic_provider_custom_name (line 611) | def test_generic_provider_custom_name(self):
method test_generic_provider_custom_user_identifier (line 637) | def test_generic_provider_custom_user_identifier(self):
class TestAzureADHybridOAuthProvider (line 656) | class TestAzureADHybridOAuthProvider:
method test_azure_ad_hybrid_provider_initialization (line 659) | def test_azure_ad_hybrid_provider_initialization(self):
method test_azure_ad_hybrid_get_token_success (line 681) | async def test_azure_ad_hybrid_get_token_success(self):
method test_azure_ad_hybrid_get_user_info_success (line 713) | async def test_azure_ad_hybrid_get_user_info_success(self):
class TestDescopeOAuthProvider (line 752) | class TestDescopeOAuthProvider:
method test_descope_provider_initialization (line 755) | def test_descope_provider_initialization(self):
method test_descope_get_token_success (line 772) | async def test_descope_get_token_success(self):
method test_descope_get_user_info_success (line 802) | async def test_descope_get_user_info_success(self):
class TestAWSCognitoOAuthProvider (line 833) | class TestAWSCognitoOAuthProvider:
method test_cognito_provider_initialization (line 836) | def test_cognito_provider_initialization(self):
method test_cognito_provider_custom_scopes (line 853) | def test_cognito_provider_custom_scopes(self):
method test_cognito_get_token_success (line 870) | async def test_cognito_get_token_success(self):
method test_cognito_get_user_info_success (line 901) | async def test_cognito_get_user_info_success(self):
class TestGitlabOAuthProvider (line 934) | class TestGitlabOAuthProvider:
method test_gitlab_provider_initialization (line 937) | def test_gitlab_provider_initialization(self):
method test_gitlab_provider_strips_trailing_slash (line 955) | def test_gitlab_provider_strips_trailing_slash(self):
method test_gitlab_get_token_success (line 970) | async def test_gitlab_get_token_success(self):
method test_gitlab_get_user_info_success (line 1001) | async def test_gitlab_get_user_info_success(self):
class TestKeycloakOAuthProvider (line 1034) | class TestKeycloakOAuthProvider:
method test_keycloak_provider_initialization (line 1037) | def test_keycloak_provider_initialization(self):
method test_keycloak_provider_custom_name (line 1056) | def test_keycloak_provider_custom_name(self):
method test_keycloak_get_token_success (line 1080) | async def test_keycloak_get_token_success(self):
method test_keycloak_get_user_info_success (line 1113) | async def test_keycloak_get_user_info_success(self):
class TestHelperFunctions (line 1146) | class TestHelperFunctions:
method test_get_oauth_provider_returns_correct_provider (line 1149) | def test_get_oauth_provider_returns_correct_provider(self):
method test_get_oauth_provider_returns_none_for_unknown (line 1156) | def test_get_oauth_provider_returns_none_for_unknown(self):
method test_get_configured_oauth_providers_empty_when_none_configured (line 1162) | def test_get_configured_oauth_providers_empty_when_none_configured(self):
method test_get_configured_oauth_providers_returns_configured (line 1170) | def test_get_configured_oauth_providers_returns_configured(self):
class TestOAuthProviderEdgeCases (line 1187) | class TestOAuthProviderEdgeCases:
method test_provider_handles_http_error (line 1191) | async def test_provider_handles_http_error(self):
method test_provider_strips_trailing_slash_from_domain (line 1215) | def test_provider_strips_trailing_slash_from_domain(self):
method test_provider_with_prompt_parameter (line 1229) | def test_provider_with_prompt_parameter(self):
FILE: backend/tests/test_server.py
function test_client (line 23) | def test_client():
function mock_load_translation (line 28) | def mock_load_translation(test_config: ChainlitConfig, monkeypatch: pyte...
function test_project_translations_default_language (line 35) | def test_project_translations_default_language(
function test_project_translations_specific_language (line 46) | def test_project_translations_specific_language(
function test_project_translations_invalid_language (line 58) | def test_project_translations_invalid_language(
function test_project_translations_bcp47_language (line 72) | def test_project_translations_bcp47_language(
function mock_get_current_user (line 85) | def mock_get_current_user():
function test_project_settings (line 97) | async def test_project_settings(test_client: TestClient, mock_get_curren...
function test_project_settings_path_traversal (line 119) | def test_project_settings_path_traversal(
function test_get_avatar_default (line 162) | def test_get_avatar_default(test_client: TestClient, monkeypatch: pytest...
function test_get_avatar_custom (line 169) | def test_get_avatar_custom(test_client: TestClient, monkeypatch: pytest....
function test_get_avatar_with_spaces (line 187) | def test_get_avatar_with_spaces(
function test_get_avatar_non_existent_favicon (line 205) | def test_get_avatar_non_existent_favicon(
function test_avatar_path_traversal (line 219) | def test_avatar_path_traversal(
function mock_session_get_by_id_patched (line 242) | def mock_session_get_by_id_patched(mock_session: Mock, monkeypatch: pyte...
function test_get_file_success (line 254) | def test_get_file_success(
function test_get_file_not_existent_file (line 295) | def test_get_file_not_existent_file(
function test_get_file_non_existing_session (line 313) | def test_get_file_non_existing_session(
function test_upload_file_success (line 333) | def test_upload_file_success(
function test_file_access_by_different_user (line 379) | def test_file_access_by_different_user(
function test_upload_file_missing_file (line 438) | def test_upload_file_missing_file(
function test_upload_file_invalid_session (line 455) | def test_upload_file_invalid_session(
function test_upload_file_unauthorized (line 477) | def test_upload_file_unauthorized(
function test_upload_file_disabled (line 503) | def test_upload_file_disabled(
function test_upload_file_mime_type_check (line 571) | def test_upload_file_mime_type_check(
function test_upload_file_size_check (line 624) | def test_upload_file_size_check(
function test_ask_file_with_spontaneous_upload_disabled (line 688) | def test_ask_file_with_spontaneous_upload_disabled(
function test_project_translations_file_path_traversal (line 750) | def test_project_translations_file_path_traversal(
function test_project_settings_with_chat_profile_config_overrides (line 770) | def test_project_settings_with_chat_profile_config_overrides(
function test_project_settings_config_overrides_serialization (line 880) | def test_project_settings_config_overrides_serialization(
function test_project_settings_config_overrides_language (line 925) | def test_project_settings_config_overrides_language(
function test_project_settings_thread_sharing_flag (line 1006) | def test_project_settings_thread_sharing_flag(
function test_share_thread_endpoint_sets_flags (line 1044) | def test_share_thread_endpoint_sets_flags(
function test_health_check (line 1108) | def test_health_check(test_client: TestClient):
FILE: backend/tests/test_session.py
class TestJSONEncoderIgnoreNonSerializable (line 18) | class TestJSONEncoderIgnoreNonSerializable:
method test_encoder_handles_serializable_objects (line 21) | def test_encoder_handles_serializable_objects(self):
method test_encoder_ignores_non_serializable_objects (line 32) | def test_encoder_ignores_non_serializable_objects(self):
method test_encoder_with_nested_non_serializable (line 45) | def test_encoder_with_nested_non_serializable(self):
class TestCleanMetadata (line 66) | class TestCleanMetadata:
method test_clean_metadata_with_normal_data (line 69) | def test_clean_metadata_with_normal_data(self):
method test_clean_metadata_removes_non_serializable (line 75) | def test_clean_metadata_removes_non_serializable(self):
method test_clean_metadata_redacts_large_data (line 87) | def test_clean_metadata_redacts_large_data(self):
method test_clean_metadata_with_custom_max_size (line 96) | def test_clean_metadata_with_custom_max_size(self):
method test_clean_metadata_preserves_unicode (line 105) | def test_clean_metadata_preserves_unicode(self):
class TestBaseSession (line 115) | class TestBaseSession:
method test_base_session_initialization (line 118) | def test_base_session_initialization(self):
method test_base_session_with_thread_id (line 137) | def test_base_session_with_thread_id(self):
method test_base_session_with_user_env (line 152) | def test_base_session_with_user_env(self):
method test_base_session_with_chat_profile (line 166) | def test_base_session_with_chat_profile(self):
method test_base_session_files_dir (line 180) | def test_base_session_files_dir(self):
method test_base_session_persist_file_with_content (line 195) | async def test_base_session_persist_file_with_content(self):
method test_base_session_persist_file_with_string_content (line 221) | async def test_base_session_persist_file_with_string_content(self):
method test_base_session_persist_file_without_path_or_content (line 246) | async def test_base_session_persist_file_without_path_or_content(self):
method test_base_session_to_persistable (line 260) | def test_base_session_to_persistable(self):
method test_base_session_to_persistable_without_persist_user_env (line 291) | def test_base_session_to_persistable_without_persist_user_env(self):
class TestHTTPSession (line 319) | class TestHTTPSession:
method test_http_session_initialization (line 322) | def test_http_session_initialization(self):
method test_http_session_delete (line 338) | async def test_http_session_delete(self):
class TestWebsocketSession (line 359) | class TestWebsocketSession:
method test_websocket_session_initialization (line 362) | def test_websocket_session_initialization(self):
method test_websocket_session_language_detection (line 383) | def test_websocket_session_language_detection(self):
method test_websocket_session_default_language (line 397) | def test_websocket_session_default_language(self):
method test_websocket_session_restore (line 411) | def test_websocket_session_restore(self):
method test_websocket_session_delete (line 434) | async def test_websocket_session_delete(self):
method test_websocket_session_get (line 461) | def test_websocket_session_get(self):
method test_websocket_session_get_by_id (line 475) | def test_websocket_session_get_by_id(self):
method test_websocket_session_require_success (line 489) | def test_websocket_session_require_success(self):
method test_websocket_session_require_failure (line 503) | def test_websocket_session_require_failure(self):
method test_websocket_session_flush_method_queue (line 509) | async def test_websocket_session_flush_method_queue(self):
class TestSessionEdgeCases (line 539) | class TestSessionEdgeCases:
method test_base_session_with_all_client_types (line 542) | def test_base_session_with_all_client_types(self):
method test_persist_file_with_mime_extension (line 558) | async def test_persist_file_with_mime_extension(self):
method test_clean_metadata_with_empty_dict (line 582) | def test_clean_metadata_with_empty_dict(self):
method test_websocket_session_with_chat_profile (line 587) | def test_websocket_session_with_chat_profile(self):
method test_websocket_session_delete_with_mcp_sessions (line 602) | async def test_websocket_session_delete_with_mcp_sessions(self):
FILE: backend/tests/test_sidebar.py
class TestElementSidebar (line 8) | class TestElementSidebar:
method test_set_title (line 11) | async def test_set_title(self, mock_chainlit_context):
method test_set_title_with_empty_string (line 20) | async def test_set_title_with_empty_string(self, mock_chainlit_context):
method test_set_title_with_special_characters (line 27) | async def test_set_title_with_special_characters(self, mock_chainlit_c...
method test_set_elements_with_single_element (line 35) | async def test_set_elements_with_single_element(self, mock_chainlit_co...
method test_set_elements_with_multiple_elements (line 54) | async def test_set_elements_with_multiple_elements(self, mock_chainlit...
method test_set_elements_with_empty_list (line 74) | async def test_set_elements_with_empty_list(self, mock_chainlit_context):
method test_set_elements_with_key (line 89) | async def test_set_elements_with_key(self, mock_chainlit_context):
method test_set_elements_with_for_id (line 102) | async def test_set_elements_with_for_id(self, mock_chainlit_context):
method test_set_elements_without_for_id (line 119) | async def test_set_elements_without_for_id(self, mock_chainlit_context):
method test_set_elements_persist_false (line 132) | async def test_set_elements_persist_false(self, mock_chainlit_context):
method test_set_elements_serialization (line 149) | async def test_set_elements_serialization(self, mock_chainlit_context):
class TestElementSidebarEdgeCases (line 172) | class TestElementSidebarEdgeCases:
method test_set_title_multiple_times (line 175) | async def test_set_title_multiple_times(self, mock_chainlit_context):
method test_set_elements_multiple_times (line 188) | async def test_set_elements_multiple_times(self, mock_chainlit_context):
method test_set_elements_with_same_key_twice (line 203) | async def test_set_elements_with_same_key_twice(self, mock_chainlit_co...
method test_set_elements_with_different_keys (line 216) | async def test_set_elements_with_different_keys(self, mock_chainlit_co...
method test_set_elements_with_large_number_of_elements (line 232) | async def test_set_elements_with_large_number_of_elements(
method test_set_title_and_set_elements_together (line 252) | async def test_set_title_and_set_elements_together(self, mock_chainlit...
method test_set_elements_with_mixed_element_types (line 272) | async def test_set_elements_with_mixed_element_types(self, mock_chainl...
method test_set_title_with_long_string (line 296) | async def test_set_title_with_long_string(self, mock_chainlit_context):
FILE: backend/tests/test_slack_socket_mode.py
function test_start_socket_mode_starts_handler (line 9) | async def test_start_socket_mode_starts_handler(monkeypatch):
function test_slack_http_route_registered (line 38) | def test_slack_http_route_registered(monkeypatch):
FILE: backend/tests/test_socket.py
class TestGetTokenFromCookie (line 19) | class TestGetTokenFromCookie:
method test_get_token_from_cookie_with_valid_cookie (line 22) | def test_get_token_from_cookie_with_valid_cookie(self):
method test_get_token_from_cookie_without_cookie (line 33) | def test_get_token_from_cookie_without_cookie(self):
method test_get_token_from_cookie_with_empty_cookie (line 39) | def test_get_token_from_cookie_with_empty_cookie(self):
class TestGetToken (line 50) | class TestGetToken:
method test_get_token_calls_get_token_from_cookie (line 53) | def test_get_token_calls_get_token_from_cookie(self):
class TestAuthenticateConnection (line 65) | class TestAuthenticateConnection:
method test_authenticate_connection_with_valid_token (line 69) | async def test_authenticate_connection_with_valid_token(self):
method test_authenticate_connection_without_token (line 87) | async def test_authenticate_connection_without_token(self):
method test_authenticate_connection_with_invalid_token (line 99) | async def test_authenticate_connection_with_invalid_token(self):
class TestRestoreExistingSession (line 113) | class TestRestoreExistingSession:
method test_restore_existing_session_success (line 116) | def test_restore_existing_session_success(self):
method test_restore_existing_session_not_found (line 136) | def test_restore_existing_session_not_found(self):
class TestPersistUserSession (line 148) | class TestPersistUserSession:
method test_persist_user_session_with_data_layer (line 152) | async def test_persist_user_session_with_data_layer(self):
method test_persist_user_session_without_data_layer (line 167) | async def test_persist_user_session_without_data_layer(self):
class TestResumeThread (line 176) | class TestResumeThread:
method test_resume_thread_without_data_layer (line 180) | async def test_resume_thread_without_data_layer(self):
method test_resume_thread_without_user (line 194) | async def test_resume_thread_without_user(self):
method test_resume_thread_without_thread_id (line 205) | async def test_resume_thread_without_thread_id(self):
method test_resume_thread_thread_not_found (line 216) | async def test_resume_thread_thread_not_found(self):
method test_resume_thread_user_not_author (line 235) | async def test_resume_thread_user_not_author(self):
method test_resume_thread_success (line 254) | async def test_resume_thread_success(self):
method test_resume_thread_with_string_metadata (line 288) | async def test_resume_thread_with_string_metadata(self):
class TestLoadUserEnv (line 320) | class TestLoadUserEnv:
method test_load_user_env_with_valid_json (line 323) | def test_load_user_env_with_valid_json(self):
method test_load_user_env_with_required_keys (line 334) | def test_load_user_env_with_required_keys(self):
method test_load_user_env_missing_required_key (line 345) | def test_load_user_env_missing_required_key(self):
method test_load_user_env_none_with_required_keys (line 357) | def test_load_user_env_none_with_required_keys(self):
method test_load_user_env_none_without_required_keys (line 368) | def test_load_user_env_none_without_required_keys(self):
class TestCleanSession (line 379) | class TestCleanSession:
method test_clean_session_with_existing_session (line 383) | async def test_clean_session_with_existing_session(self):
method test_clean_session_without_session (line 397) | async def test_clean_session_without_session(self):
class TestSocketEdgeCases (line 406) | class TestSocketEdgeCases:
method test_restore_existing_session_with_none_session_id (line 409) | def test_restore_existing_session_with_none_session_id(self):
method test_persist_user_session_with_empty_metadata (line 419) | async def test_persist_user_session_with_empty_metadata(self):
method test_load_user_env_with_empty_json (line 432) | def test_load_user_env_with_empty_json(self):
method test_resume_thread_with_empty_metadata (line 444) | async def test_resume_thread_with_empty_metadata(self):
method test_authenticate_connection_with_exception (line 472) | async def test_authenticate_connection_with_exception(self):
FILE: backend/tests/test_step.py
class TestStepClass (line 19) | class TestStepClass:
method test_step_initialization_with_defaults (line 22) | async def test_step_initialization_with_defaults(self, mock_chainlit_c...
method test_step_initialization_with_all_fields (line 48) | async def test_step_initialization_with_all_fields(self, mock_chainlit...
method test_step_input_setter_with_string (line 78) | async def test_step_input_setter_with_string(self, mock_chainlit_conte...
method test_step_input_setter_with_dict (line 86) | async def test_step_input_setter_with_dict(self, mock_chainlit_context):
method test_step_output_setter_with_string (line 98) | async def test_step_output_setter_with_string(self, mock_chainlit_cont...
method test_step_output_setter_with_dict (line 106) | async def test_step_output_setter_with_dict(self, mock_chainlit_context):
method test_step_clean_content_with_bytes (line 118) | async def test_step_clean_content_with_bytes(self, mock_chainlit_conte...
method test_step_to_dict (line 132) | async def test_step_to_dict(self, mock_chainlit_context):
method test_step_send (line 161) | async def test_step_send(self, mock_chainlit_context):
method test_step_send_with_elements (line 172) | async def test_step_send_with_elements(self, mock_chainlit_context):
method test_step_send_already_persisted (line 184) | async def test_step_send_already_persisted(self, mock_chainlit_context):
method test_step_update (line 195) | async def test_step_update(self, mock_chainlit_context):
method test_step_remove (line 207) | async def test_step_remove(self, mock_chainlit_context):
method test_step_stream_token_output (line 217) | async def test_step_stream_token_output(self, mock_chainlit_context):
method test_step_stream_token_input (line 229) | async def test_step_stream_token_input(self, mock_chainlit_context):
method test_step_stream_token_sequence (line 239) | async def test_step_stream_token_sequence(self, mock_chainlit_context):
method test_step_stream_token_empty (line 250) | async def test_step_stream_token_empty(self, mock_chainlit_context):
method test_step_context_manager_async (line 260) | async def test_step_context_manager_async(self, mock_chainlit_context):
method test_step_context_manager_with_exception (line 272) | async def test_step_context_manager_with_exception(self, mock_chainlit...
method test_step_parent_id_from_context (line 284) | async def test_step_parent_id_from_context(self, mock_chainlit_context):
method test_step_local_steps_tracking (line 291) | async def test_step_local_steps_tracking(self, mock_chainlit_context):
method test_step_with_none_input (line 308) | async def test_step_with_none_input(self, mock_chainlit_context):
method test_step_with_none_output (line 316) | async def test_step_with_none_output(self, mock_chainlit_context):
method test_step_with_list_content (line 324) | async def test_step_with_list_content(self, mock_chainlit_context):
method test_step_with_tuple_content (line 335) | async def test_step_with_tuple_content(self, mock_chainlit_context):
class TestStepDecorator (line 346) | class TestStepDecorator:
method test_step_decorator_async_function (line 349) | async def test_step_decorator_async_function(self, mock_chainlit_conte...
method test_step_decorator_sync_function (line 362) | async def test_step_decorator_sync_function(self, mock_chainlit_context):
method test_step_decorator_uses_function_name (line 374) | async def test_step_decorator_uses_function_name(self, mock_chainlit_c...
method test_step_decorator_captures_input (line 389) | async def test_step_decorator_captures_input(self, mock_chainlit_conte...
method test_step_decorator_captures_output (line 402) | async def test_step_decorator_captures_output(self, mock_chainlit_cont...
method test_step_decorator_handles_exception (line 417) | async def test_step_decorator_handles_exception(self, mock_chainlit_co...
method test_step_decorator_with_metadata (line 435) | async def test_step_decorator_with_metadata(self, mock_chainlit_context):
method test_step_decorator_with_tags (line 450) | async def test_step_decorator_with_tags(self, mock_chainlit_context):
method test_step_decorator_without_parentheses (line 465) | async def test_step_decorator_without_parentheses(self, mock_chainlit_...
class TestStepHelperFunctions (line 480) | class TestStepHelperFunctions:
method test_flatten_args_kwargs (line 483) | def test_flatten_args_kwargs(self):
method test_flatten_args_kwargs_with_all_kwargs (line 496) | def test_flatten_args_kwargs_with_all_kwargs(self):
method test_stub_step (line 506) | async def test_stub_step(self, mock_chainlit_context):
method test_check_add_step_in_cot_hidden (line 524) | async def test_check_add_step_in_cot_hidden(self, mock_chainlit_context):
method test_check_add_step_in_cot_visible (line 539) | async def test_check_add_step_in_cot_visible(self, mock_chainlit_conte...
class TestStepEdgeCases (line 552) | class TestStepEdgeCases:
method test_step_with_non_serializable_content (line 555) | async def test_step_with_non_serializable_content(self, mock_chainlit_...
method test_step_with_very_long_content (line 569) | async def test_step_with_very_long_content(self, mock_chainlit_context):
method test_step_multiple_updates (line 579) | async def test_step_multiple_updates(self, mock_chainlit_context):
method test_step_id_uniqueness (line 590) | async def test_step_id_uniqueness(self, mock_chainlit_context):
method test_step_with_custom_thread_id (line 600) | async def test_step_with_custom_thread_id(self, mock_chainlit_context):
method test_step_fail_on_persist_error_flag (line 608) | async def test_step_fail_on_persist_error_flag(self, mock_chainlit_con...
FILE: backend/tests/test_translations.py
class TestCompareJsonStructures (line 9) | class TestCompareJsonStructures:
method test_compare_identical_structures (line 12) | def test_compare_identical_structures(self):
method test_compare_with_missing_keys (line 21) | def test_compare_with_missing_keys(self):
method test_compare_with_extra_keys (line 32) | def test_compare_with_extra_keys(self):
method test_compare_with_both_missing_and_extra_keys (line 43) | def test_compare_with_both_missing_and_extra_keys(self):
method test_compare_nested_structures (line 54) | def test_compare_nested_structures(self):
method test_compare_nested_with_missing_keys (line 63) | def test_compare_nested_with_missing_keys(self):
method test_compare_nested_with_extra_keys (line 73) | def test_compare_nested_with_extra_keys(self):
method test_compare_deeply_nested_structures (line 83) | def test_compare_deeply_nested_structures(self):
method test_compare_structure_mismatch_dict_vs_value (line 93) | def test_compare_structure_mismatch_dict_vs_value(self):
method test_compare_structure_mismatch_value_vs_dict (line 103) | def test_compare_structure_mismatch_value_vs_dict(self):
method test_compare_with_non_dict_input_truth (line 113) | def test_compare_with_non_dict_input_truth(self):
method test_compare_with_non_dict_input_to_compare (line 118) | def test_compare_with_non_dict_input_to_compare(self):
method test_compare_with_both_non_dict_inputs (line 123) | def test_compare_with_both_non_dict_inputs(self):
method test_compare_empty_dicts (line 128) | def test_compare_empty_dicts(self):
method test_compare_empty_truth_with_data (line 137) | def test_compare_empty_truth_with_data(self):
method test_compare_empty_to_compare_with_data (line 147) | def test_compare_empty_to_compare_with_data(self):
method test_compare_with_different_value_types (line 157) | def test_compare_with_different_value_types(self):
method test_compare_complex_nested_structure (line 167) | def test_compare_complex_nested_structure(self):
method test_compare_with_null_values (line 193) | def test_compare_with_null_values(self):
method test_compare_with_list_values (line 202) | def test_compare_with_list_values(self):
method test_compare_path_formatting (line 212) | def test_compare_path_formatting(self):
class TestLintTranslationJson (line 224) | class TestLintTranslationJson:
method test_lint_with_no_errors (line 227) | def test_lint_with_no_errors(self):
method test_lint_with_errors (line 239) | def test_lint_with_errors(self):
method test_lint_with_nested_errors (line 253) | def test_lint_with_nested_errors(self):
method test_lint_with_structure_mismatch (line 265) | def test_lint_with_structure_mismatch(self):
method test_lint_with_multiple_errors (line 277) | def test_lint_with_multiple_errors(self):
method test_lint_output_format (line 299) | def test_lint_output_format(self):
class TestTranslationsEdgeCases (line 314) | class TestTranslationsEdgeCases:
method test_compare_with_numeric_keys (line 317) | def test_compare_with_numeric_keys(self):
method test_compare_with_special_characters_in_keys (line 326) | def test_compare_with_special_characters_in_keys(self):
method test_compare_with_unicode_keys (line 335) | def test_compare_with_unicode_keys(self):
method test_compare_very_deeply_nested (line 344) | def test_compare_very_deeply_nested(self):
method test_compare_with_empty_string_values (line 354) | def test_compare_with_empty_string_values(self):
method test_lint_with_empty_filename (line 363) | def test_lint_with_empty_filename(self):
method test_compare_preserves_error_order (line 374) | def test_compare_preserves_error_order(self):
FILE: backend/tests/test_user_session.py
function test_user_session_set_get (line 1) | async def test_user_session_set_get(mock_chainlit_context, user_session):
FILE: backend/tests/test_utils.py
class TestUtcNow (line 19) | class TestUtcNow:
method test_utc_now_returns_string (line 22) | def test_utc_now_returns_string(self):
method test_utc_now_ends_with_z (line 27) | def test_utc_now_ends_with_z(self):
method test_utc_now_is_iso_format (line 32) | def test_utc_now_is_iso_format(self):
method test_utc_now_is_current_time (line 40) | def test_utc_now_is_current_time(self):
method test_utc_now_multiple_calls (line 55) | def test_utc_now_multiple_calls(self):
class TestTimestampUtc (line 65) | class TestTimestampUtc:
method test_timestamp_utc_returns_string (line 68) | def test_timestamp_utc_returns_string(self):
method test_timestamp_utc_ends_with_z (line 73) | def test_timestamp_utc_ends_with_z(self):
method test_timestamp_utc_converts_correctly (line 78) | def test_timestamp_utc_converts_correctly(self):
method test_timestamp_utc_with_zero (line 90) | def test_timestamp_utc_with_zero(self):
method test_timestamp_utc_with_fractional_seconds (line 98) | def test_timestamp_utc_with_fractional_seconds(self):
method test_timestamp_utc_with_negative_timestamp (line 107) | def test_timestamp_utc_with_negative_timestamp(self):
class TestWrapUserFunction (line 118) | class TestWrapUserFunction:
method test_wrap_user_function_with_sync_function (line 121) | async def test_wrap_user_function_with_sync_function(self, mock_chainl...
method test_wrap_user_function_with_async_function (line 133) | async def test_wrap_user_function_with_async_function(self, mock_chain...
method test_wrap_user_function_with_no_args (line 145) | async def test_wrap_user_function_with_no_args(self, mock_chainlit_con...
method test_wrap_user_function_with_task (line 157) | async def test_wrap_user_function_with_task(self, mock_chainlit_context):
method test_wrap_user_function_handles_exception (line 173) | async def test_wrap_user_function_handles_exception(self, mock_chainli...
method test_wrap_user_function_with_task_handles_exception (line 186) | async def test_wrap_user_function_with_task_handles_exception(
method test_wrap_user_function_preserves_function_metadata (line 206) | async def test_wrap_user_function_preserves_function_metadata(
method test_wrap_user_function_with_kwargs (line 221) | async def test_wrap_user_function_with_kwargs(self, mock_chainlit_cont...
class TestMakeModuleGetattr (line 234) | class TestMakeModuleGetattr:
method test_make_module_getattr_creates_function (line 237) | def test_make_module_getattr_creates_function(self):
method test_make_module_getattr_imports_module (line 244) | def test_make_module_getattr_imports_module(self):
method test_make_module_getattr_with_nested_module (line 253) | def test_make_module_getattr_with_nested_module(self):
class TestCheckModuleVersion (line 262) | class TestCheckModuleVersion:
method test_check_module_version_with_installed_module (line 265) | def test_check_module_version_with_installed_module(self):
method test_check_module_version_with_higher_required_version (line 271) | def test_check_module_version_with_higher_required_version(self):
method test_check_module_version_with_nonexistent_module (line 277) | def test_check_module_version_with_nonexistent_module(self):
method test_check_module_version_exact_match (line 282) | def test_check_module_version_exact_match(self):
method test_check_module_version_with_builtin_module (line 288) | def test_check_module_version_with_builtin_module(self):
class TestCheckFile (line 295) | class TestCheckFile:
method test_check_file_with_valid_py_file (line 298) | def test_check_file_with_valid_py_file(self):
method test_check_file_with_valid_py3_file (line 309) | def test_check_file_with_valid_py3_file(self):
method test_check_file_with_invalid_extension (line 320) | def test_check_file_with_invalid_extension(self):
method test_check_file_with_no_extension (line 332) | def test_check_file_with_no_extension(self):
method test_check_file_with_nonexistent_file (line 344) | def test_check_file_with_nonexistent_file(self):
method test_check_file_with_json_extension (line 352) | def test_check_file_with_json_extension(self):
class TestUtilsEdgeCases (line 365) | class TestUtilsEdgeCases:
method test_utc_now_format_consistency (line 368) | def test_utc_now_format_consistency(self):
method test_timestamp_utc_with_large_timestamp (line 379) | def test_timestamp_utc_with_large_timestamp(self):
method test_wrap_user_function_with_multiple_exceptions (line 389) | async def test_wrap_user_function_with_multiple_exceptions(
method test_check_file_with_relative_path (line 406) | def test_check_file_with_relative_path(self):
method test_check_file_with_absolute_path (line 418) | def test_check_file_with_absolute_path(self):
method test_make_module_getattr_with_empty_registry (line 429) | def test_make_module_getattr_with_empty_registry(self):
method test_wrap_user_function_with_default_args (line 438) | async def test_wrap_user_function_with_default_args(self, mock_chainli...
FILE: cypress.config.ts
constant CHAINLIT_APP_PORT (line 6) | const CHAINLIT_APP_PORT = 8000;
function killChainlit (line 8) | async function killChainlit() {
method setupNodeEvents (line 37) | async setupNodeEvents(on, config) {
FILE: cypress/e2e/action/main.py
function on_test_action (line 5) | async def on_test_action():
function on_removable_action (line 10) | async def on_removable_action(action: cl.Action):
function on_multiple_actions (line 16) | async def on_multiple_actions(action: cl.Action):
function on_all_actions_removed (line 22) | async def on_all_actions_removed(_: cl.Action):
function main (line 29) | async def main():
FILE: cypress/e2e/ask_custom_element/main.py
function on_start (line 5) | async def on_start():
FILE: cypress/e2e/ask_custom_element/public/elements/JiraTicket.jsx
function JiraTicket (line 9) | function JiraTicket() {
FILE: cypress/e2e/ask_file/main.py
function start (line 7) | async def start():
FILE: cypress/e2e/ask_multiple_files/main.py
function start (line 5) | async def start():
FILE: cypress/e2e/ask_user/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/audio_element/main.py
function start (line 12) | async def start():
FILE: cypress/e2e/auth/main.py
function custom_auth (line 15) | async def custom_auth(request: Request) -> Response:
function custom_token_auth (line 25) | async def custom_token_auth() -> Response:
function on_chat_start (line 45) | async def on_chat_start():
function on_message (line 51) | async def on_message(msg: cl.Message):
FILE: cypress/e2e/auth/spec.cy.ts
function login (line 3) | function login() {
function getToken (line 11) | function getToken() {
function shouldShowGreetingMessage (line 19) | function shouldShowGreetingMessage() {
function shouldSendMessageAndRecieveAnswer (line 26) | function shouldSendMessageAndRecieveAnswer() {
FILE: cypress/e2e/blinking_cursor/main.py
function main (line 5) | async def main():
function tool (line 10) | async def tool():
function on_message (line 16) | async def on_message(message: cl.Message):
FILE: cypress/e2e/chat_context/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/chat_prefill/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/chat_profiles/main.py
function chat_profile (line 23) | async def chat_profile(current_user: cl.User):
function auth_callback (line 50) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
function on_message (line 58) | async def on_message():
FILE: cypress/e2e/chat_settings/main.py
function start (line 6) | async def start():
function setup_agent (line 65) | async def setup_agent(settings):
FILE: cypress/e2e/command/main.py
function start (line 28) | async def start():
function message (line 33) | async def message(msg: cl.Message):
FILE: cypress/e2e/config_overrides/main.py
function chat_profile (line 29) | async def chat_profile(current_user: cl.User):
function auth_callback (line 70) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
function on_message (line 78) | async def on_message():
FILE: cypress/e2e/context/main.py
function async_function_from_sync (line 6) | async def async_function_from_sync():
function sync_function (line 11) | def sync_function():
function async_function (line 17) | async def async_function():
function another_async_function (line 21) | async def another_async_function():
function main (line 27) | async def main():
FILE: cypress/e2e/copilot/main.py
function on_chat_start (line 5) | async def on_chat_start():
function on_message (line 10) | async def on_message(msg: cl.Message):
FILE: cypress/e2e/custom_build/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/custom_data_layer/sql_alchemy.py
function data_layer (line 16) | def data_layer():
function main (line 23) | async def main():
function handle_message (line 28) | async def handle_message():
function auth_callback (line 34) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
FILE: cypress/e2e/custom_element/main.py
function on_test_action (line 5) | async def on_test_action():
function on_start (line 11) | async def on_start():
FILE: cypress/e2e/custom_element/public/elements/Counter.jsx
function Counter (line 4) | function Counter() {
FILE: cypress/e2e/custom_element/spec.cy.ts
function getCustomElement (line 2) | function getCustomElement() {
FILE: cypress/e2e/custom_element_auth/main.py
function auth_callback (line 9) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
function on_start (line 17) | async def on_start():
FILE: cypress/e2e/custom_element_command/main.py
function on_start (line 5) | async def on_start():
function on_message (line 13) | async def on_message(message: cl.Message):
FILE: cypress/e2e/custom_element_command/public/elements/Commander.jsx
function Commander (line 3) | function Commander() {
FILE: cypress/e2e/custom_theme/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/data_layer/main.py
function save_thread_history (line 85) | async def save_thread_history():
class TestDataLayer (line 95) | class TestDataLayer(cl_data.BaseDataLayer):
method get_user (line 96) | async def get_user(self, identifier: str):
method create_user (line 103) | async def create_user(self, user: cl.User):
method update_thread (line 114) | async def update_thread(
method create_step (line 149) | async def create_step(self, step_dict: StepDict):
method get_thread_author (line 160) | async def get_thread_author(self, thread_id: str):
method list_threads (line 164) | async def list_threads(
method get_thread (line 172) | async def get_thread(self, thread_id: str):
method delete_thread (line 179) | async def delete_thread(self, thread_id: str):
method delete_feedback (line 182) | async def delete_feedback(
method upsert_feedback (line 188) | async def upsert_feedback(
method create_element (line 195) | async def create_element(self, element: "Element"):
method get_element (line 201) | async def get_element(
method delete_element (line 207) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method update_step (line 211) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 215) | async def delete_step(self, step_id: str):
method get_favorite_steps (line 218) | async def get_favorite_steps(self, user_id: str) -> List["StepDict"]:
method build_debug_url (line 221) | async def build_debug_url(self) -> str:
method close (line 224) | async def close(self) -> None:
function data_layer (line 229) | def data_layer():
function send_count (line 233) | async def send_count():
function main (line 239) | async def main():
function handle_message (line 247) | async def handle_message():
function auth_callback (line 260) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
function on_chat_resume (line 270) | async def on_chat_resume(thread: ThreadDict):
FILE: cypress/e2e/data_layer/spec.cy.ts
constant SELECTORS (line 7) | const SELECTORS = {
FILE: cypress/e2e/dataframe/main.py
function start (line 7) | async def start():
FILE: cypress/e2e/edit_message/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/elements/main.py
function gen_img (line 13) | async def gen_img():
function start (line 18) | async def start():
FILE: cypress/e2e/error_handling/main.py
function main (line 5) | def main():
FILE: cypress/e2e/file_element/main.py
function start (line 20) | async def start():
FILE: cypress/e2e/header_auth/main.py
function header_auth_callback (line 10) | async def header_auth_callback(headers) -> Optional[cl.User]:
function on_chat_start (line 18) | async def on_chat_start():
FILE: cypress/e2e/llama_index_cb/main.py
function start (line 9) | async def start():
FILE: cypress/e2e/modes/main.py
function start (line 7) | async def start():
function on_message (line 63) | async def on_message(message: cl.Message):
FILE: cypress/e2e/on_chat_start/main.py
function start (line 5) | async def start():
FILE: cypress/e2e/password_auth/main.py
function auth_callback (line 10) | def auth_callback(username: str, password: str) -> Optional[cl.User]:
function on_chat_start (line 18) | async def on_chat_start():
FILE: cypress/e2e/plotly/main.py
function start (line 7) | async def start():
FILE: cypress/e2e/pyplot/main.py
function start (line 7) | async def start():
FILE: cypress/e2e/readme/main.py
function on_message (line 5) | async def on_message(msg):
FILE: cypress/e2e/readme/spec.cy.ts
function openReadme (line 1) | function openReadme() {
method onBeforeLoad (line 13) | onBeforeLoad(win) {
method onBeforeLoad (line 25) | onBeforeLoad(win) {
FILE: cypress/e2e/remove_elements/main.py
function start (line 16) | async def start():
FILE: cypress/e2e/remove_step/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/sidebar/main.py
function start (line 13) | async def start():
function message (line 26) | async def message(msg: cl.Message):
FILE: cypress/e2e/starters/main.py
function starters (line 5) | async def starters():
function on_message (line 14) | async def on_message(msg: cl.Message):
FILE: cypress/e2e/starters_categories/main.py
function starter_categories (line 7) | async def starter_categories(user: Optional[cl.User] = None):
function on_message (line 26) | async def on_message(msg: cl.Message):
FILE: cypress/e2e/step/main_async.py
function tool_3 (line 4) | async def tool_3():
function tool_2 (line 11) | async def tool_2():
function tool_1 (line 18) | async def tool_1():
function main (line 24) | async def main(message: cl.Message):
FILE: cypress/e2e/step/main_sync.py
function tool_3 (line 4) | def tool_3():
function tool_2 (line 11) | def tool_2():
function tool_1 (line 18) | def tool_1():
function main (line 24) | async def main(message: cl.Message):
FILE: cypress/e2e/step/tests.ts
function tests (line 3) | function tests() {
FILE: cypress/e2e/stop_task/main_async.py
function message (line 5) | async def message(message: cl.Message):
FILE: cypress/e2e/stop_task/main_sync.py
function sync_function (line 6) | def sync_function():
function message (line 11) | async def message(message: cl.Message):
FILE: cypress/e2e/stop_task/tests.ts
function tests (line 3) | function tests() {
FILE: cypress/e2e/streaming/main.py
function main (line 9) | async def main():
FILE: cypress/e2e/streaming/spec.cy.ts
function messageStream (line 3) | function messageStream(index: number) {
function toolStream (line 10) | function toolStream(tool: string) {
FILE: cypress/e2e/tasklist/main.py
function on_message (line 30) | async def on_message():
function main (line 37) | async def main():
FILE: cypress/e2e/thread_resume/main.py
class MemoryDataLayer (line 26) | class MemoryDataLayer(cl_data.BaseDataLayer):
method get_user (line 27) | async def get_user(self, identifier: str):
method create_user (line 30) | async def create_user(self, user: cl.User):
method delete_feedback (line 35) | async def delete_feedback(
method upsert_feedback (line 41) | async def upsert_feedback(
method create_element (line 47) | async def create_element(self, element: "Element"):
method get_element (line 50) | async def get_element(
method delete_element (line 55) | async def delete_element(self, element_id: str, thread_id: Optional[st...
method create_step (line 58) | async def create_step(self, step_dict: "StepDict"):
method update_step (line 61) | async def update_step(self, step_dict: "StepDict"):
method delete_step (line 64) | async def delete_step(self, step_id: str):
method get_thread_author (line 67) | async def get_thread_author(self, thread_id: str) -> str:
method delete_thread (line 70) | async def delete_thread(self, thread_id: str):
method list_threads (line 74) | async def list_threads(
method get_thread (line 84) | async def get_thread(self, thread_id: str) -> "Optional[ThreadDict]":
method update_thread (line 91) | async def update_thread(
method get_favorite_steps (line 118) | async def get_favorite_steps(self, user_id: str) -> List["StepDict"]:
method build_debug_url (line 121) | async def build_debug_url(self) -> str:
method close (line 124) | async def close(self) -> None:
function data_layer (line 129) | def data_layer():
function auth (line 134) | def auth(username: str, password: str) -> Optional[cl.User]:
function start (line 141) | async def start():
function on_resume (line 146) | async def on_resume(thread: ThreadDict):
function on_message (line 151) | async def on_message(msg: cl.Message):
FILE: cypress/e2e/update_step/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/upload_attachments/main.py
function main (line 5) | async def main(message: cl.Message):
FILE: cypress/e2e/user_env/main.py
function main (line 5) | async def main():
FILE: cypress/e2e/user_session/main.py
function main (line 5) | async def main(message: cl.Message):
FILE: cypress/e2e/user_session/spec.cy.ts
function newSession (line 3) | function newSession() {
FILE: cypress/e2e/window_message/main.py
function window_message (line 5) | async def window_message(message: str):
function message (line 11) | async def message(message: str):
FILE: cypress/fixtures/hello.cpp
function main (line 5) | int main() {
FILE: cypress/support/testUtils.ts
function submitMessage (line 11) | function submitMessage(message: string) {
function openHistory (line 19) | function openHistory() {
function closeHistory (line 23) | function closeHistory() {
function loadCopilotScript (line 27) | function loadCopilotScript() {
function mountCopilotWidget (line 46) | function mountCopilotWidget(widgetConfig?: Partial<IWidgetConfig>) {
function colilotShouldBeClosed (line 59) | function colilotShouldBeClosed() {
function copilotShouldBeOpen (line 68) | function copilotShouldBeOpen() {
function openCopilot (line 77) | function openCopilot() {
function getCopilotThreadId (line 87) | function getCopilotThreadId() {
function clearCopilotThreadId (line 94) | function clearCopilotThreadId(newThreadId?: string) {
constant SOCKET_IO_EVENT_PREFIX (line 101) | const SOCKET_IO_EVENT_PREFIX = '42';
constant SOCKET_IO_PREFIX_LENGTH (line 102) | const SOCKET_IO_PREFIX_LENGTH = 2;
function setupWebSocketListener (line 104) | function setupWebSocketListener(
FILE: frontend/src/App.tsx
type Window (line 17) | interface Window {
function App (line 27) | function App() {
FILE: frontend/src/AppWrapper.tsx
function AppWrapper (line 13) | function AppWrapper() {
FILE: frontend/src/api/index.ts
class ExtendedChainlitAPI (line 27) | class ExtendedChainlitAPI extends ChainlitAPI {
method shareThread (line 28) | async shareThread(
method connectStreamableHttpMCP (line 39) | connectStreamableHttpMCP(
FILE: frontend/src/components/Alert.tsx
type AlertVariant (line 4) | type AlertVariant = 'info' | 'error';
type AlertProps (line 6) | interface AlertProps {
FILE: frontend/src/components/AudioPresence.tsx
type Props (line 8) | interface Props {
function AudioPresence (line 16) | function AudioPresence({
FILE: frontend/src/components/AutoResizeTextarea.tsx
type Props (line 6) | interface Props extends Omit<React.ComponentProps<'textarea'>, 'onPaste'> {
FILE: frontend/src/components/AutoResumeThread.tsx
type Props (line 13) | interface Props {
function AutoResumeThread (line 17) | function AutoResumeThread({ id }: Props) {
FILE: frontend/src/components/BlinkingCursor.tsx
constant CURSOR_PLACEHOLDER (line 3) | const CURSOR_PLACEHOLDER = '\u200B';
type Props (line 5) | interface Props {
function BlinkingCursor (line 9) | function BlinkingCursor({ whitespace }: Props) {
FILE: frontend/src/components/ButtonLink.tsx
type ButtonLinkProps (line 13) | interface ButtonLinkProps {
function ButtonLink (line 21) | function ButtonLink({
FILE: frontend/src/components/ChatSettings/ChatSettingsSidebar.tsx
function ChatSettingsSidebar (line 32) | function ChatSettingsSidebar() {
FILE: frontend/src/components/ChatSettings/CheckboxInput.tsx
type CheckboxInputProps (line 14) | interface CheckboxInputProps extends IInput {
FILE: frontend/src/components/ChatSettings/DatePickerInput.tsx
type DatePickerBaseProps (line 72) | interface DatePickerBaseProps extends IInput {
type DatePickerSharedProps (line 133) | interface DatePickerSharedProps {
type DatePickerSingleProps (line 145) | interface DatePickerSingleProps extends IInput, DatePickerSharedProps {
type DatePickerRangeProps (line 211) | interface DatePickerRangeProps extends IInput, DatePickerSharedProps {
type DatePickerInputProps (line 324) | interface DatePickerInputProps extends IInput, DatePickerSharedProps {
FILE: frontend/src/components/ChatSettings/FormInput.tsx
type TFormInputValue (line 13) | type TFormInputValue = string | number | boolean | string[] | undefined;
type IFormInput (line 15) | interface IFormInput<T, V extends TFormInputValue> extends IInput {
type TFormInput (line 22) | type TFormInput =
FILE: frontend/src/components/ChatSettings/InputLabel.tsx
type InputLabelProps (line 13) | interface InputLabelProps {
FILE: frontend/src/components/ChatSettings/InputStateHandler.tsx
type NotificationsProps (line 14) | interface NotificationsProps {
type InputProps (line 19) | interface InputProps {
type InputStateHandlerProps (line 29) | interface InputStateHandlerProps extends InputProps {
FILE: frontend/src/components/ChatSettings/MultiSelectInput.tsx
type SelectItemType (line 17) | interface SelectItemType {
type MultiSelectInputProps (line 24) | interface MultiSelectInputProps extends IInput {
FILE: frontend/src/components/ChatSettings/NotificationCount.tsx
type NotificationCountProps (line 5) | interface NotificationCountProps {
FILE: frontend/src/components/ChatSettings/RadioButtonGroup.tsx
type RadioItemType (line 9) | interface RadioItemType {
type RadioButtonGroupProps (line 14) | interface RadioButtonGroupProps extends IInput {
FILE: frontend/src/components/ChatSettings/SelectInput.tsx
type SelectItemType (line 14) | interface SelectItemType {
type SelectInputProps (line 21) | interface SelectInputProps extends IInput {
FILE: frontend/src/components/ChatSettings/SliderInput.tsx
type IInput (line 7) | interface IInput {
type SliderInputProps (line 15) | interface SliderInputProps extends IInput {
FILE: frontend/src/components/ChatSettings/SwitchInput.tsx
type InputStateProps (line 8) | interface InputStateProps {
type SwitchInputProps (line 17) | interface SwitchInputProps extends InputStateProps {
FILE: frontend/src/components/ChatSettings/TagsInput.tsx
type TagsInputProps (line 11) | type TagsInputProps = {
FILE: frontend/src/components/ChatSettings/TextInput.tsx
type TextInputProps (line 8) | interface TextInputProps
FILE: frontend/src/components/ChatSettings/index.tsx
function ChatSettingsModal (line 29) | function ChatSettingsModal() {
FILE: frontend/src/components/CodeSnippet.tsx
type CodeSnippetProps (line 11) | interface CodeSnippetProps {
type CodeProps (line 45) | interface CodeProps {
function CodeSnippet (line 59) | function CodeSnippet({ ...props }: CodeProps) {
FILE: frontend/src/components/CopyButton.tsx
type Props (line 14) | interface Props {
FILE: frontend/src/components/ElementSideView.tsx
function ElementSideView (line 22) | function ElementSideView() {
FILE: frontend/src/components/ElementView.tsx
type ElementViewProps (line 10) | interface ElementViewProps {
FILE: frontend/src/components/Elements/Dataframe.tsx
type DataframeData (line 35) | interface DataframeData {
function DataframeElement (line 177) | function DataframeElement({ element }: { element: IDataframeElement }) {
FILE: frontend/src/components/Elements/ElementRef.tsx
type ElementRefProps (line 6) | interface ElementRefProps {
FILE: frontend/src/components/Elements/LazyDataframe.tsx
type Props (line 7) | interface Props {
FILE: frontend/src/components/Elements/PDF.tsx
type Props (line 3) | interface Props {
FILE: frontend/src/components/Elements/Plotly.tsx
type Props (line 12) | interface Props {
FILE: frontend/src/components/Elements/Text.tsx
type TextElementProps (line 9) | interface TextElementProps {
FILE: frontend/src/components/Elements/index.tsx
type ElementProps (line 13) | interface ElementProps {
FILE: frontend/src/components/ErrorBoundary.tsx
type Props (line 5) | interface Props {
type State (line 10) | interface State {
class ErrorBoundary (line 15) | class ErrorBoundary extends Component<Props, State> {
method getDerivedStateFromError (line 21) | public static getDerivedStateFromError(err: Error): State {
method componentDidCatch (line 26) | public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
method render (line 30) | public render() {
FILE: frontend/src/components/Icon.tsx
type Props (line 3) | interface Props {
FILE: frontend/src/components/Kbd.tsx
type KbdProps (line 8) | type KbdProps = React.HTMLAttributes<HTMLElement> & {
FILE: frontend/src/components/LeftSidebar/Search.tsx
function SearchChats (line 31) | function SearchChats() {
FILE: frontend/src/components/LeftSidebar/ThreadHistory.tsx
constant BATCH_SIZE (line 20) | const BATCH_SIZE = 35;
function ThreadHistory (line 23) | function ThreadHistory() {
FILE: frontend/src/components/LeftSidebar/ThreadList.tsx
type ThreadListProps (line 63) | interface ThreadListProps {
function ThreadList (line 70) | function ThreadList({
FILE: frontend/src/components/LeftSidebar/ThreadOptions.tsx
type Props (line 15) | interface Props {
function ThreadOptions (line 22) | function ThreadOptions({
FILE: frontend/src/components/LeftSidebar/index.tsx
function LeftSidebar (line 10) | function LeftSidebar({
FILE: frontend/src/components/Loader.tsx
type LoaderProps (line 4) | interface LoaderProps {
FILE: frontend/src/components/LoginForm.tsx
type Props (line 16) | interface Props {
type FormValues (line 28) | interface FormValues {
function LoginForm (line 33) | function LoginForm({
FILE: frontend/src/components/Logo.tsx
type Props (line 8) | interface Props {
FILE: frontend/src/components/Markdown.tsx
type Props (line 37) | interface Props {
method code (line 145) | code(props) {
method pre (line 153) | pre({ children, ...props }: any) {
method a (line 156) | a({ children, ...props }) {
method blockquote (line 221) | blockquote(props) {
method em (line 229) | em(props) {
method strong (line 232) | strong(props) {
method hr (line 235) | hr() {
method ul (line 238) | ul(props) {
method ol (line 246) | ol(props) {
method h1 (line 254) | h1(props) {
method h2 (line 262) | h2(props) {
method h3 (line 270) | h3(props) {
method h4 (line 278) | h4(props) {
method p (line 286) | p(props) {
method table (line 295) | table({ children, ...props }) {
method thead (line 302) | thead({ children, ...props }) {
method tr (line 305) | tr({ children, ...props }) {
method th (line 308) | th({ children, ...props }) {
method td (line 311) | td({ children, ...props }) {
method tbody (line 314) | tbody({ children, ...props }) {
FILE: frontend/src/components/MarkdownAlert.tsx
type AlertProps (line 25) | interface AlertProps {
type AlertVariant (line 48) | type AlertVariant = (typeof AlertTypes)[number];
FILE: frontend/src/components/ProviderButton.tsx
function capitalizeFirstLetter (line 13) | function capitalizeFirstLetter(string: string) {
function getProviderName (line 17) | function getProviderName(provider: string) {
function renderProviderIcon (line 35) | function renderProviderIcon(provider: string) {
type ProviderButtonProps (line 59) | interface ProviderButtonProps {
FILE: frontend/src/components/QuiltedGrid.tsx
type QuiltedGridProps (line 18) | interface QuiltedGridProps<T extends IImageElement | IVideoElement> {
FILE: frontend/src/components/ReadOnlyThread.tsx
type Props (line 28) | type Props = {
FILE: frontend/src/components/Tasklist/Task.tsx
type ITask (line 5) | interface ITask {
type ITaskList (line 11) | interface ITaskList {
type TaskProps (line 16) | interface TaskProps {
FILE: frontend/src/components/Tasklist/index.tsx
type HeaderProps (line 11) | interface HeaderProps {
type TaskListProps (line 27) | interface TaskListProps {
FILE: frontend/src/components/ThemeProvider.tsx
type Theme (line 3) | type Theme = 'dark' | 'light' | 'system';
type ThemeProviderProps (line 5) | type ThemeProviderProps = {
type ThemeProviderState (line 11) | type ThemeProviderState = {
function applyThemeVariables (line 23) | function applyThemeVariables(variant: 'dark' | 'light') {
function ThemeProvider (line 37) | function ThemeProvider({
FILE: frontend/src/components/WaterMark.tsx
function WaterMark (line 4) | function WaterMark() {
FILE: frontend/src/components/chat/Footer.tsx
type Props (line 10) | interface Props {
function ChatFooter (line 18) | function ChatFooter({ showIfEmptyThread, ...props }: Props) {
FILE: frontend/src/components/chat/MessageComposer/Attachment.tsx
type AttachmentProps (line 12) | interface AttachmentProps {
FILE: frontend/src/components/chat/MessageComposer/CommandButtons.tsx
type Props (line 17) | interface Props {
type AnimatedCommandButtonProps (line 23) | interface AnimatedCommandButtonProps {
FILE: frontend/src/components/chat/MessageComposer/CommandPopoverButton.tsx
type Props (line 33) | interface Props {
FILE: frontend/src/components/chat/MessageComposer/FavoriteButton.tsx
constant TOOLTIP_DELAY_MS (line 33) | const TOOLTIP_DELAY_MS = 700;
type Props (line 35) | interface Props {
FILE: frontend/src/components/chat/MessageComposer/Input.tsx
type Props (line 24) | interface Props {
type InputMethods (line 36) | interface InputMethods {
FILE: frontend/src/components/chat/MessageComposer/Mcp/AddForm.tsx
type McpAddFormProps (line 23) | interface McpAddFormProps {
FILE: frontend/src/components/chat/MessageComposer/Mcp/AnimatedPlugIcon.tsx
type AnimatedPlugIconProps (line 4) | interface AnimatedPlugIconProps {
FILE: frontend/src/components/chat/MessageComposer/Mcp/List.tsx
type McpListProps (line 30) | interface McpListProps {
type McpItemProps (line 85) | interface McpItemProps {
type DeleteMcpButtonProps (line 152) | interface DeleteMcpButtonProps {
FILE: frontend/src/components/chat/MessageComposer/Mcp/index.tsx
type Props (line 27) | interface Props {
FILE: frontend/src/components/chat/MessageComposer/ModePicker.tsx
type Props (line 21) | interface Props {
FILE: frontend/src/components/chat/MessageComposer/SubmitButton.tsx
type SubmitButtonProps (line 18) | interface SubmitButtonProps {
function SubmitButton (line 23) | function SubmitButton({
FILE: frontend/src/components/chat/MessageComposer/UploadButton.tsx
type UploadButtonProps (line 15) | interface UploadButtonProps {
FILE: frontend/src/components/chat/MessageComposer/VoiceButton.tsx
type Props (line 19) | interface Props {
FILE: frontend/src/components/chat/MessageComposer/index.tsx
type Props (line 48) | interface Props {
function MessageComposer (line 55) | function MessageComposer({
FILE: frontend/src/components/chat/Messages/Message/AskFileButton.tsx
type UploadState (line 14) | interface UploadState {
type _AskFileButtonProps (line 21) | interface _AskFileButtonProps {
type AskFileButtonProps (line 180) | interface AskFileButtonProps {
FILE: frontend/src/components/chat/Messages/Message/Avatar.tsx
type Props (line 20) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Buttons/Actions/ActionButton.tsx
type ActionProps (line 22) | interface ActionProps {
FILE: frontend/src/components/chat/Messages/Message/Buttons/Actions/index.tsx
type Props (line 5) | interface Props {
function MessageActions (line 9) | function MessageActions({ actions }: Props) {
FILE: frontend/src/components/chat/Messages/Message/Buttons/DebugButton.tsx
type DebugButtonProps (line 13) | interface DebugButtonProps {
FILE: frontend/src/components/chat/Messages/Message/Buttons/FeedbackButtons.tsx
type FeedbackButtonsProps (line 30) | interface FeedbackButtonsProps {
function FeedbackButtons (line 34) | function FeedbackButtons({ message }: FeedbackButtonsProps) {
FILE: frontend/src/components/chat/Messages/Message/Buttons/index.tsx
type Props (line 14) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlineCustomElementList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedAudioList.tsx
type InlinedAudioListProps (line 5) | interface InlinedAudioListProps {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedDataframeList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedFileList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedImageList.tsx
type Props (line 6) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedPDFList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedPlotlyList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedTextList.tsx
type Props (line 6) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/InlinedVideoList.tsx
type Props (line 5) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/InlinedElements/index.tsx
type Props (line 15) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Content/index.tsx
type ContentSection (line 12) | type ContentSection = 'input' | 'output';
type Props (line 14) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/Step.tsx
type Props (line 14) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/UserMessage.tsx
type Props (line 22) | interface Props {
FILE: frontend/src/components/chat/Messages/Message/index.tsx
type Props (line 22) | interface Props {
constant EMPTY_ELEMENTS (line 32) | const EMPTY_ELEMENTS: IMessageElement[] = [];
FILE: frontend/src/components/chat/Messages/index.tsx
type Props (line 14) | interface Props {
constant CL_RUN_NAMES (line 23) | const CL_RUN_NAMES = ['on_chat_start', 'on_message', 'on_audio_end'];
FILE: frontend/src/components/chat/MessagesContainer/index.tsx
type Props (line 24) | interface Props {
FILE: frontend/src/components/chat/ScrollContainer.tsx
type Props (line 15) | interface Props {
function ScrollContainer (line 23) | function ScrollContainer({
FILE: frontend/src/components/chat/ScrollDownButton.tsx
type Props (line 5) | interface Props {
function ScrollDownButton (line 9) | function ScrollDownButton({ onClick }: Props) {
FILE: frontend/src/components/chat/Starter.tsx
type StarterProps (line 19) | interface StarterProps {
function Starter (line 23) | function Starter({ starter }: StarterProps) {
FILE: frontend/src/components/chat/StarterCategory.tsx
type Props (line 5) | interface Props {
function StarterCategory (line 11) | function StarterCategory({ category, isSelected, onClick }: Props) {
FILE: frontend/src/components/chat/Starters.tsx
type Props (line 9) | interface Props {
function Starters (line 13) | function Starters({ className }: Props) {
FILE: frontend/src/components/chat/WelcomeScreen.tsx
type Props (line 24) | interface Props {
function WelcomeScreen (line 31) | function WelcomeScreen(props: Props) {
FILE: frontend/src/components/header/ApiKeys.tsx
function ApiKeys (line 15) | function ApiKeys() {
FILE: frontend/src/components/header/ChatProfiles.tsx
type Props (line 27) | interface Props {
function ChatProfiles (line 31) | function ChatProfiles({ navigate }: Props) {
FILE: frontend/src/components/header/NewChat.tsx
type NewChatDialogProps (line 24) | type NewChatDialogProps = {
type Props (line 70) | interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
FILE: frontend/src/components/header/Readme.tsx
function ReadmeButton (line 16) | function ReadmeButton() {
FILE: frontend/src/components/header/Share.tsx
function ShareButton (line 16) | function ShareButton() {
FILE: frontend/src/components/header/SidebarTrigger.tsx
function SidebarTrigger (line 13) | function SidebarTrigger() {
FILE: frontend/src/components/header/ThemeToggle.tsx
type Props (line 14) | interface Props {
function ThemeToggle (line 18) | function ThemeToggle({ className }: Props) {
FILE: frontend/src/components/header/UserNav.tsx
function UserNav (line 18) | function UserNav() {
FILE: frontend/src/components/i18n/Translator.tsx
type options (line 7) | type options = TOptions<$Dictionary>;
type TranslatorProps (line 9) | type TranslatorProps = {
FILE: frontend/src/components/share/ShareDialog.tsx
type ShareDialogProps (line 21) | type ShareDialogProps = {
function ShareDialog (line 27) | function ShareDialog({
FILE: frontend/src/components/ui/badge.tsx
type BadgeProps (line 25) | interface BadgeProps
function Badge (line 29) | function Badge({ className, variant, ...props }: BadgeProps) {
FILE: frontend/src/components/ui/button.tsx
type ButtonProps (line 35) | interface ButtonProps
FILE: frontend/src/components/ui/calendar.tsx
function Calendar (line 12) | function Calendar({
function CalendarDayButton (line 173) | function CalendarDayButton({
FILE: frontend/src/components/ui/carousel.tsx
type CarouselApi (line 10) | type CarouselApi = UseEmblaCarouselType[1];
type UseCarouselParameters (line 11) | type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
type CarouselOptions (line 12) | type CarouselOptions = UseCarouselParameters[0];
type CarouselPlugin (line 13) | type CarouselPlugin = UseCarouselParameters[1];
type CarouselProps (line 15) | type CarouselProps = {
type CarouselContextProps (line 22) | type CarouselContextProps = {
function useCarousel (line 33) | function useCarousel() {
FILE: frontend/src/components/ui/form.tsx
type FormFieldContextValue (line 18) | type FormFieldContextValue<
type FormItemContextValue (line 65) | type FormItemContextValue = {
FILE: frontend/src/components/ui/pagination.tsx
type PaginationLinkProps (line 37) | type PaginationLinkProps = {
FILE: frontend/src/components/ui/radio-group.tsx
function RadioGroup (line 8) | function RadioGroup({
function RadioGroupItem (line 21) | function RadioGroupItem({
FILE: frontend/src/components/ui/sheet.tsx
type SheetContentProps (line 49) | interface SheetContentProps
FILE: frontend/src/components/ui/sidebar.tsx
constant SIDEBAR_COOKIE_NAME (line 21) | const SIDEBAR_COOKIE_NAME = 'sidebar:state';
constant SIDEBAR_COOKIE_MAX_AGE (line 22) | const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
constant SIDEBAR_WIDTH (line 23) | const SIDEBAR_WIDTH = '16rem';
constant SIDEBAR_WIDTH_MOBILE (line 24) | const SIDEBAR_WIDTH_MOBILE = '18rem';
constant SIDEBAR_WIDTH_ICON (line 25) | const SIDEBAR_WIDTH_ICON = '3rem';
constant SIDEBAR_KEYBOARD_SHORTCUT (line 26) | const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
type SidebarContext (line 28) | type SidebarContext = {
function useSidebar (line 40) | function useSidebar() {
FILE: frontend/src/components/ui/skeleton.tsx
function Skeleton (line 3) | function Skeleton({
FILE: frontend/src/components/ui/sonner.tsx
type ToasterProps (line 5) | type ToasterProps = React.ComponentProps<typeof Sonner>;
FILE: frontend/src/components/ui/tooltip.tsx
constant TOOLTIP_DELAY_MS (line 6) | const TOOLTIP_DELAY_MS = 500;
constant TOOLTIP_SKIP_DELAY_MS (line 7) | const TOOLTIP_SKIP_DELAY_MS = 0;
type ProviderProps (line 9) | type ProviderProps = React.ComponentProps<typeof TooltipPrimitive.Provid...
FILE: frontend/src/hooks/query.ts
function useQuery (line 4) | function useQuery() {
FILE: frontend/src/hooks/use-mobile.tsx
constant MOBILE_BREAKPOINT (line 3) | const MOBILE_BREAKPOINT = 768;
function useIsMobile (line 5) | function useIsMobile() {
FILE: frontend/src/hooks/useCommandNavigation.tsx
type UseCommandNavigationProps (line 3) | interface UseCommandNavigationProps {
FILE: frontend/src/hooks/usePlatform.ts
constant MOBILE_REGEX (line 3) | const MOBILE_REGEX =
type PlatformPayload (line 6) | type PlatformPayload = {
FILE: frontend/src/hooks/useUpload.tsx
type useUploadProps (line 11) | interface useUploadProps {
FILE: frontend/src/i18n/dateLocale.ts
function getDateFnsLocale (line 94) | function getDateFnsLocale(i18nLocale: string | undefined): Locale {
FILE: frontend/src/i18n/index.ts
function i18nSetupLocalization (line 9) | function i18nSetupLocalization(): void {
FILE: frontend/src/index.d.ts
type Array (line 7) | interface Array<T> {
FILE: frontend/src/lib/utils.ts
function cn (line 6) | function cn(...inputs: ClassValue[]) {
function hslToHex (line 18) | function hslToHex(hslStr: string): string {
FILE: frontend/src/pages/AuthCallback.tsx
function AuthCallback (line 6) | function AuthCallback() {
FILE: frontend/src/pages/Element.tsx
function Element (line 19) | function Element() {
FILE: frontend/src/pages/Env.tsx
type FormValues (line 42) | type FormValues = z.infer<typeof schema>;
FILE: frontend/src/pages/Home.tsx
function Home (line 5) | function Home() {
FILE: frontend/src/pages/Login.tsx
function Login (line 16) | function Login() {
FILE: frontend/src/pages/Page.tsx
type Props (line 16) | type Props = {
FILE: frontend/src/pages/Thread.tsx
function ThreadPage (line 18) | function ThreadPage() {
FILE: frontend/src/state/chat.ts
type IAttachment (line 5) | interface IAttachment {
FILE: frontend/src/types/Input.ts
type IInput (line 3) | interface IInput {
FILE: frontend/src/types/NotificationCount.tsx
type NotificationCountProps (line 1) | type NotificationCountProps = {
FILE: frontend/src/types/chat.ts
type IToken (line 3) | interface IToken {
type ISession (line 9) | interface ISession {
FILE: frontend/src/types/messageContext.ts
type IMessageContext (line 9) | interface IMessageContext {
FILE: frontend/tests/FavoriteButton.spec.tsx
method observe (line 46) | observe() {}
method unobserve (line 47) | unobserve() {}
method disconnect (line 48) | disconnect() {}
FILE: libs/copilot/index.tsx
type Window (line 24) | interface Window {
FILE: libs/copilot/src/ThemeProvider.tsx
type Theme (line 3) | type Theme = 'dark' | 'light' | 'system';
type ThemeProviderProps (line 5) | type ThemeProviderProps = {
type ThemeProviderState (line 11) | type ThemeProviderState = {
function applyThemeVariables (line 23) | function applyThemeVariables(variant: 'dark' | 'light') {
function ThemeProvider (line 38) | function ThemeProvider({
FILE: libs/copilot/src/api.ts
function makeApiClient (line 5) | function makeApiClient(
FILE: libs/copilot/src/app.tsx
type Props (line 17) | interface Props {
type Window (line 22) | interface Window {
function App (line 34) | function App({ widgetConfig }: Props) {
FILE: libs/copilot/src/appWrapper.tsx
type Props (line 12) | interface Props {
function AppWrapper (line 16) | function AppWrapper({ widgetConfig }: Props) {
FILE: libs/copilot/src/chat/index.tsx
function ChatWrapper (line 13) | function ChatWrapper() {
FILE: libs/copilot/src/components/ElementSideView.tsx
function ElementSideView (line 12) | function ElementSideView() {
FILE: libs/copilot/src/components/Header.tsx
type IProjectConfig (line 12) | interface IProjectConfig {
type Props (line 19) | interface Props {
FILE: libs/copilot/src/components/WelcomeScreen.tsx
function WelcomeScreen (line 7) | function WelcomeScreen() {
FILE: libs/copilot/src/lib/utils.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: libs/copilot/src/state.ts
constant COPILOT_THREAD_ID_KEY (line 4) | const COPILOT_THREAD_ID_KEY = 'chainlit-copilot-thread-id';
constant COPILOT_THREAD_CHANGED_EVENT_KEY (line 5) | const COPILOT_THREAD_CHANGED_EVENT_KEY =
class CopilotThreadChangedEventParams (line 7) | class CopilotThreadChangedEventParams {
FILE: libs/copilot/src/types.ts
type IWidgetConfig (line 1) | interface IWidgetConfig {
FILE: libs/copilot/src/widget.tsx
type Props (line 23) | interface Props {
FILE: libs/copilot/stories/App.stories.ts
type Story (line 19) | type Story = StoryObj<typeof meta>;
FILE: libs/react-client/src/api/hooks/api.ts
function useApi (line 48) | function useApi<T>(
FILE: libs/react-client/src/api/hooks/auth/types.ts
type JWTPayload (line 3) | interface JWTPayload extends IUser {
type AuthState (line 7) | interface AuthState {
type AuthActions (line 14) | interface AuthActions {
type IUseAuth (line 19) | type IUseAuth = AuthState & AuthActions;
FILE: libs/react-client/src/api/index.tsx
type IThreadFilters (line 9) | interface IThreadFilters {
type IPageInfo (line 14) | interface IPageInfo {
type IPagination (line 19) | interface IPagination {
class ClientError (line 24) | class ClientError extends Error {
method constructor (line 28) | constructor(message: string, status: number, detail?: string) {
method toString (line 34) | toString() {
type Payload (line 43) | type Payload = FormData | any;
class APIBase (line 45) | class APIBase {
method constructor (line 46) | constructor(
method buildEndpoint (line 54) | buildEndpoint(path: string) {
method getDetailFromErrorResponse (line 73) | private async getDetailFromErrorResponse(
method handleRequestError (line 85) | private handleRequestError(error: any) {
method fetch (line 115) | async fetch(
method get (line 153) | async get(endpoint: string) {
method post (line 157) | async post(endpoint: string, data: Payload, signal?: AbortSignal) {
method put (line 161) | async put(endpoint: string, data: Payload) {
method patch (line 165) | async patch(endpoint: string, data: Payload) {
method delete (line 169) | async delete(endpo
Condensed preview — 588 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,362K chars).
[
{
"path": ".editorconfig",
"chars": 186,
"preview": "root = true\n\n[*]\nend_of_line = lf\n\n[*.{py,ts,tsx}]\nindent_style = space\ninsert_final_newline = true\n\n[*.py]\nindent_size "
},
{
"path": ".eslintignore",
"chars": 17,
"preview": "node_modules\ndist"
},
{
"path": ".eslintrc",
"chars": 652,
"preview": "{\n \"root\": true,\n \"parser\": \"@typescript-eslint/parser\",\n \"ignorePatterns\": [\"**/*.jsx\"],\n \"plugins\": [\"@typescript-"
},
{
"path": ".github/CODEOWNERS",
"chars": 37,
"preview": "* @hayescode @asvishnyakov @sandangel"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 851,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: needs-triage\nassignees: ''\ntype: 'Bug'\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 620,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: needs-triage\nassignees: ''\ntype: 'Fe"
},
{
"path": ".github/actions/pnpm-node-install/action.yaml",
"chars": 713,
"preview": "name: Install Node, pnpm and dependencies.\ndescription: Install Node, pnpm and dependencies using cache.\n\ninputs:\n node"
},
{
"path": ".github/actions/uv-python-install/action.yaml",
"chars": 1076,
"preview": "name: Install Python, uv and dependencies.\ndescription: Install Python, uv and project dependencies using cache\n\ninputs:"
},
{
"path": ".github/copilot-instructions.md",
"chars": 5982,
"preview": "# Chainlit Development Instructions\n\nChainlit is a Python framework for building conversational AI applications with Pyt"
},
{
"path": ".github/workflows/ci.yaml",
"chars": 1098,
"preview": "name: CI\n\non:\n workflow_call:\n workflow_dispatch:\n merge_group:\n pull_request:\n branches: [main, dev, 'release/**"
},
{
"path": ".github/workflows/close_stale.yml",
"chars": 1243,
"preview": "name: Close inactive issues and pull requests\non:\n schedule:\n - cron: \"30 1 * * *\"\n workflow_dispatch:\n \njobs:\n c"
},
{
"path": ".github/workflows/copilot-setup-steps.yaml",
"chars": 1819,
"preview": "name: \"Copilot Setup Steps\"\n\n# Automatically run the setup steps when they are changed to allow for easy validation, and"
},
{
"path": ".github/workflows/e2e-tests.yaml",
"chars": 1199,
"preview": "name: E2ETests\n\non: [workflow_call]\n\npermissions: read-all\n\njobs:\n ci:\n runs-on: ${{ matrix.os }}\n strategy:\n "
},
{
"path": ".github/workflows/lint-backend.yaml",
"chars": 922,
"preview": "name: LintBackend\n\non: [workflow_call]\n\npermissions: read-all\n\njobs:\n lint-backend:\n runs-on: ubuntu-latest\n env:"
},
{
"path": ".github/workflows/lint-ui.yaml",
"chars": 347,
"preview": "name: LintUI\n\non: [workflow_call]\n\npermissions: read-all\n\njobs:\n ci:\n runs-on: ubuntu-latest\n steps:\n - uses"
},
{
"path": ".github/workflows/publish-libs.yaml",
"chars": 1709,
"preview": "name: Publish libs\n\non:\n workflow_dispatch:\n inputs:\n dry_run:\n description: 'Dry run (test publishing)'"
},
{
"path": ".github/workflows/publish.yaml",
"chars": 2785,
"preview": "name: Publish\n\non:\n workflow_dispatch:\n inputs:\n use_testpypi:\n description: 'Publish to TestPyPI instea"
},
{
"path": ".github/workflows/pytest.yaml",
"chars": 897,
"preview": "name: Pytest\n\non: [workflow_call]\n\npermissions: read-all\n\njobs:\n pytest:\n runs-on: ubuntu-latest\n strategy:\n "
},
{
"path": ".gitignore",
"chars": 549,
"preview": "build\ndist\n\n*.egg-info\n\n.env\n\n*.files\n\nvenv\n.venv\n.DS_Store\n\n**/.chainlit/*\nchainlit.md\n\ncypress/screenshots\ncypress/vid"
},
{
"path": ".husky/pre-commit",
"chars": 17,
"preview": "pnpm lint-staged\n"
},
{
"path": ".npmrc",
"chars": 154,
"preview": "shared-workspace-lockfile=false\npublic-hoist-pattern[]=*eslint*\npublic-hoist-pattern[]=*prettier*\npublic-hoist-pattern[]"
},
{
"path": ".prettierrc",
"chars": 412,
"preview": "{\n \"semi\": true,\n \"trailingComma\": \"none\",\n \"singleQuote\": true,\n \"printWidth\": 80,\n \"plugins\": [\"@trivago/prettier"
},
{
"path": "CHANGELOG.md",
"chars": 54876,
"preview": "# Changelog\n\nAll notable changes to Chainlit will be documented in this file.\n\nThe format is based on [Keep a Changelog]"
},
{
"path": "CONTRIBUTING.md",
"chars": 5276,
"preview": "# Contribute to Chainlit\n\nTo contribute to Chainlit, you first need to set up the project on your local machine.\n\n## Tab"
},
{
"path": "LICENSE",
"chars": 11413,
"preview": "Copyright 2023- The Chainlit team. All rights reserved.\n\n Apache License\n "
},
{
"path": "PRIVACY_POLICY.md",
"chars": 87,
"preview": "# Privacy Policy\n\nChainlit doesn't collect any data from its users after 2.6.1 release."
},
{
"path": "RELENG.md",
"chars": 2046,
"preview": "# Release Engineering Instructions\n\nThis document outlines the steps for maintainers to create a new release of the proj"
},
{
"path": "backend/build.py",
"chars": 3479,
"preview": "\"\"\"Build script gets called on uv/pip build.\"\"\"\n\nimport pathlib\nimport shutil\nimport subprocess\nimport sys\n\nfrom hatchli"
},
{
"path": "backend/chainlit/__init__.py",
"chars": 5121,
"preview": "import os\n\nfrom dotenv import load_dotenv\n\n# ruff: noqa: E402\n# Keep this here to ensure imports have environment availa"
},
{
"path": "backend/chainlit/__main__.py",
"chars": 87,
"preview": "from chainlit.cli import cli\n\nif __name__ == \"__main__\":\n cli(prog_name=\"chainlit\")\n"
},
{
"path": "backend/chainlit/_utils.py",
"chars": 289,
"preview": "\"\"\"Util functions which are explicitly not part of the public API.\"\"\"\n\nfrom pathlib import Path\n\n\ndef is_path_inside(chi"
},
{
"path": "backend/chainlit/action.py",
"chars": 1085,
"preview": "import uuid\nfrom typing import Dict, Optional\n\nfrom dataclasses_json import DataClassJsonMixin\nfrom pydantic import Fiel"
},
{
"path": "backend/chainlit/auth/__init__.py",
"chars": 3032,
"preview": "import os\n\nfrom fastapi import Depends, HTTPException\n\nfrom chainlit.config import config\nfrom chainlit.data import get_"
},
{
"path": "backend/chainlit/auth/cookie.py",
"chars": 6175,
"preview": "import os\nfrom typing import Literal, Optional, cast\n\nfrom fastapi import Request, Response\nfrom fastapi.exceptions impo"
},
{
"path": "backend/chainlit/auth/jwt.py",
"chars": 1004,
"preview": "import os\nfrom datetime import datetime, timedelta, timezone\nfrom typing import Any, Dict, Optional\n\nimport jwt as pyjwt"
},
{
"path": "backend/chainlit/cache.py",
"chars": 1389,
"preview": "import importlib.util\nimport os\nimport threading\nfrom typing import Any\n\nfrom chainlit.config import config\nfrom chainli"
},
{
"path": "backend/chainlit/callbacks.py",
"chars": 16600,
"preview": "import inspect\nfrom typing import Any, Awaitable, Callable, Dict, List, Optional, Union, overload\n\nfrom fastapi import R"
},
{
"path": "backend/chainlit/chat_context.py",
"chars": 1848,
"preview": "from typing import TYPE_CHECKING, Dict, List\n\nfrom chainlit.context import context\n\nif TYPE_CHECKING:\n from chainlit."
},
{
"path": "backend/chainlit/chat_settings.py",
"chars": 1259,
"preview": "from typing import Any, List\n\nfrom pydantic import Field\nfrom pydantic.dataclasses import dataclass\n\nfrom chainlit.conte"
},
{
"path": "backend/chainlit/cli/__init__.py",
"chars": 6377,
"preview": "import asyncio\nimport logging\nimport os\nimport sys\n\nimport click\nimport nest_asyncio\nimport uvicorn\n\n# Not sure if it is"
},
{
"path": "backend/chainlit/config.py",
"chars": 23375,
"preview": "import json\nimport os\nimport site\nimport sys\nfrom importlib import util\nfrom pathlib import Path\nfrom typing import (\n "
},
{
"path": "backend/chainlit/context.py",
"chars": 3315,
"preview": "import asyncio\nimport uuid\nfrom contextvars import ContextVar\nfrom typing import TYPE_CHECKING, Dict, List, Optional, Un"
},
{
"path": "backend/chainlit/data/__init__.py",
"chars": 4575,
"preview": "import os\nimport warnings\nfrom typing import Optional\n\nfrom .base import BaseDataLayer\nfrom .utils import (\n queue_un"
},
{
"path": "backend/chainlit/data/acl.py",
"chars": 575,
"preview": "from fastapi import HTTPException\n\nfrom chainlit.data import get_data_layer\n\n\nasync def is_thread_author(username: str, "
},
{
"path": "backend/chainlit/data/base.py",
"chars": 3010,
"preview": "from abc import ABC, abstractmethod\nfrom typing import TYPE_CHECKING, Dict, List, Optional\n\nfrom chainlit.types import ("
},
{
"path": "backend/chainlit/data/chainlit_data_layer.py",
"chars": 26531,
"preview": "import json\nimport uuid\nfrom datetime import datetime\nfrom typing import TYPE_CHECKING, Any, Dict, List, Optional, Union"
},
{
"path": "backend/chainlit/data/dynamodb.py",
"chars": 23109,
"preview": "import asyncio\nimport json\nimport logging\nimport os\nimport random\nfrom dataclasses import asdict\nfrom datetime import da"
},
{
"path": "backend/chainlit/data/literalai.py",
"chars": 17810,
"preview": "import json\n\n# Deprecation warning for users of this provider\nimport sys\nimport warnings\nfrom typing import Dict, List, "
},
{
"path": "backend/chainlit/data/sql_alchemy.py",
"chars": 39755,
"preview": "import json\nimport ssl\nimport uuid\nfrom dataclasses import asdict\nfrom datetime import datetime\nfrom typing import TYPE_"
},
{
"path": "backend/chainlit/data/storage_clients/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "backend/chainlit/data/storage_clients/azure.py",
"chars": 2768,
"preview": "from typing import TYPE_CHECKING, Any, Dict, Optional, Union\n\nfrom azure.storage.filedatalake import (\n ContentSettin"
},
{
"path": "backend/chainlit/data/storage_clients/azure_blob.py",
"chars": 3670,
"preview": "from datetime import datetime, timedelta, timezone\nfrom typing import Any, Dict, Union\n\nfrom azure.storage.blob import B"
},
{
"path": "backend/chainlit/data/storage_clients/base.py",
"chars": 818,
"preview": "import os\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Dict, Union\n\nstorage_expiry_time = int(os.getenv(\""
},
{
"path": "backend/chainlit/data/storage_clients/gcs.py",
"chars": 3666,
"preview": "from typing import Any, Dict, Optional, Union\n\nfrom google.auth import default\nfrom google.cloud import storage # type:"
},
{
"path": "backend/chainlit/data/storage_clients/s3.py",
"chars": 3157,
"preview": "import os\nfrom typing import Any, Dict, Union\n\nimport boto3 # type: ignore\n\nfrom chainlit import make_async\nfrom chainl"
},
{
"path": "backend/chainlit/data/utils.py",
"chars": 966,
"preview": "import functools\nfrom collections import deque\n\nfrom chainlit.context import context\nfrom chainlit.session import Websoc"
},
{
"path": "backend/chainlit/discord/__init__.py",
"chars": 219,
"preview": "import importlib.util\n\nif importlib.util.find_spec(\"discord\") is None:\n raise ValueError(\n \"The discord packag"
},
{
"path": "backend/chainlit/discord/app.py",
"chars": 11423,
"preview": "import asyncio\nimport mimetypes\nimport re\nimport uuid\nfrom datetime import datetime\nfrom io import BytesIO\nfrom typing i"
},
{
"path": "backend/chainlit/element.py",
"chars": 13441,
"preview": "import json\nimport mimetypes\nimport uuid\nfrom enum import Enum\nfrom io import BytesIO\nfrom typing import (\n Any,\n "
},
{
"path": "backend/chainlit/emitter.py",
"chars": 16712,
"preview": "import asyncio\nimport uuid\nfrom typing import Any, Dict, List, Literal, Optional, Union, cast, get_args\n\nfrom socketio.e"
},
{
"path": "backend/chainlit/input_widget.py",
"chars": 12608,
"preview": "from abc import abstractmethod\nfrom datetime import date\nfrom typing import Any, Dict, List, Literal, Optional\n\nfrom pyd"
},
{
"path": "backend/chainlit/langchain/__init__.py",
"chars": 217,
"preview": "from chainlit.utils import check_module_version\n\nif not check_module_version(\"langchain\", \"0.0.198\"):\n raise ValueErr"
},
{
"path": "backend/chainlit/langchain/callbacks.py",
"chars": 24145,
"preview": "import time\nfrom typing import Any, Dict, List, Optional, Tuple, TypedDict, Union\nfrom uuid import UUID\n\nimport pydantic"
},
{
"path": "backend/chainlit/langflow/__init__.py",
"chars": 740,
"preview": "from chainlit.utils import check_module_version\n\nif not check_module_version(\"langflow\", \"0.1.4\"):\n raise ValueError("
},
{
"path": "backend/chainlit/llama_index/__init__.py",
"chars": 227,
"preview": "from chainlit.utils import check_module_version\n\nif not check_module_version(\"llama_index.core\", \"0.10.15\"):\n raise V"
},
{
"path": "backend/chainlit/llama_index/callbacks.py",
"chars": 7280,
"preview": "from typing import Any, Dict, List, Optional\n\nfrom literalai import ChatGeneration, CompletionGeneration, GenerationMess"
},
{
"path": "backend/chainlit/logger.py",
"chars": 218,
"preview": "import logging\n\nlogging.getLogger(\"socketio\").setLevel(logging.ERROR)\nlogging.getLogger(\"engineio\").setLevel(logging.ERR"
},
{
"path": "backend/chainlit/markdown.py",
"chars": 2118,
"preview": "import os\nfrom pathlib import Path\nfrom typing import Optional\n\nfrom chainlit.logger import logger\n\nfrom ._utils import "
},
{
"path": "backend/chainlit/mcp.py",
"chars": 3438,
"preview": "import shlex\nfrom typing import Dict, Literal, Optional, Union\n\nfrom pydantic import BaseModel\n\nfrom chainlit.config imp"
},
{
"path": "backend/chainlit/message.py",
"chars": 19167,
"preview": "import asyncio\nimport json\nimport time\nimport uuid\nfrom abc import ABC\nfrom typing import Dict, List, Optional, Union, c"
},
{
"path": "backend/chainlit/mistralai/__init__.py",
"chars": 1554,
"preview": "import asyncio\nfrom typing import Union\n\nfrom literalai import ChatGeneration, CompletionGeneration\n\nfrom chainlit.conte"
},
{
"path": "backend/chainlit/mode.py",
"chars": 2020,
"preview": "\"\"\"Mode and ModeOption dataclasses for the Modes system.\n\nThe Modes system allows developers to define multiple picker c"
},
{
"path": "backend/chainlit/oauth_providers.py",
"chars": 30630,
"preview": "import base64\nimport os\nimport urllib.parse\nfrom typing import Dict, List, Optional, Tuple\n\nimport httpx\nfrom fastapi im"
},
{
"path": "backend/chainlit/openai/__init__.py",
"chars": 1711,
"preview": "import asyncio\nfrom typing import Union\n\nfrom literalai import ChatGeneration, CompletionGeneration\n\nfrom chainlit.conte"
},
{
"path": "backend/chainlit/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "backend/chainlit/sample/hello.py",
"chars": 416,
"preview": "# This is a simple example of a chainlit app.\n\nfrom chainlit import AskUserMessage, Message, on_chat_start\n\n\n@on_chat_st"
},
{
"path": "backend/chainlit/sample/starters_demo.py",
"chars": 1965,
"preview": "from typing import Optional\n\nimport chainlit as cl\n\n\n@cl.set_starter_categories\nasync def starter_categories(user: Optio"
},
{
"path": "backend/chainlit/secret.py",
"chars": 293,
"preview": "import secrets\nimport string\n\n# Using punctuation, without chars that can break in the cli (quotes, backslash, backtick."
},
{
"path": "backend/chainlit/semantic_kernel/__init__.py",
"chars": 3805,
"preview": "from collections.abc import Awaitable, Callable\nfrom typing import TYPE_CHECKING, Any\n\nfrom pydantic import BaseModel\n\nf"
},
{
"path": "backend/chainlit/server.py",
"chars": 55182,
"preview": "import asyncio\nimport fnmatch\nimport glob\nimport json\nimport mimetypes\nimport os\nimport re\nimport shutil\nimport urllib.p"
},
{
"path": "backend/chainlit/session.py",
"chars": 11548,
"preview": "import asyncio\nimport json\nimport mimetypes\nimport re\nimport shutil\nimport uuid\nfrom contextlib import AsyncExitStack\nfr"
},
{
"path": "backend/chainlit/sidebar.py",
"chars": 1973,
"preview": "import asyncio\nfrom typing import List, Optional\n\nfrom chainlit.context import context\nfrom chainlit.element import Elem"
},
{
"path": "backend/chainlit/slack/__init__.py",
"chars": 226,
"preview": "import importlib.util\n\nif importlib.util.find_spec(\"slack_bolt\") is None:\n raise ValueError(\n \"The slack_bolt "
},
{
"path": "backend/chainlit/slack/app.py",
"chars": 15390,
"preview": "import asyncio\nimport os\nimport re\nimport uuid\nfrom functools import partial\nfrom typing import Dict, List, Optional, Un"
},
{
"path": "backend/chainlit/socket.py",
"chars": 15403,
"preview": "import asyncio\nimport json\nfrom typing import Any, Dict, Literal, Optional, Tuple, TypedDict, Union\nfrom urllib.parse im"
},
{
"path": "backend/chainlit/step.py",
"chars": 15013,
"preview": "import asyncio\nimport inspect\nimport json\nimport time\nimport uuid\nfrom copy import deepcopy\nfrom functools import wraps\n"
},
{
"path": "backend/chainlit/sync.py",
"chars": 1236,
"preview": "import sys\nfrom typing import Any, Coroutine, TypeVar\n\nif sys.version_info >= (3, 10):\n from typing import ParamSpec\n"
},
{
"path": "backend/chainlit/teams/__init__.py",
"chars": 236,
"preview": "import importlib.util\n\nif importlib.util.find_spec(\"botbuilder\") is None:\n raise ValueError(\n \"The botbuilder-"
},
{
"path": "backend/chainlit/teams/app.py",
"chars": 10782,
"preview": "import asyncio\nimport base64\nimport mimetypes\nimport os\nimport uuid\nfrom datetime import datetime\nfrom typing import TYP"
},
{
"path": "backend/chainlit/translations/ar-SA.json",
"chars": 7051,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"إلغاء\",\n \"confirm\": \"تأكيد\",\n \"continue\": \"متابعة\",\n \"g"
},
{
"path": "backend/chainlit/translations/bn.json",
"chars": 7633,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"বাতিল করুন\",\n \"confirm\": \"নিশ্চিত করুন\",\n \"continue\": \"চালিয"
},
{
"path": "backend/chainlit/translations/da-DK.json",
"chars": 8880,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Annuller\",\n \"confirm\": \"Bekræft\",\n \""
},
{
"path": "backend/chainlit/translations/de-DE.json",
"chars": 7688,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Abbrechen\",\n \"confirm\": \"Bestätigen\",\n \"continue\": \"Fortfahr"
},
{
"path": "backend/chainlit/translations/el-GR.json",
"chars": 8106,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Άκυρο\",\n \"confirm\": \"Επιβεβαίωση\",\n \"continue\": \"Συνέχεια\",\n"
},
{
"path": "backend/chainlit/translations/en-US.json",
"chars": 7158,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Cancel\",\n \"confirm\": \"Confirm\",\n \"continue\": \"Continue\",\n "
},
{
"path": "backend/chainlit/translations/es.json",
"chars": 7704,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Cancelar\",\n \"confirm\": \"Confirmar\",\n \"continue\": \"Continuar\""
},
{
"path": "backend/chainlit/translations/fr-FR.json",
"chars": 9701,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Annuler\",\n \"confirm\": \"Confirmer\",\n "
},
{
"path": "backend/chainlit/translations/gu.json",
"chars": 7264,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"રદ કરો\",\n \"confirm\": \"પુષ્ટિ કરો\",\n \"continue\": \"ચાલુ રાખો\","
},
{
"path": "backend/chainlit/translations/he-IL.json",
"chars": 6744,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"ביטול\",\n \"confirm\": \"אישור\",\n \"continue\": \"המשך\",\n \"goB"
},
{
"path": "backend/chainlit/translations/hi.json",
"chars": 7492,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"रद्द करें\",\n \"confirm\": \"पुष्टि करें\",\n \"continue\": \"जारी रख"
},
{
"path": "backend/chainlit/translations/it.json",
"chars": 7506,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Cancella\",\n \"confirm\": \"Conferma\",\n \"continue\": \"Continua\",\n"
},
{
"path": "backend/chainlit/translations/ja.json",
"chars": 6603,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"キャンセル\",\n \"confirm\": \"確認\",\n \"continue\": \"続ける\",\n "
},
{
"path": "backend/chainlit/translations/kn.json",
"chars": 7780,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"ರದ್ದುಮಾಡಿ\",\n \"confirm\": \"ದೃಢೀಕರಿಸಿ\",\n \"continue\": \"ಮುಂದುವರಿಸ"
},
{
"path": "backend/chainlit/translations/ko.json",
"chars": 7514,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"취소\",\n \"confirm\": \"확인\",\n \"continue\": "
},
{
"path": "backend/chainlit/translations/ml.json",
"chars": 7984,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"റദ്ദാക്കുക\",\n \"confirm\": \"സ്ഥിരീകരിക്കുക\",\n \"continue\": \"തുട"
},
{
"path": "backend/chainlit/translations/mr.json",
"chars": 7310,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"रद्द करा\",\n \"confirm\": \"पुष्टी करा\",\n \"continue\": \"पुढे जा\","
},
{
"path": "backend/chainlit/translations/nl.json",
"chars": 8062,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"Annuleren\",\n \"confirm\": \"Bevestigen\",\n \"continue\":"
},
{
"path": "backend/chainlit/translations/ta.json",
"chars": 7785,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"ரத்து செய்\",\n \"confirm\": \"உறுதிப்படுத்து\",\n \"continue\": \"தொட"
},
{
"path": "backend/chainlit/translations/te.json",
"chars": 7704,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"రద్దు చేయండి\",\n \"confirm\": \"నిర్ధారించండి\",\n \"continue\": \"కొ"
},
{
"path": "backend/chainlit/translations/zh-CN.json",
"chars": 5541,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"取消\",\n \"confirm\": \"确认\",\n \"continue\": \"继续\",\n \"goBack\": \"返"
},
{
"path": "backend/chainlit/translations/zh-TW.json",
"chars": 5561,
"preview": "{\n \"common\": {\n \"actions\": {\n \"cancel\": \"取消\",\n \"confirm\": \"確認\",\n \"continue\": \"繼續\",\n \"goBack\": \"返"
},
{
"path": "backend/chainlit/translations.py",
"chars": 2024,
"preview": "# TODO:\n# - Support linting plural\n# - Support interpolation\n\n\ndef compare_json_structures(truth, to_compare, path=\"\"):\n"
},
{
"path": "backend/chainlit/types.py",
"chars": 7552,
"preview": "from enum import Enum\nfrom pathlib import Path\nfrom typing import (\n TYPE_CHECKING,\n Any,\n Dict,\n Generic,\n "
},
{
"path": "backend/chainlit/user.py",
"chars": 772,
"preview": "from typing import Dict, Literal, Optional, TypedDict\n\nfrom dataclasses_json import DataClassJsonMixin\nfrom pydantic imp"
},
{
"path": "backend/chainlit/user_session.py",
"chars": 4873,
"preview": "from typing import Callable, Dict, Generic, Optional, TypeVar\n\nfrom chainlit.context import context\n\nuser_sessions: Dict"
},
{
"path": "backend/chainlit/utils.py",
"chars": 5503,
"preview": "import functools\nimport importlib\nimport inspect\nimport os\nfrom asyncio import CancelledError\nfrom datetime import datet"
},
{
"path": "backend/chainlit/version.py",
"chars": 23,
"preview": "__version__ = \"2.10.0\"\n"
},
{
"path": "backend/pyproject.toml",
"chars": 4315,
"preview": "[project]\nname = \"chainlit\"\ndynamic = [\"version\"]\nkeywords = [\n \"LLM\",\n \"Agents\",\n \"MCP\",\n \"gen ai\",\n \"ch"
},
{
"path": "backend/tests/__init__.py",
"chars": 1,
"preview": "\n"
},
{
"path": "backend/tests/auth/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "backend/tests/auth/test_cookie.py",
"chars": 5446,
"preview": "import importlib\n\nimport pytest\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom starlet"
},
{
"path": "backend/tests/conftest.py",
"chars": 3904,
"preview": "import datetime\nfrom contextlib import asynccontextmanager\nfrom pathlib import Path\nfrom typing import Callable\nfrom uni"
},
{
"path": "backend/tests/data/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "backend/tests/data/conftest.py",
"chars": 530,
"preview": "from unittest.mock import AsyncMock\n\nimport pytest\n\nfrom chainlit.data.storage_clients.base import BaseStorageClient\nfro"
},
{
"path": "backend/tests/data/storage_clients/test_gcs.py",
"chars": 12268,
"preview": "from unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom chainlit.data.storage_clients.base import storage_expiry"
},
{
"path": "backend/tests/data/storage_clients/test_s3.py",
"chars": 1502,
"preview": "import os\n\nimport boto3 # type: ignore\nimport pytest\nfrom moto import mock_aws\n\nfrom chainlit.data.storage_clients.s3 i"
},
{
"path": "backend/tests/data/test_chainlit_data_layer.py",
"chars": 6005,
"preview": "import json\nfrom unittest.mock import AsyncMock\n\nimport pytest\n\nfrom chainlit.data.chainlit_data_layer import ChainlitDa"
},
{
"path": "backend/tests/data/test_get_data_layer.py",
"chars": 494,
"preview": "from unittest.mock import AsyncMock, Mock\n\nfrom chainlit.data import get_data_layer\n\n\nasync def test_get_data_layer(\n "
},
{
"path": "backend/tests/data/test_literalai.py",
"chars": 33811,
"preview": "import datetime\nimport uuid\nfrom unittest.mock import ANY, AsyncMock, Mock, patch\n\nimport pytest\nfrom httpx import HTTPS"
},
{
"path": "backend/tests/data/test_sql_alchemy.py",
"chars": 6958,
"preview": "import uuid\nfrom pathlib import Path\n\nimport pytest\nfrom sqlalchemy import text\nfrom sqlalchemy.ext.asyncio import creat"
},
{
"path": "backend/tests/langchain/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "backend/tests/langchain/test_async_callback.py",
"chars": 5177,
"preview": "\"\"\"Tests for async LangChain callback handlers.\"\"\"\n\nfrom datetime import datetime\nfrom unittest.mock import AsyncMock, M"
},
{
"path": "backend/tests/langchain/test_chain_types.py",
"chars": 4252,
"preview": "\"\"\"Tests for different LangChain chain types and their integration with Chainlit.\"\"\"\n\nfrom datetime import datetime\nfrom"
},
{
"path": "backend/tests/langchain/test_sync_callback.py",
"chars": 4778,
"preview": "\"\"\"Tests for synchronous LangChain callback operations and helper classes.\"\"\"\n\nfrom datetime import datetime\nfrom unitte"
},
{
"path": "backend/tests/llama_index/test_callbacks.py",
"chars": 3643,
"preview": "from unittest.mock import patch\n\nfrom llama_index.core.callbacks.schema import CBEventType, EventPayload\nfrom llama_inde"
},
{
"path": "backend/tests/test_action.py",
"chars": 9851,
"preview": "import uuid\n\nimport pytest\n\nfrom chainlit.action import Action\n\n\n@pytest.mark.asyncio\nclass TestAction:\n \"\"\"Test suit"
},
{
"path": "backend/tests/test_cache.py",
"chars": 15833,
"preview": "import sys\nimport threading\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom chainlit.cache import cache, init"
},
{
"path": "backend/tests/test_callbacks.py",
"chars": 27416,
"preview": "from __future__ import annotations\n\nimport asyncio\nfrom unittest.mock import AsyncMock, Mock\n\nfrom chainlit import confi"
},
{
"path": "backend/tests/test_chat_context.py",
"chars": 15463,
"preview": "import asyncio\nfrom contextlib import contextmanager\nfrom unittest.mock import Mock, patch\n\nfrom chainlit.chat_context i"
},
{
"path": "backend/tests/test_chat_settings.py",
"chars": 13284,
"preview": "import pytest\n\nfrom chainlit.chat_settings import ChatSettings\nfrom chainlit.input_widget import (\n Checkbox,\n Num"
},
{
"path": "backend/tests/test_context.py",
"chars": 1615,
"preview": "from unittest.mock import Mock\n\nimport pytest\n\nfrom chainlit.context import (\n ChainlitContext,\n ChainlitContextEx"
},
{
"path": "backend/tests/test_element.py",
"chars": 18445,
"preview": "import uuid\nfrom unittest.mock import AsyncMock\n\nimport pytest\n\nfrom chainlit.element import (\n Audio,\n CustomElem"
},
{
"path": "backend/tests/test_emitter.py",
"chars": 4917,
"preview": "from unittest.mock import MagicMock\n\nimport pytest\n\nfrom chainlit.element import ElementDict\nfrom chainlit.emitter impor"
},
{
"path": "backend/tests/test_input_widget.py",
"chars": 24325,
"preview": "import pytest\n\nfrom chainlit.input_widget import (\n Checkbox,\n MultiSelect,\n NumberInput,\n RadioGroup,\n S"
},
{
"path": "backend/tests/test_markdown.py",
"chars": 13350,
"preview": "import os\nimport tempfile\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom chainlit.markdown import DEFAULT_MARKDOWN"
},
{
"path": "backend/tests/test_mcp.py",
"chars": 17534,
"preview": "import sys\nfrom unittest.mock import patch\n\nimport pytest\nfrom pydantic import ValidationError\n\nfrom chainlit.mcp import"
},
{
"path": "backend/tests/test_message.py",
"chars": 29213,
"preview": "import asyncio\nimport json\nfrom contextlib import contextmanager\nfrom unittest.mock import AsyncMock, Mock, patch\n\nimpor"
},
{
"path": "backend/tests/test_modes.py",
"chars": 9520,
"preview": "\"\"\"Tests for Modes system functionality.\"\"\"\n\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\n\nimport chainlit "
},
{
"path": "backend/tests/test_oauth_providers.py",
"chars": 47120,
"preview": "import os\nfrom unittest.mock import AsyncMock, Mock, patch\n\nimport httpx\nimport pytest\nfrom fastapi import HTTPException"
},
{
"path": "backend/tests/test_server.py",
"chars": 34983,
"preview": "import datetime\nimport os\nimport pathlib\nfrom pathlib import Path\nfrom typing import Callable\nfrom unittest.mock import "
},
{
"path": "backend/tests/test_session.py",
"chars": 20717,
"preview": "import json\nimport tempfile\nimport uuid\nfrom pathlib import Path\nfrom unittest.mock import AsyncMock, Mock, patch\n\nimpor"
},
{
"path": "backend/tests/test_sidebar.py",
"chars": 13034,
"preview": "import pytest\n\nfrom chainlit.element import File, Image, Text\nfrom chainlit.sidebar import ElementSidebar\n\n\n@pytest.mark"
},
{
"path": "backend/tests/test_slack_socket_mode.py",
"chars": 2000,
"preview": "# tests/test_slack_socket_mode.py\nimport importlib\nfrom unittest.mock import AsyncMock, patch\n\nimport pytest\n\n\n@pytest.m"
},
{
"path": "backend/tests/test_socket.py",
"chars": 17622,
"preview": "import json\nfrom unittest.mock import AsyncMock, Mock, patch\n\nimport pytest\n\nfrom chainlit.session import WebsocketSessi"
},
{
"path": "backend/tests/test_step.py",
"chars": 23330,
"preview": "import sys\nimport uuid\nfrom unittest.mock import AsyncMock, Mock, patch\n\nimport pytest\n\nfrom chainlit.context import loc"
},
{
"path": "backend/tests/test_translations.py",
"chars": 14101,
"preview": "from io import StringIO\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom chainlit.translations import compare_json_s"
},
{
"path": "backend/tests/test_user_session.py",
"chars": 612,
"preview": "async def test_user_session_set_get(mock_chainlit_context, user_session):\n async with mock_chainlit_context as contex"
},
{
"path": "backend/tests/test_utils.py",
"chars": 15239,
"preview": "import os\nimport tempfile\nfrom datetime import datetime, timezone\nfrom unittest.mock import AsyncMock, patch\n\nimport cli"
},
{
"path": "cypress/e2e/action/main.py",
"chars": 2561,
"preview": "import chainlit as cl\n\n\n@cl.action_callback(\"test action\")\nasync def on_test_action():\n await cl.Message(content=\"Exe"
},
{
"path": "cypress/e2e/action/spec.cy.ts",
"chars": 2007,
"preview": "describe('Action', () => {\n it('should correctly execute and display actions', () => {\n // Click on \"first action\"\n "
},
{
"path": "cypress/e2e/ask_custom_element/main.py",
"chars": 1125,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def on_start():\n element = cl.CustomElement(\n name=\"JiraTicket"
},
{
"path": "cypress/e2e/ask_custom_element/public/elements/JiraTicket.jsx",
"chars": 3565,
"preview": "import { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, Ca"
},
{
"path": "cypress/e2e/ask_custom_element/spec.cy.ts",
"chars": 467,
"preview": "describe('Ask Custom Element', () => {\n it('should send element props to the backend', () => {\n cy.get('.step').shou"
},
{
"path": "cypress/e2e/ask_file/main.py",
"chars": 1195,
"preview": "import aiofiles\n\nimport chainlit as cl\n\n\n@cl.on_chat_start\nasync def start():\n files = await cl.AskFileMessage(\n "
},
{
"path": "cypress/e2e/ask_file/spec.cy.ts",
"chars": 1308,
"preview": "describe('Upload file', () => {\n it('should be able to receive and decode files', () => {\n cy.get('#ask-upload-butto"
},
{
"path": "cypress/e2e/ask_multiple_files/main.py",
"chars": 704,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def start():\n files = await cl.AskFileMessage(\n content=\"Pleas"
},
{
"path": "cypress/e2e/ask_multiple_files/spec.cy.ts",
"chars": 750,
"preview": "describe('Upload multiple files', () => {\n it('should be able to receive two files', () => {\n cy.get('#ask-upload-bu"
},
{
"path": "cypress/e2e/ask_user/main.py",
"chars": 252,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def main():\n res = await cl.AskUserMessage(content=\"What is your name"
},
{
"path": "cypress/e2e/ask_user/spec.cy.ts",
"chars": 343,
"preview": "import { submitMessage } from '../../support/testUtils';\n\ndescribe('Ask User', () => {\n it('should send a new message c"
},
{
"path": "cypress/e2e/audio_element/main.py",
"chars": 446,
"preview": "import os\n\nimport chainlit as cl\n\n# Get the directory where the script is located\nscript_directory = os.path.dirname(os."
},
{
"path": "cypress/e2e/audio_element/spec.cy.ts",
"chars": 479,
"preview": "describe('audio', () => {\n it('should be able to display an audio element', () => {\n cy.get('.step').should('have.le"
},
{
"path": "cypress/e2e/auth/main.py",
"chars": 1267,
"preview": "import os\nfrom uuid import uuid4\n\nimport chainlit as cl\nfrom chainlit.auth import create_jwt\nfrom chainlit.server import"
},
{
"path": "cypress/e2e/auth/spec.cy.ts",
"chars": 3386,
"preview": "import { loadCopilotScript, mountCopilotWidget, openCopilot, submitMessage } from '../../support/testUtils';\n\nfunction l"
},
{
"path": "cypress/e2e/blinking_cursor/main.py",
"chars": 446,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def main():\n await cl.Message(\"Hello, this is a test message!\").send("
},
{
"path": "cypress/e2e/blinking_cursor/spec.cy.ts",
"chars": 889,
"preview": "import { submitMessage } from '../../support/testUtils';\n\ndescribe('Blinking cursor', () => {\n it('It should display un"
},
{
"path": "cypress/e2e/chat_context/main.py",
"chars": 161,
"preview": "import chainlit as cl\n\n\n@cl.on_message\nasync def main():\n await cl.Message(\n content=f\"Chat context length: {l"
},
{
"path": "cypress/e2e/chat_context/spec.cy.ts",
"chars": 374,
"preview": "import { submitMessage } from '../../support/testUtils';\n\ndescribe('Chat Context', () => {\n it('should be able to curre"
},
{
"path": "cypress/e2e/chat_prefill/main.py",
"chars": 122,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def main():\n await cl.Message(\"Hello, this is a test message!\").send("
},
{
"path": "cypress/e2e/chat_prefill/spec.cy.ts",
"chars": 974,
"preview": "describe('Chat Prefill', () => {\n it('should display a prefill message when the chat starts', () => {\n cy.visit('/?p"
},
{
"path": "cypress/e2e/chat_profiles/main.py",
"chars": 1900,
"preview": "import os\nfrom typing import Optional\n\nimport chainlit as cl\n\nos.environ[\"CHAINLIT_AUTH_SECRET\"] = \"SUPER_SECRET\" # nos"
},
{
"path": "cypress/e2e/chat_profiles/spec.cy.ts",
"chars": 3807,
"preview": "import { submitMessage } from '../../support/testUtils';\n\ndescribe('Chat profiles', () => {\n it('should be able to sele"
},
{
"path": "cypress/e2e/chat_settings/main.py",
"chars": 1973,
"preview": "import chainlit as cl\nfrom chainlit.input_widget import Select, Slider, Switch\n\n\n@cl.on_chat_start\nasync def start():\n "
},
{
"path": "cypress/e2e/chat_settings/spec.cy.ts",
"chars": 1986,
"preview": "const openChatSettingsModal = () => {\n cy.step('Open chat settings modal');\n\n cy.get('#chat-settings-open-modal').shou"
},
{
"path": "cypress/e2e/command/main.py",
"chars": 1105,
"preview": "import chainlit as cl\n\ncommands = [\n {\"id\": \"Picture\", \"icon\": \"image\", \"description\": \"Use DALL-E\"},\n {\"id\": \"Sea"
},
{
"path": "cypress/e2e/command/spec.cy.ts",
"chars": 16312,
"preview": "import 'cypress-plugin-steps';\n\ndescribe('Command', () => {\n // Taller viewport reduces header overlap in headless + ab"
},
{
"path": "cypress/e2e/config_overrides/main.py",
"chars": 2681,
"preview": "import os\nfrom typing import Optional\n\nimport chainlit as cl\nfrom chainlit.config import (\n ChainlitConfigOverrides,\n"
},
{
"path": "cypress/e2e/config_overrides/spec.cy.ts",
"chars": 5098,
"preview": "import { submitMessage } from '../../support/testUtils';\n\ndescribe('Config overrides with chat profiles', () => {\n it('"
},
{
"path": "cypress/e2e/context/main.py",
"chars": 1353,
"preview": "import chainlit as cl\nfrom chainlit.context import context\nfrom chainlit.sync import make_async, run_sync\n\n\nasync def as"
},
{
"path": "cypress/e2e/context/spec.cy.ts",
"chars": 450,
"preview": "describe('Context should be reachable', () => {\n it('should find the Emitter from async, make_async and async_from_sync"
},
{
"path": "cypress/e2e/copilot/main.py",
"chars": 529,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def on_chat_start():\n await cl.Message(content=\"Hi from copilot!\").se"
},
{
"path": "cypress/e2e/copilot/spec.cy.ts",
"chars": 4462,
"preview": "import {\n copilotShouldBeOpen,\n clearCopilotThreadId,\n getCopilotThreadId,\n loadCopilotScript,\n mountCopilotWidget,"
},
{
"path": "cypress/e2e/custom_build/.gitignore",
"chars": 22,
"preview": "!.chainlit/config.toml"
},
{
"path": "cypress/e2e/custom_build/main.py",
"chars": 106,
"preview": "import chainlit as cl\n\n\n@cl.on_chat_start\nasync def main():\n await cl.Message(content=\"Hello!\").send()\n"
},
{
"path": "cypress/e2e/custom_build/public/.gitignore",
"chars": 12,
"preview": "!build\n!dist"
},
{
"path": "cypress/e2e/custom_build/public/build/assets/.PLACEHOLDER",
"chars": 0,
"preview": ""
},
{
"path": "cypress/e2e/custom_build/public/build/index.html",
"chars": 163,
"preview": "<html>\n <head>\n <title>Custom Build</title>\n </head>\n <body>\n <p>This is a test page for custom b"
},
{
"path": "cypress/e2e/custom_build/spec.cy.ts",
"chars": 200,
"preview": "describe('Custom Build', () => {\n it('should correctly serve the custom build page', () => {\n cy.get('body').contain"
},
{
"path": "cypress/e2e/custom_data_layer/sql_alchemy.py",
"chars": 921,
"preview": "import os\nfrom typing import Optional\n\nimport chainlit as cl\nfrom chainlit.data.sql_alchemy import SQLAlchemyDataLayer\nf"
},
{
"path": "cypress/e2e/custom_element/main.py",
"chars": 394,
"preview": "import chainlit as cl\n\n\n@cl.action_callback(\"test\")\nasync def on_test_action():\n await cl.sleep(1)\n await cl.Messa"
},
{
"path": "cypress/e2e/custom_element/public/elements/Counter.jsx",
"chars": 863,
"preview": "import { Button } from \"@/components/ui/button\"\nimport { X } from 'lucide-react';\n\nexport default function Counter() {\n "
}
]
// ... and 388 more files (download for full content)
About this extraction
This page contains the full source code of the Chainlit/chainlit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 588 files (2.1 MB), approximately 582.0k tokens, and a symbol index with 2285 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.