Full Code of Chainlit/chainlit for AI

main 3843e8a401ca cached
588 files
2.1 MB
582.0k tokens
2285 symbols
1 requests
Download .txt
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
Download .txt
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
Download .txt
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.

Copied to clipboard!