Full Code of huggingface/chat-ui for AI

main 6859cbeaeee0 cached
412 files
1.1 MB
321.2k tokens
589 symbols
1 requests
Download .txt
Showing preview only (1,195K chars total). Download the full file or copy to clipboard to get everything.
Repository: huggingface/chat-ui
Branch: main
Commit: 6859cbeaeee0
Files: 412
Total size: 1.1 MB

Directory structure:
gitextract_mfj9ft39/

├── .devcontainer/
│   ├── Dockerfile
│   └── devcontainer.json
├── .dockerignore
├── .env
├── .env.ci
├── .eslintignore
├── .eslintrc.cjs
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report--chat-ui-.md
│   │   ├── config-support.md
│   │   ├── feature-request--chat-ui-.md
│   │   └── huggingchat.md
│   ├── release.yml
│   └── workflows/
│       ├── build-docs.yml
│       ├── build-image.yml
│       ├── build-pr-docs.yml
│       ├── deploy-dev.yml
│       ├── deploy-prod.yml
│       ├── lint-and-test.yml
│       ├── slugify.yaml
│       ├── trufflehog.yml
│       └── upload-pr-documentation.yml
├── .gitignore
├── .husky/
│   ├── lint-stage-config.js
│   └── pre-commit
├── .npmrc
├── .prettierignore
├── .prettierrc
├── .vscode/
│   ├── launch.json
│   └── settings.json
├── CLAUDE.md
├── Dockerfile
├── LICENSE
├── PRIVACY.md
├── README.md
├── chart/
│   ├── Chart.yaml
│   ├── env/
│   │   ├── dev.yaml
│   │   └── prod.yaml
│   ├── templates/
│   │   ├── _helpers.tpl
│   │   ├── config.yaml
│   │   ├── deployment.yaml
│   │   ├── hpa.yaml
│   │   ├── infisical.yaml
│   │   ├── ingress-internal.yaml
│   │   ├── ingress.yaml
│   │   ├── network-policy.yaml
│   │   ├── service-account.yaml
│   │   ├── service-monitor.yaml
│   │   └── service.yaml
│   └── values.yaml
├── docker-compose.yml
├── docs/
│   └── source/
│       ├── _toctree.yml
│       ├── configuration/
│       │   ├── common-issues.md
│       │   ├── llm-router.md
│       │   ├── mcp-tools.md
│       │   ├── metrics.md
│       │   ├── open-id.md
│       │   ├── overview.md
│       │   └── theming.md
│       ├── developing/
│       │   └── architecture.md
│       ├── index.md
│       └── installation/
│           ├── docker.md
│           ├── helm.md
│           └── local.md
├── entrypoint.sh
├── models/
│   └── add-your-models-here.txt
├── package.json
├── postcss.config.js
├── scripts/
│   ├── config.ts
│   ├── populate.ts
│   ├── samples.txt
│   ├── setups/
│   │   ├── vitest-setup-client.ts
│   │   └── vitest-setup-server.ts
│   └── updateLocalEnv.ts
├── server.log
├── src/
│   ├── ambient.d.ts
│   ├── app.d.ts
│   ├── app.html
│   ├── hooks.server.ts
│   ├── hooks.ts
│   ├── lib/
│   │   ├── APIClient.ts
│   │   ├── actions/
│   │   │   ├── clickOutside.ts
│   │   │   └── snapScrollToBottom.ts
│   │   ├── buildPrompt.ts
│   │   ├── components/
│   │   │   ├── AnnouncementBanner.svelte
│   │   │   ├── BackgroundGenerationPoller.svelte
│   │   │   ├── CodeBlock.svelte
│   │   │   ├── CopyToClipBoardBtn.svelte
│   │   │   ├── DeleteConversationModal.svelte
│   │   │   ├── EditConversationModal.svelte
│   │   │   ├── ExpandNavigation.svelte
│   │   │   ├── HoverTooltip.svelte
│   │   │   ├── HtmlPreviewModal.svelte
│   │   │   ├── InfiniteScroll.svelte
│   │   │   ├── MobileNav.svelte
│   │   │   ├── Modal.svelte
│   │   │   ├── ModelCardMetadata.svelte
│   │   │   ├── NavConversationItem.svelte
│   │   │   ├── NavMenu.svelte
│   │   │   ├── Pagination.svelte
│   │   │   ├── PaginationArrow.svelte
│   │   │   ├── Portal.svelte
│   │   │   ├── RetryBtn.svelte
│   │   │   ├── ScrollToBottomBtn.svelte
│   │   │   ├── ScrollToPreviousBtn.svelte
│   │   │   ├── ShareConversationModal.svelte
│   │   │   ├── StopGeneratingBtn.svelte
│   │   │   ├── SubscribeModal.svelte
│   │   │   ├── Switch.svelte
│   │   │   ├── SystemPromptModal.svelte
│   │   │   ├── Toast.svelte
│   │   │   ├── Tooltip.svelte
│   │   │   ├── WelcomeModal.svelte
│   │   │   ├── chat/
│   │   │   │   ├── Alternatives.svelte
│   │   │   │   ├── BlockWrapper.svelte
│   │   │   │   ├── ChatInput.svelte
│   │   │   │   ├── ChatIntroduction.svelte
│   │   │   │   ├── ChatMessage.svelte
│   │   │   │   ├── ChatWindow.svelte
│   │   │   │   ├── FileDropzone.svelte
│   │   │   │   ├── ImageLightbox.svelte
│   │   │   │   ├── MarkdownBlock.svelte
│   │   │   │   ├── MarkdownRenderer.svelte
│   │   │   │   ├── MarkdownRenderer.svelte.test.ts
│   │   │   │   ├── MessageAvatar.svelte
│   │   │   │   ├── ModelSwitch.svelte
│   │   │   │   ├── OpenReasoningResults.svelte
│   │   │   │   ├── ToolUpdate.svelte
│   │   │   │   ├── UploadedFile.svelte
│   │   │   │   ├── UrlFetchModal.svelte
│   │   │   │   └── VoiceRecorder.svelte
│   │   │   ├── icons/
│   │   │   │   ├── IconBurger.svelte
│   │   │   │   ├── IconCheap.svelte
│   │   │   │   ├── IconChevron.svelte
│   │   │   │   ├── IconDazzled.svelte
│   │   │   │   ├── IconFast.svelte
│   │   │   │   ├── IconLoading.svelte
│   │   │   │   ├── IconMCP.svelte
│   │   │   │   ├── IconMoon.svelte
│   │   │   │   ├── IconNew.svelte
│   │   │   │   ├── IconOmni.svelte
│   │   │   │   ├── IconPaperclip.svelte
│   │   │   │   ├── IconPro.svelte
│   │   │   │   ├── IconShare.svelte
│   │   │   │   ├── IconSun.svelte
│   │   │   │   ├── Logo.svelte
│   │   │   │   └── LogoHuggingFaceBorderless.svelte
│   │   │   ├── mcp/
│   │   │   │   ├── AddServerForm.svelte
│   │   │   │   ├── MCPServerManager.svelte
│   │   │   │   └── ServerCard.svelte
│   │   │   ├── players/
│   │   │   │   └── AudioPlayer.svelte
│   │   │   └── voice/
│   │   │       └── AudioWaveform.svelte
│   │   ├── constants/
│   │   │   ├── mcpExamples.ts
│   │   │   ├── mime.ts
│   │   │   ├── pagination.ts
│   │   │   ├── publicSepToken.ts
│   │   │   └── routerExamples.ts
│   │   ├── createShareLink.ts
│   │   ├── jobs/
│   │   │   └── refresh-conversation-stats.ts
│   │   ├── migrations/
│   │   │   ├── lock.ts
│   │   │   ├── migrations.spec.ts
│   │   │   ├── migrations.ts
│   │   │   └── routines/
│   │   │       ├── 01-update-search-assistants.ts
│   │   │       ├── 02-update-assistants-models.ts
│   │   │       ├── 04-update-message-updates.ts
│   │   │       ├── 05-update-message-files.ts
│   │   │       ├── 06-trim-message-updates.ts
│   │   │       ├── 08-update-featured-to-review.ts
│   │   │       ├── 09-delete-empty-conversations.spec.ts
│   │   │       ├── 09-delete-empty-conversations.ts
│   │   │       ├── 10-update-reports-assistantid.ts
│   │   │       └── index.ts
│   │   ├── server/
│   │   │   ├── __tests__/
│   │   │   │   └── conversation-stop-generating.spec.ts
│   │   │   ├── abortRegistry.ts
│   │   │   ├── abortedGenerations.ts
│   │   │   ├── adminToken.ts
│   │   │   ├── api/
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── conversations-id.spec.ts
│   │   │   │   │   ├── conversations-message.spec.ts
│   │   │   │   │   ├── conversations.spec.ts
│   │   │   │   │   ├── misc.spec.ts
│   │   │   │   │   ├── testHelpers.ts
│   │   │   │   │   ├── user-reports.spec.ts
│   │   │   │   │   └── user.spec.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── requireAuth.ts
│   │   │   │       ├── resolveConversation.ts
│   │   │   │       ├── resolveModel.ts
│   │   │   │       └── superjsonResponse.ts
│   │   │   ├── apiToken.ts
│   │   │   ├── auth.ts
│   │   │   ├── config.ts
│   │   │   ├── conversation.ts
│   │   │   ├── database.ts
│   │   │   ├── endpoints/
│   │   │   │   ├── document.ts
│   │   │   │   ├── endpoints.ts
│   │   │   │   ├── images.ts
│   │   │   │   ├── openai/
│   │   │   │   │   ├── endpointOai.ts
│   │   │   │   │   ├── openAIChatToTextGenerationStream.ts
│   │   │   │   │   └── openAICompletionToTextGenerationStream.ts
│   │   │   │   └── preprocessMessages.ts
│   │   │   ├── exitHandler.ts
│   │   │   ├── files/
│   │   │   │   ├── downloadFile.ts
│   │   │   │   └── uploadFile.ts
│   │   │   ├── findRepoRoot.ts
│   │   │   ├── generateFromDefaultEndpoint.ts
│   │   │   ├── hooks/
│   │   │   │   ├── error.ts
│   │   │   │   ├── fetch.ts
│   │   │   │   ├── handle.ts
│   │   │   │   └── init.ts
│   │   │   ├── isURLLocal.spec.ts
│   │   │   ├── isURLLocal.ts
│   │   │   ├── logger.ts
│   │   │   ├── mcp/
│   │   │   │   ├── clientPool.ts
│   │   │   │   ├── hf.ts
│   │   │   │   ├── httpClient.ts
│   │   │   │   ├── registry.ts
│   │   │   │   └── tools.ts
│   │   │   ├── metrics.ts
│   │   │   ├── models.ts
│   │   │   ├── requestContext.ts
│   │   │   ├── router/
│   │   │   │   ├── arch.ts
│   │   │   │   ├── endpoint.ts
│   │   │   │   ├── multimodal.ts
│   │   │   │   ├── policy.ts
│   │   │   │   ├── toolsRoute.ts
│   │   │   │   └── types.ts
│   │   │   ├── sendSlack.ts
│   │   │   ├── textGeneration/
│   │   │   │   ├── generate.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── mcp/
│   │   │   │   │   ├── fileRefs.ts
│   │   │   │   │   ├── routerResolution.ts
│   │   │   │   │   ├── runMcpFlow.ts
│   │   │   │   │   └── toolInvocation.ts
│   │   │   │   ├── reasoning.ts
│   │   │   │   ├── title.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── prepareFiles.ts
│   │   │   │       ├── routing.ts
│   │   │   │       └── toolPrompt.ts
│   │   │   ├── urlSafety.ts
│   │   │   └── usageLimits.ts
│   │   ├── stores/
│   │   │   ├── backgroundGenerations.svelte.ts
│   │   │   ├── backgroundGenerations.ts
│   │   │   ├── errors.ts
│   │   │   ├── isAborted.ts
│   │   │   ├── isPro.ts
│   │   │   ├── loading.ts
│   │   │   ├── mcpServers.ts
│   │   │   ├── pendingChatInput.ts
│   │   │   ├── pendingMessage.ts
│   │   │   ├── settings.ts
│   │   │   ├── shareModal.ts
│   │   │   └── titleUpdate.ts
│   │   ├── switchTheme.ts
│   │   ├── types/
│   │   │   ├── AbortedGeneration.ts
│   │   │   ├── Assistant.ts
│   │   │   ├── AssistantStats.ts
│   │   │   ├── ConfigKey.ts
│   │   │   ├── ConvSidebar.ts
│   │   │   ├── Conversation.ts
│   │   │   ├── ConversationStats.ts
│   │   │   ├── Message.ts
│   │   │   ├── MessageEvent.ts
│   │   │   ├── MessageUpdate.ts
│   │   │   ├── MigrationResult.ts
│   │   │   ├── Model.ts
│   │   │   ├── Report.ts
│   │   │   ├── Review.ts
│   │   │   ├── Semaphore.ts
│   │   │   ├── Session.ts
│   │   │   ├── Settings.ts
│   │   │   ├── SharedConversation.ts
│   │   │   ├── Template.ts
│   │   │   ├── Timestamps.ts
│   │   │   ├── TokenCache.ts
│   │   │   ├── Tool.ts
│   │   │   ├── UrlDependency.ts
│   │   │   └── User.ts
│   │   ├── utils/
│   │   │   ├── PublicConfig.svelte.ts
│   │   │   ├── auth.ts
│   │   │   ├── chunk.ts
│   │   │   ├── cookiesAreEnabled.ts
│   │   │   ├── debounce.ts
│   │   │   ├── deepestChild.ts
│   │   │   ├── favicon.ts
│   │   │   ├── fetchJSON.ts
│   │   │   ├── file2base64.ts
│   │   │   ├── formatUserCount.ts
│   │   │   ├── generationState.spec.ts
│   │   │   ├── generationState.ts
│   │   │   ├── getHref.ts
│   │   │   ├── getReturnFromGenerator.ts
│   │   │   ├── haptics.ts
│   │   │   ├── hashConv.ts
│   │   │   ├── hf.ts
│   │   │   ├── isDesktop.ts
│   │   │   ├── isUrl.ts
│   │   │   ├── isVirtualKeyboard.ts
│   │   │   ├── loadAttachmentsFromUrls.ts
│   │   │   ├── marked.spec.ts
│   │   │   ├── marked.ts
│   │   │   ├── mcpValidation.ts
│   │   │   ├── mergeAsyncGenerators.ts
│   │   │   ├── messageUpdates.spec.ts
│   │   │   ├── messageUpdates.ts
│   │   │   ├── mime.ts
│   │   │   ├── models.ts
│   │   │   ├── parseBlocks.ts
│   │   │   ├── parseIncompleteMarkdown.ts
│   │   │   ├── parseStringToList.ts
│   │   │   ├── randomUuid.ts
│   │   │   ├── searchTokens.ts
│   │   │   ├── sha256.ts
│   │   │   ├── stringifyError.ts
│   │   │   ├── sum.ts
│   │   │   ├── template.spec.ts
│   │   │   ├── template.ts
│   │   │   ├── timeout.ts
│   │   │   ├── toolProgress.spec.ts
│   │   │   ├── toolProgress.ts
│   │   │   ├── tree/
│   │   │   │   ├── addChildren.spec.ts
│   │   │   │   ├── addChildren.ts
│   │   │   │   ├── addSibling.spec.ts
│   │   │   │   ├── addSibling.ts
│   │   │   │   ├── buildSubtree.spec.ts
│   │   │   │   ├── buildSubtree.ts
│   │   │   │   ├── convertLegacyConversation.spec.ts
│   │   │   │   ├── convertLegacyConversation.ts
│   │   │   │   ├── isMessageId.spec.ts
│   │   │   │   ├── isMessageId.ts
│   │   │   │   ├── tree.d.ts
│   │   │   │   └── treeHelpers.spec.ts
│   │   │   ├── updates.ts
│   │   │   └── urlParams.ts
│   │   └── workers/
│   │       └── markdownWorker.ts
│   ├── routes/
│   │   ├── +error.svelte
│   │   ├── +layout.svelte
│   │   ├── +layout.ts
│   │   ├── +page.svelte
│   │   ├── .well-known/
│   │   │   └── oauth-cimd/
│   │   │       └── +server.ts
│   │   ├── __debug/
│   │   │   └── openai/
│   │   │       └── +server.ts
│   │   ├── admin/
│   │   │   ├── export/
│   │   │   │   └── +server.ts
│   │   │   └── stats/
│   │   │       └── compute/
│   │   │           └── +server.ts
│   │   ├── api/
│   │   │   ├── conversation/
│   │   │   │   └── [id]/
│   │   │   │       ├── +server.ts
│   │   │   │       └── message/
│   │   │   │           └── [messageId]/
│   │   │   │               └── +server.ts
│   │   │   ├── conversations/
│   │   │   │   └── +server.ts
│   │   │   ├── fetch-url/
│   │   │   │   └── +server.ts
│   │   │   ├── mcp/
│   │   │   │   ├── health/
│   │   │   │   │   └── +server.ts
│   │   │   │   └── servers/
│   │   │   │       └── +server.ts
│   │   │   ├── models/
│   │   │   │   └── +server.ts
│   │   │   ├── transcribe/
│   │   │   │   └── +server.ts
│   │   │   ├── user/
│   │   │   │   ├── +server.ts
│   │   │   │   └── validate-token/
│   │   │   │       └── +server.ts
│   │   │   └── v2/
│   │   │       ├── conversations/
│   │   │       │   ├── +server.ts
│   │   │       │   ├── [id]/
│   │   │       │   │   ├── +server.ts
│   │   │       │   │   └── message/
│   │   │       │   │       └── [messageId]/
│   │   │       │   │           └── +server.ts
│   │   │       │   └── import-share/
│   │   │       │       └── +server.ts
│   │   │       ├── debug/
│   │   │       │   ├── config/
│   │   │       │   │   └── +server.ts
│   │   │       │   └── refresh/
│   │   │       │       └── +server.ts
│   │   │       ├── export/
│   │   │       │   └── +server.ts
│   │   │       ├── feature-flags/
│   │   │       │   └── +server.ts
│   │   │       ├── models/
│   │   │       │   ├── +server.ts
│   │   │       │   ├── [namespace]/
│   │   │       │   │   ├── +server.ts
│   │   │       │   │   ├── [model]/
│   │   │       │   │   │   ├── +server.ts
│   │   │       │   │   │   └── subscribe/
│   │   │       │   │   │       └── +server.ts
│   │   │       │   │   └── subscribe/
│   │   │       │   │       └── +server.ts
│   │   │       │   ├── old/
│   │   │       │   │   └── +server.ts
│   │   │       │   └── refresh/
│   │   │       │       └── +server.ts
│   │   │       ├── public-config/
│   │   │       │   └── +server.ts
│   │   │       └── user/
│   │   │           ├── +server.ts
│   │   │           ├── billing-orgs/
│   │   │           │   └── +server.ts
│   │   │           ├── reports/
│   │   │           │   └── +server.ts
│   │   │           └── settings/
│   │   │               └── +server.ts
│   │   ├── conversation/
│   │   │   ├── +server.ts
│   │   │   └── [id]/
│   │   │       ├── +page.svelte
│   │   │       ├── +page.ts
│   │   │       ├── +server.ts
│   │   │       ├── message/
│   │   │       │   └── [messageId]/
│   │   │       │       └── prompt/
│   │   │       │           └── +server.ts
│   │   │       ├── output/
│   │   │       │   └── [sha256]/
│   │   │       │       └── +server.ts
│   │   │       ├── share/
│   │   │       │   └── +server.ts
│   │   │       └── stop-generating/
│   │   │           └── +server.ts
│   │   ├── healthcheck/
│   │   │   └── +server.ts
│   │   ├── login/
│   │   │   ├── +server.ts
│   │   │   └── callback/
│   │   │       ├── +server.ts
│   │   │       ├── updateUser.spec.ts
│   │   │       └── updateUser.ts
│   │   ├── logout/
│   │   │   └── +server.ts
│   │   ├── metrics/
│   │   │   └── +server.ts
│   │   ├── models/
│   │   │   ├── +page.svelte
│   │   │   └── [...model]/
│   │   │       ├── +page.svelte
│   │   │       └── +page.ts
│   │   ├── privacy/
│   │   │   └── +page.svelte
│   │   ├── r/
│   │   │   └── [id]/
│   │   │       └── +page.ts
│   │   └── settings/
│   │       ├── (nav)/
│   │       │   ├── +layout.svelte
│   │       │   ├── +layout.ts
│   │       │   ├── +page.svelte
│   │       │   ├── +server.ts
│   │       │   ├── [...model]/
│   │       │   │   ├── +page.svelte
│   │       │   │   └── +page.ts
│   │       │   └── application/
│   │       │       └── +page.svelte
│   │       └── +layout.svelte
│   └── styles/
│       ├── highlight-js.css
│       └── main.css
├── static/
│   ├── chatui/
│   │   └── manifest.json
│   ├── huggingchat/
│   │   ├── manifest.json
│   │   └── routes.chat.json
│   └── robots.txt
├── stub/
│   └── @reflink/
│       └── reflink/
│           ├── index.js
│           └── package.json
├── svelte.config.js
├── tailwind.config.cjs
├── tsconfig.json
└── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm

# Install MongoDB tools (mongosh, mongorestore, mongodump) directly from MongoDB repository
RUN curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg && \
    echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] http://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list && \
    apt-get update && \
    apt-get install -y mongodb-mongosh mongodb-database-tools vim && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/*


================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
	"name": "Node.js & TypeScript",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"build": {
		"dockerfile": "Dockerfile"
	},

	"customizations": {
		"vscode": {
			"extensions": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint", "svelte.svelte-vscode"]
		}
	},

	"features": {
		// Install docker in container
		"ghcr.io/devcontainers/features/docker-in-docker:2": {
			// Use proprietary docker engine. I get a timeout error when using the default moby engine and loading
			// microsoft's PGP keys
			"moby": false
		}
	}

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "yarn install",

	// Configure tool-specific properties.
	// "customizations": {},

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}


================================================
FILE: .dockerignore
================================================
Dockerfile
.vscode/
.idea
.gitignore
LICENSE
README.md
node_modules/
.svelte-kit/
.env*
!.env
.env.local
db
models/**

================================================
FILE: .env
================================================
# Use .env.local to change these variables
# DO NOT EDIT THIS FILE WITH SENSITIVE DATA

### Models ###
# Models are sourced exclusively from an OpenAI-compatible base URL.
# Example: https://router.huggingface.co/v1
OPENAI_BASE_URL=https://router.huggingface.co/v1

# Canonical auth token for any OpenAI-compatible provider
OPENAI_API_KEY=#your provider API key (works for HF router, OpenAI, LM Studio, etc.). 
# When set to true, user token will be used for inference calls
USE_USER_TOKEN=false
# Automatically redirect to oauth login page if user is not logged in, when set to "true"
AUTOMATIC_LOGIN=false

### MongoDB ###
MONGODB_URL=#your mongodb URL here, use chat-ui-db image if you don't want to set this
MONGODB_DB_NAME=chat-ui
MONGODB_DIRECT_CONNECTION=false


## Public app configuration ##
PUBLIC_APP_NAME=ChatUI # name used as title throughout the app
PUBLIC_APP_ASSETS=chatui # used to find logos & favicons in static/$PUBLIC_APP_ASSETS
PUBLIC_APP_DESCRIPTION="Making the community's best AI chat models available to everyone."# description used throughout the app
PUBLIC_ORIGIN=
PUBLIC_SHARE_PREFIX=
PUBLIC_GOOGLE_ANALYTICS_ID=
PUBLIC_PLAUSIBLE_SCRIPT_URL=
PUBLIC_APPLE_APP_ID=

COUPLE_SESSION_WITH_COOKIE_NAME=
# when OPEN_ID is configured, users are required to login after the welcome modal
OPENID_CLIENT_ID="" # You can set to "__CIMD__" for automatic oauth app creation when deployed, see https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/
OPENID_CLIENT_SECRET=
OPENID_SCOPES="openid profile inference-api read-mcp read-billing"
USE_USER_TOKEN=
AUTOMATIC_LOGIN=# if true authentication is required on all routes

### Local Storage ###
MONGO_STORAGE_PATH= # where is the db folder stored

## Models overrides
MODELS=

## Task model
# Optional: set to the model id/name from the `${OPENAI_BASE_URL}/models` list
# to use for internal tasks (title summarization, etc). If not set, the current model will be used
TASK_MODEL=

# Arch router (OpenAI-compatible) endpoint base URL used for route selection
# Example: https://api.openai.com/v1 or your hosted Arch endpoint
LLM_ROUTER_ARCH_BASE_URL=

## LLM Router Configuration
# Path to routes policy (JSON array). Required when the router is enabled; must point to a valid JSON file.
LLM_ROUTER_ROUTES_PATH=

# Model used at the Arch router endpoint for selection
LLM_ROUTER_ARCH_MODEL=

# Fallback behavior
# Route to map "other" to (must exist in routes file)
LLM_ROUTER_OTHER_ROUTE=casual_conversation
# Model to call if the Arch selection fails entirely
LLM_ROUTER_FALLBACK_MODEL=
# Arch selection timeout in milliseconds (default 10000)
LLM_ROUTER_ARCH_TIMEOUT_MS=10000
# Maximum length (in characters) for assistant messages sent to router for route selection (default 500)
LLM_ROUTER_MAX_ASSISTANT_LENGTH=500
# Maximum length (in characters) for previous user messages sent to router (latest user message not trimmed, default 400)
LLM_ROUTER_MAX_PREV_USER_LENGTH=400

# Enable router multimodal handling (set to true to allow image inputs via router)
LLM_ROUTER_ENABLE_MULTIMODAL=
# Required when LLM_ROUTER_ENABLE_MULTIMODAL=true: id or name of the multimodal model to use for image requests
LLM_ROUTER_MULTIMODAL_MODEL=

# Enable router tool support (set to true to allow tool calling via router)
LLM_ROUTER_ENABLE_TOOLS=
# Required when tools are active: id or name of the model to use for MCP tool calls.
LLM_ROUTER_TOOLS_MODEL=

# Router UI overrides (client-visible)
# Public display name for the router entry in the model list. Defaults to "Omni".
PUBLIC_LLM_ROUTER_DISPLAY_NAME=Omni
# Optional: public logo URL for the router entry. If unset, the UI shows a Carbon icon.
PUBLIC_LLM_ROUTER_LOGO_URL=
# Public alias id used for the virtual router model (Omni). Defaults to "omni".
PUBLIC_LLM_ROUTER_ALIAS_ID=omni

### Transcription ###
# Voice-to-text transcription using Whisper models
# If set, enables the microphone button in the chat input
# Example: openai/whisper-large-v3-turbo
TRANSCRIPTION_MODEL=
# Optional: Base URL for transcription API (defaults to HF inference)
# Default: https://router.huggingface.co/hf-inference/models
TRANSCRIPTION_BASE_URL=

### Authentication ###
# Parameters to enable open id login
OPENID_CONFIG=
# if it's defined, only these emails will be allowed to use login
ALLOWED_USER_EMAILS=[]
# If it's defined, users with emails matching these domains will also be allowed to use login
ALLOWED_USER_DOMAINS=[]
# valid alternative redirect URLs for OAuth, used for HuggingChat apps
ALTERNATIVE_REDIRECT_URLS=[] 
### Cookies
# name of the cookie used to store the session
COOKIE_NAME=hf-chat
# If the value of this cookie changes, the session is destroyed. Useful if chat-ui is deployed on a subpath
# of your domain, and you want chat ui sessions to reset if the user's auth changes
COUPLE_SESSION_WITH_COOKIE_NAME=
# specify secure behaviour for cookies 
COOKIE_SAMESITE=# can be "lax", "strict", "none" or left empty
COOKIE_SECURE=# set to true to only allow cookies over https
TRUSTED_EMAIL_HEADER=# header to use to get the user email, only use if you know what you are doing

### Admin stuff ###
ADMIN_CLI_LOGIN=true # set to false to disable the CLI login
ADMIN_TOKEN=#We recommend leaving this empty, you can get the token from the terminal.

### Feature Flags ###
LLM_SUMMARIZATION=true # generate conversation titles with LLMs
 
ALLOW_IFRAME=true # Allow the app to be embedded in an iframe

# Base servers list (JSON array). Example: MCP_SERVERS=[{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"}, {"name": "Hugging Face", "url": "https://hf.co/mcp"}]
MCP_SERVERS=
# When true, forward the logged-in user's Hugging Face access token
MCP_FORWARD_HF_USER_TOKEN=
# Exa API key (injected at runtime into mcp.exa.ai URLs as ?exaApiKey=)
EXA_API_KEY=
# Timeout in milliseconds for MCP tool calls (default: 120000 = 2 minutes)
MCP_TOOL_TIMEOUT_MS=
ENABLE_DATA_EXPORT=true

### Rate limits ### 
# See `src/lib/server/usageLimits.ts`
# {
#   conversations: number, # how many conversations
#   messages: number, # how many messages in a conversation
#   assistants: number, # how many assistants
#   messageLength: number, # how long can a message be before we cut it off
#   messagesPerMinute: number, # how many messages per minute
#   tools: number # how many tools
# }
USAGE_LIMITS={}

### HuggingFace specific ###
## Feature flag & admin settings
# Used for setting early access & admin flags to users
HF_ORG_ADMIN=
HF_ORG_EARLY_ACCESS=
WEBHOOK_URL_REPORT_ASSISTANT=#provide slack webhook url to get notified for reports/feature requests


### Metrics ###
METRICS_ENABLED=false
METRICS_PORT=5565
LOG_LEVEL=info


### Parquet export ###
# Not in use anymore but useful to export conversations to a parquet file as a HuggingFace dataset
PARQUET_EXPORT_DATASET=
PARQUET_EXPORT_HF_TOKEN=
ADMIN_API_SECRET=# secret to admin API calls, like computing usage stats or exporting parquet data

### Config ###
ENABLE_CONFIG_MANAGER=true

### Docker build variables ### 
# These values cannot be updated at runtime
# They need to be passed when building the docker image
# See https://github.com/huggingface/chat-ui/main/.github/workflows/deploy-prod.yml#L44-L47
APP_BASE="" # base path of the app, e.g. /chat, left blank as default
### Body size limit for SvelteKit https://svelte.dev/docs/kit/adapter-node#Environment-variables-BODY_SIZE_LIMIT
BODY_SIZE_LIMIT=15728640
PUBLIC_COMMIT_SHA=

### LEGACY parameters
ALLOW_INSECURE_COOKIES=false # LEGACY! Use COOKIE_SECURE and COOKIE_SAMESITE instead
PARQUET_EXPORT_SECRET=#DEPRECATED, use ADMIN_API_SECRET instead
RATE_LIMIT= # /!\ DEPRECATED definition of messages per minute. Use USAGE_LIMITS.messagesPerMinute instead
OPENID_NAME_CLAIM="name" # Change to "username" for some providers that do not provide name
OPENID_PROVIDER_URL=https://huggingface.co # for Google, use https://accounts.google.com
OPENID_TOLERANCE=
OPENID_RESOURCE=
EXPOSE_API=# deprecated, API is now always exposed


================================================
FILE: .env.ci
================================================
MONGODB_URL=mongodb://localhost:27017/

================================================
FILE: .eslintignore
================================================
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock


================================================
FILE: .eslintrc.cjs
================================================
module.exports = {
	root: true,
	parser: "@typescript-eslint/parser",
	extends: [
		"eslint:recommended",
		"plugin:@typescript-eslint/recommended",
		"plugin:svelte/recommended",
		"prettier",
	],
	plugins: ["@typescript-eslint"],
	ignorePatterns: ["*.cjs"],
	overrides: [
		{
			files: ["*.svelte"],
			parser: "svelte-eslint-parser",
			parserOptions: {
				parser: "@typescript-eslint/parser",
			},
		},
	],
	parserOptions: {
		sourceType: "module",
		ecmaVersion: 2020,
		extraFileExtensions: [".svelte"],
	},
	rules: {
		"no-empty": "off",
		"require-yield": "off",
		"@typescript-eslint/no-explicit-any": "error",
		"@typescript-eslint/no-non-null-assertion": "error",
		"@typescript-eslint/no-unused-vars": [
			// prevent variables with a _ prefix from being marked as unused
			"error",
			{
				argsIgnorePattern: "^_",
			},
		],
		"object-shorthand": ["error", "always"],
	},
	env: {
		browser: true,
		es2017: true,
		node: true,
	},
};


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report--chat-ui-.md
================================================
---
name: Bug Report (chat-ui)
about: Use this for confirmed issues with chat-ui
title: ""
labels: bug
assignees: ""
---

## Bug description

<!-- A clear and concise description of what the bug is. -->

## Steps to reproduce

<!-- Steps to reproduce the issue -->

## Screenshots

<!-- If applicable, add screenshots to help explain your problem. -->

## Context

### Logs

<!-- Add any logs that are relevant to your issue. Could be browser or server logs. Wrap in code blocks. -->

```
// logs here if relevant
```

### Specs

- **OS**:
- **Browser**:
- **chat-ui commit**:

### Config

<!-- Add the environment variables you've used to setup chat-ui, making sure to redact any secrets. -->

## Notes

<!-- Anything else relevant to help the issue get solved -->


================================================
FILE: .github/ISSUE_TEMPLATE/config-support.md
================================================
---
name: Config Support
about: Help with setting up chat-ui locally
title: ""
labels: support
assignees: ""
---

**Please use the discussions on GitHub** for getting help with setting things up instead of opening an issue: https://github.com/huggingface/chat-ui/discussions


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request--chat-ui-.md
================================================
---
name: Feature Request (chat-ui)
about: Suggest new features to be added to chat-ui
title: ""
labels: enhancement
assignees: ""
---

## Describe your feature request

<!-- Short description of what this is about -->

## Screenshots (if relevant)

## Implementation idea

<!-- If you know how this should be implemented in the codebase, share your thoughts. Let us know if you feel like implementing it yourself as well! -->


================================================
FILE: .github/ISSUE_TEMPLATE/huggingchat.md
================================================
---
name: HuggingChat
about: Requests & reporting outages on HuggingChat, the hosted version of chat-ui.
title: ""
labels: huggingchat
assignees: ""
---

**Do not use GitHub issues** for requesting models on HuggingChat or reporting issues with HuggingChat being down/overloaded.

**Use the discussions page on the hub instead:** https://huggingface.co/spaces/huggingchat/chat-ui/discussions


================================================
FILE: .github/release.yml
================================================
changelog:
  exclude:
    labels:
      - huggingchat
      - CI/CD
      - documentation
  categories:
    - title: Features
      labels:
        - enhancement
    - title: Bugfixes
      labels:
        - bug
    - title: Other changes
      labels:
        - "*"


================================================
FILE: .github/workflows/build-docs.yml
================================================
name: Build documentation

on:
  push:
    branches:
      - main
      - v*-release

jobs:
  build:
    uses: huggingface/doc-builder/.github/workflows/build_main_documentation.yml@main
    with:
      commit_sha: ${{ github.sha }}
      package: chat-ui
      additional_args: --not_python_module
    secrets:
      token: ${{ secrets.HUGGINGFACE_PUSH }}
      hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }}


================================================
FILE: .github/workflows/build-image.yml
================================================
name: Build and Publish Image

permissions:
  packages: write

on:
  push:
    branches:
      - "main"
  pull_request:
    branches:
      - "*"
    paths:
      - "Dockerfile"
      - "entrypoint.sh"
  workflow_dispatch:
  release:
    types: [published, edited]

jobs:
  build-and-publish-image-with-db:
    runs-on:
      group: aws-general-8-plus
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Extract package version
        id: package-version
        run: |
          VERSION=$(jq -r .version package.json)
          echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
          MAJOR=$(echo $VERSION | cut -d '.' -f1)
          echo "MAJOR=$MAJOR" >> $GITHUB_OUTPUT
          MINOR=$(echo $VERSION | cut -d '.' -f1).$(echo $VERSION | cut -d '.' -f2)
          echo "MINOR=$MINOR" >> $GITHUB_OUTPUT

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/huggingface/chat-ui-db
          tags: |
            type=raw,value=${{ steps.package-version.outputs.VERSION }},enable=${{github.event_name == 'release'}}
            type=raw,value=${{ steps.package-version.outputs.MAJOR }},enable=${{github.event_name == 'release'}}
            type=raw,value=${{ steps.package-version.outputs.MINOR }},enable=${{github.event_name == 'release'}}
            type=raw,value=latest,enable={{is_default_branch}}
            type=sha,enable={{is_default_branch}}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v4.5.0

      - name: Build and Publish Docker Image with DB
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64,linux/arm64
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            INCLUDE_DB=true
            PUBLIC_COMMIT_SHA=${{ env.GITHUB_SHA_SHORT }}
  build-and-publish-image-nodb:
    runs-on:
      group: aws-general-8-plus
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Extract package version
        id: package-version
        run: |
          VERSION=$(jq -r .version package.json)
          echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
          MAJOR=$(echo $VERSION | cut -d '.' -f1)
          echo "MAJOR=$MAJOR" >> $GITHUB_OUTPUT
          MINOR=$(echo $VERSION | cut -d '.' -f1).$(echo $VERSION | cut -d '.' -f2)
          echo "MINOR=$MINOR" >> $GITHUB_OUTPUT

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            ghcr.io/huggingface/chat-ui
          tags: |
            type=raw,value=${{ steps.package-version.outputs.VERSION }},enable=${{github.event_name == 'release'}}
            type=raw,value=${{ steps.package-version.outputs.MAJOR }},enable=${{github.event_name == 'release'}}
            type=raw,value=${{ steps.package-version.outputs.MINOR }},enable=${{github.event_name == 'release'}}
            type=raw,value=latest,enable={{is_default_branch}}
            type=sha,enable={{is_default_branch}}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v4.5.0

      - name: Build and Publish Docker Image without DB
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64,linux/arm64
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            INCLUDE_DB=false
            PUBLIC_COMMIT_SHA=${{ env.GITHUB_SHA_SHORT }}


================================================
FILE: .github/workflows/build-pr-docs.yml
================================================
name: Build PR Documentation

on:
  pull_request:
    paths:
      - "docs/source/**"
      - ".github/workflows/build-pr-docs.yml"

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build:
    uses: huggingface/doc-builder/.github/workflows/build_pr_documentation.yml@main
    with:
      commit_sha: ${{ github.event.pull_request.head.sha }}
      pr_number: ${{ github.event.number }}
      package: chat-ui
      additional_args: --not_python_module


================================================
FILE: .github/workflows/deploy-dev.yml
================================================
name: Deploy to ephemeral
on:
  pull_request:
    types: [opened, reopened, synchronize, labeled, unlabeled]

jobs:
  branch-slug:
    uses: ./.github/workflows/slugify.yaml
    with:
      value: ${{ github.head_ref }}

  deploy-dev:
    if: contains(github.event.pull_request.labels.*.name, 'preview')
    runs-on: ubuntu-latest
    needs: branch-slug
    environment:
      name: dev
      url: https://${{ needs.branch-slug.outputs.slug }}.chat-dev.huggingface.tech/chat/
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v4.5.0

      - name: Set GITHUB_SHA_SHORT from PR
        if: env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT != null
        run: echo "GITHUB_SHA_SHORT=${{ env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT }}" >> $GITHUB_ENV

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            huggingface/chat-ui
          tags: |
            type=raw,value=dev-${{ env.GITHUB_SHA_SHORT }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build and Publish HuggingChat image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64
          cache-to: type=gha,mode=max,scope=amd64
          cache-from: type=gha,scope=amd64
          provenance: false
          build-args: |
            INCLUDE_DB=false
            APP_BASE=/chat
            PUBLIC_COMMIT_SHA=${{ env.GITHUB_SHA_SHORT }}


================================================
FILE: .github/workflows/deploy-prod.yml
================================================
name: Deploy to k8s
on:
  # run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build-and-publish-huggingchat-image:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            huggingface/chat-ui
          tags: |
            type=raw,value=latest,enable={{is_default_branch}}
            type=sha,enable=true,prefix=sha-,format=short,sha-len=8

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v4.5.0

      - name: Build and Publish HuggingChat image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64
          cache-to: type=gha,mode=max,scope=amd64
          cache-from: type=gha,scope=amd64
          provenance: false
          build-args: |
            INCLUDE_DB=false
            APP_BASE=/chat
            PUBLIC_COMMIT_SHA=${{ env.GITHUB_SHA_SHORT }}
  deploy:
    name: Deploy on prod
    runs-on: ubuntu-latest
    needs: ["build-and-publish-huggingchat-image"]
    steps:
      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v4.5.0

      - name: Gen values
        run: |
          VALUES=$(cat <<-END
          image:
            tag: "sha-${{ env.GITHUB_SHA_SHORT }}"
          END
          )
          echo "VALUES=$(echo "$VALUES" | yq -o=json | jq tostring)" >> $GITHUB_ENV

      - name: Deploy on infra-deployments
        uses: aurelien-baudet/workflow-dispatch@v2
        with:
          workflow: Update application single value
          repo: huggingface/infra-deployments
          wait-for-completion: true
          wait-for-completion-interval: 10s
          display-workflow-run-url-interval: 10s
          ref: refs/heads/main
          token: ${{ secrets.GIT_TOKEN_INFRA_DEPLOYMENT }}
          inputs: '{"path": "hub/chat-ui/chat-ui.yaml", "value": ${{ env.VALUES }}, "url": "${{ github.event.head_commit.url }}"}'


================================================
FILE: .github/workflows/lint-and-test.yml
================================================
name: Lint and test

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-node@v3
        with:
          node-version: "20"
          cache: "npm"
      - run: |
          npm install ci
      - name: "Checking lint/format errors"
        run: |
          npm run lint
      - name: "Checking type errors"
        run: |
          npm run check

  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "20"
          cache: "npm"
      - run: |
          npm ci
          npx playwright install
      - name: "Tests"
        run: |
          npm run test

  build-check:
    runs-on:
      group: aws-general-8-plus
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
      - name: Build Docker image
        run: |
          docker build \
            --build-arg INCLUDE_DB=true \
            -t chat-ui-test:latest .

      - name: Run Docker container
        run: |
          export DOTENV_LOCAL=$(<.env.ci)
          docker run -d --rm --network=host \
            --name chat-ui-test \
            -e DOTENV_LOCAL="$DOTENV_LOCAL" \
            chat-ui-test:latest

      - name: Wait for server to start
        run: |
          for i in {1..10}; do
            if curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/ | grep -q "200"; then
              echo "Server is up"
              exit 0
            fi
            echo "Waiting for server..."
            sleep 2
          done
          echo "Server did not start in time"
          docker logs chat-ui-test
          exit 1

      - name: Stop Docker container
        if: always()
        run: |
          docker stop chat-ui-test || true


================================================
FILE: .github/workflows/slugify.yaml
================================================
name: Generate Branch Slug

on:
  workflow_call:
    inputs:
      value:
        description: "Value to slugify"
        required: true
        type: string
    outputs:
      slug:
        description: "Slugified value"
        value: ${{ jobs.generate-slug.outputs.slug }}

jobs:
  generate-slug:
    runs-on: ubuntu-latest
    outputs:
      slug: ${{ steps.slugify.outputs.slug }}

    steps:
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.21"

      - name: Generate slug
        id: slugify
        run: |
          # Create working directory
          mkdir -p $HOME/slugify
          cd $HOME/slugify

          # Create Go script
          cat > main.go << 'EOF'
          package main

          import (
              "fmt"
              "os"
              "github.com/gosimple/slug"
          )

          func main() {
              if len(os.Args) < 2 {
                  fmt.Println("Usage: slugify <text>")
                  os.Exit(1)
              }

              text := os.Args[1]
              slugged := slug.Make(text)
              fmt.Println(slugged)
          }
          EOF

          # Initialize module and install dependency
          go mod init slugify
          go mod tidy
          go get github.com/gosimple/slug

          # Build
          go build -o slugify main.go

          # Generate slug
          VALUE="${{ inputs.value }}"
          echo "Input value: $VALUE"

          SLUG=$(./slugify "$VALUE")
          echo "Generated slug: $SLUG"

          # Export
          echo "slug=$SLUG" >> $GITHUB_OUTPUT


================================================
FILE: .github/workflows/trufflehog.yml
================================================
on:
  push:

name: Secret Leaks

jobs:
  trufflehog:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Secret Scanning
        uses: trufflesecurity/trufflehog@main
        with:
          extra_args: --results=verified,unknown


================================================
FILE: .github/workflows/upload-pr-documentation.yml
================================================
name: Upload PR Documentation

on:
  workflow_run:
    workflows: ["Build PR Documentation"]
    types:
      - completed

jobs:
  build:
    uses: huggingface/doc-builder/.github/workflows/upload_pr_documentation.yml@main
    with:
      package_name: chat-ui
    secrets:
      hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }}
      comment_bot_token: ${{ secrets.COMMENT_BOT_TOKEN }}


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
SECRET_CONFIG
.idea
!.env.ci
!.env
gcp-*.json
db
models/*
!models/add-your-models-here.txt
.claude/*
!.claude/skills/

================================================
FILE: .husky/lint-stage-config.js
================================================
export default {
	"*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix", "eslint"],
	"*.json": ["prettier --write"],
};


================================================
FILE: .husky/pre-commit
================================================
set -e
npx lint-staged --config ./.husky/lint-stage-config.js


================================================
FILE: .npmrc
================================================
engine-strict=true


================================================
FILE: .prettierignore
================================================
.DS_Store
node_modules
/build
/.svelte-kit
/package
/chart
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock


================================================
FILE: .prettierrc
================================================
{
	"useTabs": true,
	"trailingComma": "es5",
	"printWidth": 100,
	"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
	"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}


================================================
FILE: .vscode/launch.json
================================================
{
	"version": "0.2.0",
	"configurations": [
		{
			"command": "npm run dev",
			"name": "Run development server",
			"request": "launch",
			"type": "node-terminal"
		}
	]
}


================================================
FILE: .vscode/settings.json
================================================
{
	"editor.formatOnSave": true,
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	"editor.codeActionsOnSave": {
		"source.fixAll": "explicit"
	},
	"eslint.validate": ["javascript", "svelte"],
	"[svelte]": {
		"editor.defaultFormatter": "esbenp.prettier-vscode"
	},
	"[typescript]": {
		"editor.defaultFormatter": "esbenp.prettier-vscode"
	}
}


================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

Chat UI is a SvelteKit application that provides a chat interface for LLMs. It powers HuggingChat (hf.co/chat). The app speaks exclusively to OpenAI-compatible APIs via `OPENAI_BASE_URL`.

## Commands

```bash
npm run dev          # Start dev server on localhost:5173
npm run build        # Production build
npm run preview      # Preview production build
npm run check        # TypeScript validation (svelte-kit sync + svelte-check)
npm run lint         # Check formatting (Prettier) and linting (ESLint)
npm run format       # Auto-format with Prettier
npm run test         # Run all tests (Vitest)
```

### Running a Single Test

```bash
npx vitest run path/to/file.spec.ts        # Run specific test file
npx vitest run -t "test name"              # Run test by name
npx vitest --watch path/to/file.spec.ts    # Watch mode for single file
```

### Test Environments

Tests are split into three workspaces (configured in vite.config.ts):

- **Client tests** (`*.svelte.test.ts`): Browser environment with Playwright
- **SSR tests** (`*.ssr.test.ts`): Node environment for server-side rendering
- **Server tests** (`*.test.ts`, `*.spec.ts`): Node environment for utilities

## Architecture

### Stack

- **SvelteKit 2** with Svelte 5 (uses runes: `$state`, `$effect`, `$bindable`)
- **MongoDB** for persistence (auto-fallback to in-memory with MongoMemoryServer when `MONGODB_URL` not set)
- **TailwindCSS** for styling

### Key Directories

```
src/
├── lib/
│   ├── components/       # Svelte components (chat/, mcp/, voice/, icons/)
│   ├── server/
│   │   ├── api/utils/       # Shared API helpers (auth, superjson, model/conversation resolvers)
│   │   ├── textGeneration/  # LLM streaming pipeline
│   │   ├── mcp/          # Model Context Protocol integration
│   │   ├── router/       # Smart model routing (Omni)
│   │   ├── database.ts   # MongoDB collections
│   │   ├── models.ts     # Model registry from OPENAI_BASE_URL/models
│   │   └── auth.ts       # OpenID Connect authentication
│   ├── types/            # TypeScript interfaces (Conversation, Message, User, Model, etc.)
│   ├── stores/           # Svelte stores for reactive state
│   └── utils/            # Helpers (tree/, marked.ts, auth.ts, etc.)
├── routes/               # SvelteKit file-based routing
│   ├── conversation/[id]/  # Chat page + streaming endpoint
│   ├── settings/         # User settings pages
│   ├── api/              # Legacy v1 API endpoints (mcp, transcribe, fetch-url)
│   ├── api/v2/           # REST API endpoints (+server.ts)
│   └── r/[id]/           # Shared conversation view
```

### Text Generation Flow

1. User sends message via `POST /conversation/[id]`
2. Server validates user, fetches conversation history
3. Builds message tree structure (see `src/lib/utils/tree/`)
4. Calls LLM endpoint via OpenAI client
5. Streams response back, stores in MongoDB

### Model Context Protocol (MCP)

MCP servers are configured via `MCP_SERVERS` env var. When enabled, tools are exposed as OpenAI function calls. The router can auto-select tools-capable models when `LLM_ROUTER_ENABLE_TOOLS=true`.

### LLM Router (Omni)

Smart routing via Arch-Router model. Configured with:

- `LLM_ROUTER_ROUTES_PATH`: JSON file defining routes
- `LLM_ROUTER_ARCH_BASE_URL`: Router endpoint
- Shortcuts: multimodal routes bypass router if `LLM_ROUTER_ENABLE_MULTIMODAL=true`

### Database Collections

- `conversations` - Chat sessions with nested messages
- `users` - User accounts (OIDC-backed)
- `sessions` - Session data
- `sharedConversations` - Public share links
- `settings` - User preferences

## Environment Setup

Copy `.env` to `.env.local` and configure:

```env
OPENAI_BASE_URL=https://router.huggingface.co/v1
OPENAI_API_KEY=hf_***
# MONGODB_URL is optional; omit for in-memory DB persisted to ./db
```

See `.env` for full list of variables including router config, MCP servers, auth, and feature flags.

## Code Conventions

- TypeScript strict mode enabled
- ESLint: no `any`, no non-null assertions
- Prettier: tabs, 100 char width, Tailwind class sorting
- Server vs client separation via SvelteKit conventions (`+page.server.ts` vs `+page.ts`)

## Feature Development Checklist

When building new features, consider:

1. **HuggingChat vs self-hosted**: Wrap HuggingChat-specific features with `publicConfig.isHuggingChat`
2. **Settings persistence**: Add new fields to `src/lib/types/Settings.ts`, update API endpoint at `src/routes/api/v2/user/settings/+server.ts`
3. **Rich dropdowns**: Use `bits-ui` (Select, DropdownMenu) instead of native elements when you need icons/images in options
4. **Scrollbars**: Use `scrollbar-custom` class for styled scrollbars
5. **Icons**: Custom icons in `$lib/components/icons/`, use Carbon (`~icons/carbon/*`) or Lucide (`~icons/lucide/*`) for standard icons
6. **Provider avatars**: Use `PROVIDERS_HUB_ORGS` from `@huggingface/inference` for HF provider avatar URLs


================================================
FILE: Dockerfile
================================================
# syntax=docker/dockerfile:1
ARG INCLUDE_DB=false

FROM node:24-slim AS base

# install dotenv-cli
RUN npm install -g dotenv-cli

# switch to a user that works for spaces
RUN userdel -r node
RUN useradd -m -u 1000 user
USER user

ENV HOME=/home/user \
    PATH=/home/user/.local/bin:$PATH

WORKDIR /app

# add a .env.local if the user doesn't bind a volume to it
RUN touch /app/.env.local

USER root
RUN apt-get update
RUN apt-get install -y libgomp1 libcurl4 curl dnsutils nano

# ensure npm cache dir exists before adjusting ownership
RUN mkdir -p /home/user/.npm && chown -R 1000:1000 /home/user/.npm

USER user


COPY --chown=1000 .env /app/.env
COPY --chown=1000 entrypoint.sh /app/entrypoint.sh
COPY --chown=1000 package.json /app/package.json
COPY --chown=1000 package-lock.json /app/package-lock.json

RUN chmod +x /app/entrypoint.sh

FROM node:24 AS builder

WORKDIR /app

COPY --link --chown=1000 package-lock.json package.json ./

ARG APP_BASE=
ARG PUBLIC_APP_COLOR=
ENV BODY_SIZE_LIMIT=15728640

RUN --mount=type=cache,target=/app/.npm \
    npm set cache /app/.npm && \
    npm ci

COPY --link --chown=1000 . .

RUN git config --global --add safe.directory /app && \
    npm run build

# mongo image
FROM mongo:7 AS mongo

# image to be used if INCLUDE_DB is false
FROM base AS local_db_false

# image to be used if INCLUDE_DB is true
FROM base AS local_db_true

# copy mongo from the other stage
COPY --from=mongo /usr/bin/mongo* /usr/bin/

ENV MONGODB_URL=mongodb://localhost:27017
USER root
RUN mkdir -p /data/db
RUN chown -R 1000:1000 /data/db
USER user
# final image
FROM local_db_${INCLUDE_DB} AS final

# build arg to determine if the database should be included
ARG INCLUDE_DB=false
ENV INCLUDE_DB=${INCLUDE_DB}

# svelte requires APP_BASE at build time so it must be passed as a build arg
ARG APP_BASE=
ARG PUBLIC_APP_COLOR=
ARG PUBLIC_COMMIT_SHA=
ENV PUBLIC_COMMIT_SHA=${PUBLIC_COMMIT_SHA}
ENV BODY_SIZE_LIMIT=15728640

#import the build & dependencies
COPY --from=builder --chown=1000 /app/build /app/build
COPY --from=builder --chown=1000 /app/node_modules /app/node_modules

CMD ["/bin/bash", "-c", "/app/entrypoint.sh"]


================================================
FILE: LICENSE
================================================
Copyright 2018- The Hugging Face 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.md
================================================
## Privacy

> Last updated: Sep 15, 2025

Basics:

- Sign-in: You authenticate with your Hugging Face account.
- Conversation history: Stored so you can access past chats; you can delete any conversation at any time from the UI.

🗓 Please also consult huggingface.co's main privacy policy at <https://huggingface.co/privacy>. To exercise any of your legal privacy rights, please send an email to <privacy@huggingface.co>.

## Data handling and processing

HuggingChat uses Hugging Face’s Inference Providers to access models from multiple partners via a single API. Depending on the model and availability, inference runs with the corresponding provider.

- Inference Providers documentation: <https://huggingface.co/docs/inference-providers>
- Security & Compliance: <https://huggingface.co/docs/inference-providers/security>

Security and routing facts

- Hugging Face does not store any user data for training purposes.
- Hugging Face does not store the request body or the response when routing requests through Hugging Face.
- Logs are kept for debugging purposes for up to 30 days, but no user data or tokens are stored in those logs.
- Inference Provider routing uses TLS/SSL to encrypt data in transit.
- The Hugging Face Hub (which Inference Providers is a feature of) is SOC 2 Type 2 certified. See <https://huggingface.co/docs/hub/security>.

External providers are responsible for their own security and data handling. Please consult each provider’s respective security and privacy policies via the Inference Providers documentation linked above.

## Technical details

[![chat-ui](https://img.shields.io/github/stars/huggingface/chat-ui)](https://github.com/huggingface/chat-ui)

The app is completely open source, and further development takes place on the [huggingface/chat-ui](https://github.com/huggingface/chat-ui) GitHub repo. We're always open to contributions!

You can find the production configuration for HuggingChat [here](https://github.com/huggingface/chat-ui/blob/main/chart/env/prod.yaml).

HuggingChat connects to the OpenAI‑compatible Inference Providers router at `https://router.huggingface.co/v1` to access models across multiple providers. Provider selection may be automatic or fixed depending on the model configuration.

We welcome any feedback on this app: please participate in the public discussion at <https://huggingface.co/spaces/huggingchat/chat-ui/discussions>

<a target="_blank" href="https://huggingface.co/spaces/huggingchat/chat-ui/discussions"><img src="https://huggingface.co/datasets/huggingface/badges/raw/main/open-a-discussion-xl.svg" title="open a discussion"></a>


================================================
FILE: README.md
================================================
# Chat UI

![Chat UI repository thumbnail](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/chat-ui/chat-ui-2026.png)

A chat interface for LLMs. It is a SvelteKit app and it powers the [HuggingChat app on hf.co/chat](https://huggingface.co/chat).

0. [Quickstart](#quickstart)
1. [Database Options](#database-options)
2. [Launch](#launch)
3. [Optional Docker Image](#optional-docker-image)
4. [Extra parameters](#extra-parameters)
5. [Building](#building)

> [!NOTE]
> Chat UI only supports OpenAI-compatible APIs via `OPENAI_BASE_URL` and the `/models` endpoint. Provider-specific integrations (legacy `MODELS` env var, GGUF discovery, embeddings, web-search helpers, etc.) are removed, but any service that speaks the OpenAI protocol (llama.cpp server, Ollama, OpenRouter, etc. will work by default).

> [!NOTE]
> The old version is still available on the [legacy branch](https://github.com/huggingface/chat-ui/tree/legacy)

## Quickstart

Chat UI speaks to OpenAI-compatible APIs only. The fastest way to get running is with the Hugging Face Inference Providers router plus your personal Hugging Face access token.

**Step 1 – Create `.env.local`:**

```env
OPENAI_BASE_URL=https://router.huggingface.co/v1
OPENAI_API_KEY=hf_************************
```

`OPENAI_API_KEY` can come from any OpenAI-compatible endpoint you plan to call. Pick the combo that matches your setup and drop the values into `.env.local`:

| Provider                                      | Example `OPENAI_BASE_URL`          | Example key env                                                         |
| --------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------- |
| Hugging Face Inference Providers router       | `https://router.huggingface.co/v1` | `OPENAI_API_KEY=hf_xxx` (or `HF_TOKEN` legacy alias)                    |
| llama.cpp server (`llama.cpp --server --api`) | `http://127.0.0.1:8080/v1`         | `OPENAI_API_KEY=sk-local-demo` (any string works; llama.cpp ignores it) |
| Ollama (with OpenAI-compatible bridge)        | `http://127.0.0.1:11434/v1`        | `OPENAI_API_KEY=ollama`                                                 |
| OpenRouter                                    | `https://openrouter.ai/api/v1`     | `OPENAI_API_KEY=sk-or-v1-...`                                           |
| Poe                                           | `https://api.poe.com/v1`           | `OPENAI_API_KEY=pk_...`                                                 |

Check the root [`.env` template](./.env) for the full list of optional variables you can override.

**Step 2 – Install and launch the dev server:**

```bash
git clone https://github.com/huggingface/chat-ui
cd chat-ui
npm install
npm run dev -- --open
```

You now have Chat UI running locally. Open the browser and start chatting.

## Database Options

Chat history, users, settings, files, and stats all live in MongoDB. You can point Chat UI at any MongoDB 6/7 deployment.

> [!TIP]
> For quick local development, you can skip this section. When `MONGODB_URL` is not set, Chat UI falls back to an embedded MongoDB that persists to `./db`.

### MongoDB Atlas (managed)

1. Create a free cluster at [mongodb.com](https://www.mongodb.com/pricing).
2. Add your IP (or `0.0.0.0/0` for development) to the network access list.
3. Create a database user and copy the connection string.
4. Paste that string into `MONGODB_URL` in `.env.local`. Keep the default `MONGODB_DB_NAME=chat-ui` or change it per environment.

Atlas keeps MongoDB off your laptop, which is ideal for teams or cloud deployments.

### Local MongoDB (container)

If you prefer to run MongoDB in a container:

```bash
docker run -d -p 27017:27017 --name mongo-chatui mongo:latest
```

Then set `MONGODB_URL=mongodb://localhost:27017` in `.env.local`.

## Launch

After configuring your environment variables, start Chat UI with:

```bash
npm install
npm run dev
```

The dev server listens on `http://localhost:5173` by default. Use `npm run build` / `npm run preview` for production builds.

## Optional Docker Image

The `chat-ui-db` image bundles MongoDB inside the container:

```bash
docker run \
  -p 3000:3000 \
  -e OPENAI_BASE_URL=https://router.huggingface.co/v1 \
  -e OPENAI_API_KEY=hf_*** \
  -v chat-ui-data:/data \
  ghcr.io/huggingface/chat-ui-db:latest
```

All environment variables accepted in `.env.local` can be provided as `-e` flags.

## Extra parameters

### Theming

You can use a few environment variables to customize the look and feel of chat-ui. These are by default:

```env
PUBLIC_APP_NAME=ChatUI
PUBLIC_APP_ASSETS=chatui
PUBLIC_APP_DESCRIPTION="Making the community's best AI chat models available to everyone."
PUBLIC_APP_DATA_SHARING=
```

- `PUBLIC_APP_NAME` The name used as a title throughout the app.
- `PUBLIC_APP_ASSETS` Is used to find logos & favicons in `static/$PUBLIC_APP_ASSETS`, current options are `chatui` and `huggingchat`.
- `PUBLIC_APP_DATA_SHARING` Can be set to 1 to add a toggle in the user settings that lets your users opt-in to data sharing with models creator.

### Models

Models are discovered from `${OPENAI_BASE_URL}/models`, and you can optionally override their metadata via the `MODELS` env var (JSON5). Legacy provider‑specific integrations and GGUF discovery are removed. Authorization uses `OPENAI_API_KEY` (preferred). `HF_TOKEN` remains a legacy alias.

### LLM Router (Optional)

Chat UI can perform server-side smart routing using [katanemo/Arch-Router-1.5B](https://huggingface.co/katanemo/Arch-Router-1.5B) as the routing model without running a separate router service. The UI exposes a virtual model alias called "Omni" (configurable) that, when selected, chooses the best route/model for each message.

- Provide a routes policy JSON via `LLM_ROUTER_ROUTES_PATH`. No sample file ships with this branch, so you must point the variable to a JSON array you create yourself (for example, commit one in your project like `config/routes.chat.json`). Each route entry needs `name`, `description`, `primary_model`, and optional `fallback_models`.
- Configure the Arch router selection endpoint with `LLM_ROUTER_ARCH_BASE_URL` (OpenAI-compatible `/chat/completions`) and `LLM_ROUTER_ARCH_MODEL` (e.g. `router/omni`). The Arch call reuses `OPENAI_API_KEY` for auth.
- Map `other` to a concrete route via `LLM_ROUTER_OTHER_ROUTE` (default: `casual_conversation`). If Arch selection fails, calls fall back to `LLM_ROUTER_FALLBACK_MODEL`.
- Selection timeout can be tuned via `LLM_ROUTER_ARCH_TIMEOUT_MS` (default 10000).
- Omni alias configuration: `PUBLIC_LLM_ROUTER_ALIAS_ID` (default `omni`), `PUBLIC_LLM_ROUTER_DISPLAY_NAME` (default `Omni`), and optional `PUBLIC_LLM_ROUTER_LOGO_URL`.

When you select Omni in the UI, Chat UI will:

- Call the Arch endpoint once (non-streaming) to pick the best route for the last turns.
- Emit RouterMetadata immediately (route and actual model used) so the UI can display it.
- Stream from the selected model via your configured `OPENAI_BASE_URL`. On errors, it tries route fallbacks.

Tool and multimodal shortcuts:

- Multimodal: If `LLM_ROUTER_ENABLE_MULTIMODAL=true` and the user sends an image, the router bypasses Arch and uses the model specified in `LLM_ROUTER_MULTIMODAL_MODEL`. Route name: `multimodal`.
- Tools: If `LLM_ROUTER_ENABLE_TOOLS=true` and the user has at least one MCP server enabled, the router bypasses Arch and uses `LLM_ROUTER_TOOLS_MODEL`. If that model is missing or misconfigured, it falls back to Arch routing. Route name: `agentic`.

### MCP Tools (Optional)

Chat UI can call tools exposed by Model Context Protocol (MCP) servers and feed results back to the model using OpenAI function calling. You can preconfigure trusted servers via env, let users add their own, and optionally have the Omni router auto‑select a tools‑capable model.

Configure servers (base list for all users):

```env
# JSON array of servers: name, url, optional headers
MCP_SERVERS=[
  {"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"},
  {"name": "Hugging Face MCP Login", "url": "https://hf.co/mcp?login"}
]

# Forward the signed-in user's Hugging Face token to the official HF MCP login endpoint
# when no Authorization header is set on that server entry.
MCP_FORWARD_HF_USER_TOKEN=true
```

Enable router tool path (Omni):

- Set `LLM_ROUTER_ENABLE_TOOLS=true` and choose a tools‑capable target with `LLM_ROUTER_TOOLS_MODEL=<model id or name>`.
- The target must support OpenAI tools/function calling. Chat UI surfaces a “tools” badge on models that advertise this; you can also force‑enable it per‑model in settings (see below).

Use tools in the UI:

- Open “MCP Servers” from the top‑right menu or from the `+` menu in the chat input to add servers, toggle them on, and run Health Check. The server card lists available tools.
- When a model calls a tool, the message shows a compact “tool” block with parameters, a progress bar while running, and the result (or error). Results are also provided back to the model for follow‑up.

Per‑model overrides:

- In Settings → Model, you can toggle “Tool calling (functions)” and “Multimodal input” per model. These overrides apply even if the provider metadata doesn’t advertise the capability.

## Building

To create a production version of your app:

```bash
npm run build
```

You can preview the production build with `npm run preview`.

> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.


================================================
FILE: chart/Chart.yaml
================================================
apiVersion: v2
name: chat-ui
version: 0.0.1-latest
type: application
icon: https://huggingface.co/front/assets/huggingface_logo-noborder.svg


================================================
FILE: chart/env/dev.yaml
================================================
image:
  repository: huggingface
  name: chat-ui

#nodeSelector:
#  role-huggingchat: "true"
#
#tolerations:
#  - key: "huggingface.co/huggingchat"
#    operator: "Equal"
#    value: "true"
#    effect: "NoSchedule"

serviceAccount:
  enabled: true
  create: true
  name: huggingchat-ephemeral

ingress:
  enabled: false

ingressInternal:
  enabled: true
  path: "/chat"
  annotations:
    external-dns.alpha.kubernetes.io/hostname: "*.chat-dev.huggingface.tech"
    alb.ingress.kubernetes.io/healthcheck-path: "/chat/healthcheck"
    alb.ingress.kubernetes.io/listen-ports: "[{\"HTTP\": 80}, {\"HTTPS\": 443}]"
    alb.ingress.kubernetes.io/group.name: "chat-dev-internal-public"
    alb.ingress.kubernetes.io/load-balancer-name: "chat-dev-internal-public"
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/tags: "Env=prod,Project=hub,Terraform=true"
    alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30
    alb.ingress.kubernetes.io/target-type: "ip"
    alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:707930574880:certificate/bc3eb446-1c04-432c-ac6b-946a88d725da"
    kubernetes.io/ingress.class: "alb"

envVars:
  TEST: "test"
  COUPLE_SESSION_WITH_COOKIE_NAME: "token"
  OPENID_SCOPES: "openid profile inference-api read-mcp read-billing"
  USE_USER_TOKEN: "true"
  MCP_FORWARD_HF_USER_TOKEN: "true"
  AUTOMATIC_LOGIN: "false"

  ADDRESS_HEADER: "X-Forwarded-For"
  APP_BASE: "/chat"
  ALLOW_IFRAME: "false"
  COOKIE_SAMESITE: "lax"
  COOKIE_SECURE: "true"
  EXPOSE_API: "true"
  METRICS_ENABLED: "true"
  LOG_LEVEL: "debug"
  NODE_LOG_STRUCTURED_DATA: "true"

  OPENAI_BASE_URL: "https://router.huggingface.co/v1"
  PUBLIC_APP_ASSETS: "huggingchat"
  PUBLIC_APP_NAME: "HuggingChat"
  PUBLIC_APP_DESCRIPTION: "Making the community's best AI chat models available to everyone"
  PUBLIC_ORIGIN: ""
  PUBLIC_PLAUSIBLE_SCRIPT_URL: "https://plausible.io/js/pa-Io_oigECawqdlgpf5qvHb.js"

  TASK_MODEL: "Qwen/Qwen3-4B-Instruct-2507"
  LLM_ROUTER_ARCH_BASE_URL: "https://router.huggingface.co/v1"
  LLM_ROUTER_ROUTES_PATH: "build/client/chat/huggingchat/routes.chat.json"
  LLM_ROUTER_ARCH_MODEL: "katanemo/Arch-Router-1.5B"
  LLM_ROUTER_OTHER_ROUTE: "casual_conversation"
  LLM_ROUTER_ARCH_TIMEOUT_MS: "10000"
  LLM_ROUTER_ENABLE_MULTIMODAL: "true"
  LLM_ROUTER_MULTIMODAL_MODEL: "Qwen/Qwen3.5-397B-A17B"
  LLM_ROUTER_ENABLE_TOOLS: "true"
  LLM_ROUTER_TOOLS_MODEL: "moonshotai/Kimi-K2-Instruct-0905"
  TRANSCRIPTION_MODEL: "openai/whisper-large-v3-turbo"
  MCP_SERVERS: >
    [{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp?tools=web_search_exa,get_code_context_exa,crawling_exa"}, {"name": "Hugging Face", "url": "https://hf.co/mcp?login"}]
  MCP_TOOL_TIMEOUT_MS: "120000"
  PUBLIC_LLM_ROUTER_DISPLAY_NAME: "Omni"
  PUBLIC_LLM_ROUTER_LOGO_URL: "https://cdn-uploads.huggingface.co/production/uploads/5f17f0a0925b9863e28ad517/C5V0v1xZXv6M7FXsdJH9b.png"
  PUBLIC_LLM_ROUTER_ALIAS_ID: "omni"
  MODELS: >
    [
      { "id": "Qwen/Qwen3.5-9B", "description": "Dense multimodal hybrid with 262K context excelling at reasoning on-device." },
      { "id": "CohereLabs/tiny-aya-global", "description": "Tiny multilingual assistant covering 70+ languages for on-device deployment." },
      { "id": "CohereLabs/tiny-aya-earth", "description": "Regional Aya for African languages with culturally tuned on-device inference." },
      { "id": "CohereLabs/tiny-aya-fire", "description": "Regional Aya for South Asian languages with culturally tuned on-device inference." },
      { "id": "CohereLabs/tiny-aya-water", "description": "Regional Aya for Asia-Pacific and European multilingual on-device tasks." },
      { "id": "Qwen/Qwen3.5-122B-A10B", "description": "Multimodal MoE excelling at agentic tool use with 1M context and 201 languages." },
      { "id": "Qwen/Qwen3.5-35B-A3B", "description": "Compact multimodal MoE with hybrid DeltaNet, 1M context, and 201 languages." },
      { "id": "Qwen/Qwen3.5-27B", "description": "Dense multimodal hybrid with top-tier reasoning density and 1M context." },
      { "id": "Qwen/Qwen3.5-397B-A17B", "description": "Native multimodal MoE with hybrid attention, 1M context, and 201 languages.", "parameters": { "max_tokens": 32768 } },
      { "id": "allenai/Olmo-3.1-32B-Think", "description": "Updated Olmo Think with extended RL for stronger math, code, and instruction following." },
      { "id": "MiniMaxAI/MiniMax-M2.5", "description": "Frontier 230B MoE agent for top-tier coding, tool calling, and fast inference." },
      { "id": "zai-org/GLM-5", "description": "Flagship 745B MoE for agentic reasoning, coding, and creative writing." },
      { "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", "description": "Flagship Qwen3 vision-language MoE for visual agents, documents, and GUI automation." },
      { "id": "google/gemma-3n-E4B-it", "description": "Mobile-first multimodal Gemma handling text, images, video, and audio on-device." },
      { "id": "nvidia/NVIDIA-Nemotron-Nano-9B-v2", "description": "Hybrid Mamba-Transformer with 128K context and controllable reasoning budget." },
      { "id": "mistralai/Mistral-7B-Instruct-v0.2", "description": "Efficient 7B instruction model with 32K context for dialogue and coding." },
      { "id": "Qwen/Qwen3-Coder-Next-FP8", "description": "FP8 Qwen3-Coder-Next for efficient inference with repository-scale coding agents." },
      { "id": "arcee-ai/Trinity-Mini", "description": "Compact US-built MoE for multi-turn agents, tool use, and structured outputs." },
      { "id": "Qwen/Qwen3-Coder-Next", "description": "Ultra-sparse coding MoE for repository-scale agents with 256K context." },
      { "id": "moonshotai/Kimi-K2.5", "description": "Native multimodal agent with agent swarms for parallel tool orchestration." },
      { "id": "allenai/Molmo2-8B", "description": "Open vision-language model excelling at video understanding, pointing, and object tracking." },
      { "id": "zai-org/GLM-4.7-Flash", "description": "Fast GLM-4.7 variant optimized for lower latency coding and agents." },
      { "id": "zai-org/GLM-4.7", "description": "Flagship GLM MoE for coding, reasoning, and agentic tool use." },
      { "id": "zai-org/GLM-4.7-FP8", "description": "FP8 GLM-4.7 for efficient inference with strong coding." },
      { "id": "MiniMaxAI/MiniMax-M2.1", "description": "MoE agent model with multilingual coding and fast outputs." },
      { "id": "XiaomiMiMo/MiMo-V2-Flash", "description": "Fast MoE reasoning model with speculative decoding for agents." },
      { "id": "Qwen/Qwen3-VL-32B-Instruct", "description": "Vision-language Qwen for documents, GUI agents, and visual reasoning." },
      { "id": "allenai/Olmo-3.1-32B-Instruct", "description": "Fully open chat model strong at tool use and dialogue." },
      { "id": "zai-org/AutoGLM-Phone-9B-Multilingual", "description": "Mobile agent for multilingual Android device automation." },
      { "id": "utter-project/EuroLLM-22B-Instruct-2512", "description": "European multilingual model for all EU languages and translation." },
      { "id": "dicta-il/DictaLM-3.0-24B-Thinking", "description": "Hebrew-English reasoning model with explicit thinking traces for bilingual QA and logic." },
      { "id": "EssentialAI/rnj-1-instruct", "description": "8B code and STEM model rivaling larger models on agentic coding, math, and tool use." },
      { "id": "MiniMaxAI/MiniMax-M2", "description": "Compact MoE model tuned for fast coding, agentic workflows, and long-context chat." },
      { "id": "PrimeIntellect/INTELLECT-3-FP8", "description": "FP8 INTELLECT-3 variant for cheaper frontier-level math, code, and general reasoning." },
      { "id": "Qwen/Qwen3-VL-30B-A3B-Instruct", "description": "Flagship Qwen3 vision-language model for high-accuracy image, text, and video reasoning." },
      { "id": "Qwen/Qwen3-VL-30B-A3B-Thinking", "description": "Thinking-mode Qwen3-VL that emits detailed multimodal reasoning traces for difficult problems." },
      { "id": "Qwen/Qwen3-VL-8B-Instruct", "description": "Smaller Qwen3 vision-language assistant for everyday multimodal chat, captioning, and analysis." },
      { "id": "aisingapore/Qwen-SEA-LION-v4-32B-IT", "description": "SEA-LION v4 Qwen optimized for Southeast Asian languages and regional enterprise workloads." },
      { "id": "allenai/Olmo-3-32B-Think", "description": "Fully open 32B thinking model excelling at stepwise math, coding, and research reasoning." },
      { "id": "allenai/Olmo-3-7B-Instruct", "description": "Lightweight Olmo assistant for instruction following, Q&A, and everyday open-source workflows." },
      { "id": "allenai/Olmo-3-7B-Think", "description": "7B Olmo reasoning model delivering transparent multi-step thinking on modest hardware." },
      { "id": "deepcogito/cogito-671b-v2.1", "description": "Frontier-scale 671B MoE focused on deep reasoning, math proofs, and complex coding." },
      { "id": "deepcogito/cogito-671b-v2.1-FP8", "description": "FP8 Cogito v2.1 making 671B-scale reasoning more affordable to serve and experiment with." },
      { "id": "deepseek-ai/DeepSeek-V3.2", "description": "Latest DeepSeek agent model combining strong reasoning, tool-use, and efficient long-context inference." },
      { "id": "moonshotai/Kimi-K2-Thinking", "description": "Reasoning-focused Kimi K2 variant for deep chain-of-thought and large agentic tool flows." },
      { "id": "nvidia/NVIDIA-Nemotron-Nano-12B-v2", "description": "NVIDIA Nano 12B general assistant for coding, chat, and agents with efficient deployment." },
      { "id": "ServiceNow-AI/Apriel-1.6-15b-Thinker", "description": "15B multimodal reasoning model with efficient thinking for enterprise and coding tasks." },
      { "id": "openai/gpt-oss-safeguard-20b", "description": "Safety-focused gpt-oss variant for content classification, policy enforcement, and LLM output filtering." },
      { "id": "zai-org/GLM-4.5", "description": "Flagship GLM agent model unifying advanced reasoning, coding, and tool-using capabilities." },
      { "id": "zai-org/GLM-4.5V-FP8", "description": "FP8 vision-language GLM-4.5V for efficient multilingual visual QA, understanding, and hybrid reasoning." },    
      { "id": "deepseek-ai/DeepSeek-V3.2-Exp", "description": "Experimental V3.2 release focused on faster, lower-cost inference with strong general reasoning and tool use." },
      { "id": "zai-org/GLM-4.6", "description": "Next-gen GLM with very long context and solid multilingual reasoning; good for agents and tools." },
      { "id": "Kwaipilot/KAT-Dev", "description": "Developer-oriented assistant tuned for coding, debugging, and lightweight agent workflows." },
      { "id": "Qwen/Qwen2.5-VL-72B-Instruct", "description": "Flagship multimodal Qwen (text+image) instruction model for high-accuracy visual reasoning and detailed explanations." },
      { "id": "deepseek-ai/DeepSeek-V3.1-Terminus", "description": "Refined V3.1 variant optimized for reliability on long contexts, structured outputs, and tool use." },
      { "id": "Qwen/Qwen3-VL-235B-A22B-Thinking", "description": "Deliberative multimodal Qwen that can produce step-wise visual+text reasoning traces for complex tasks." },
      { "id": "zai-org/GLM-4.6-FP8", "description": "FP8-optimized GLM-4.6 for faster/cheaper deployment with near-parity quality on most tasks." },
      { "id": "zai-org/GLM-4.6V", "description": "106B vision-language model with 128K context and native tool calling for multimodal agents.", "parameters": { "max_tokens": 8192 } },
      { "id": "zai-org/GLM-4.6V-Flash", "description": "9B lightweight vision model for fast local inference with tool calling and UI understanding." },
      { "id": "zai-org/GLM-4.6V-FP8", "description": "FP8-quantized GLM-4.6V for efficient multimodal deployment with native tool use." },
      { "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", "description": "Deliberative text-only 235B Qwen variant for transparent, step-by-step reasoning on hard problems." },
      { "id": "Qwen/Qwen3-Next-80B-A3B-Instruct", "description": "Instruction tuned Qwen for multilingual reasoning, coding, long contexts." },
      { "id": "Qwen/Qwen3-Next-80B-A3B-Thinking", "description": "Thinking mode Qwen that outputs explicit step by step reasoning." },
      { "id": "moonshotai/Kimi-K2-Instruct-0905", "description": "Instruction MoE strong coding and multi step reasoning, long context." },
      { "id": "openai/gpt-oss-20b", "description": "Efficient open model for reasoning and tool use, runs locally." },
      { "id": "swiss-ai/Apertus-8B-Instruct-2509", "description": "Open, multilingual, trained on compliant data transparent global assistant." },
      { "id": "openai/gpt-oss-120b", "description": "High performing open model suitable for large scale applications." },
      { "id": "Qwen/Qwen3-Coder-30B-A3B-Instruct", "description": "Code specialized Qwen long context strong generation and function calling." },
      { "id": "meta-llama/Llama-3.1-8B-Instruct", "description": "Instruction tuned Llama efficient conversational assistant with improved alignment." },
      { "id": "Qwen/Qwen2.5-VL-7B-Instruct", "description": "Vision language Qwen handles images and text for basic multimodal tasks." },
      { "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", "description": "Instruction tuned Qwen reliable general tasks with long context support." },
      { "id": "baidu/ERNIE-4.5-VL-28B-A3B-PT", "description": "Baidu multimodal MoE strong at complex vision language reasoning." },
      { "id": "baidu/ERNIE-4.5-0.3B-PT", "description": "Tiny efficient Baidu model surprisingly long context for lightweight chat." },
      { "id": "deepseek-ai/DeepSeek-R1", "description": "MoE reasoning model excels at math, logic, coding with steps." },
      { "id": "baidu/ERNIE-4.5-21B-A3B-PT", "description": "Efficient Baidu MoE competitive generation with fewer active parameters." },
      { "id": "swiss-ai/Apertus-70B-Instruct-2509", "description": "Open multilingual model trained on open data transparent and capable." },
      { "id": "Qwen/Qwen3-4B-Instruct-2507", "description": "Compact instruction Qwen great for lightweight assistants and apps." },
      { "id": "meta-llama/Llama-3.2-3B-Instruct", "description": "Small efficient Llama for basic conversations and instructions." },
      { "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", "description": "Huge Qwen coder repository scale understanding and advanced generation." },
      { "id": "meta-llama/Meta-Llama-3-8B-Instruct", "description": "Aligned, efficient Llama dependable open source assistant tasks." },
      { "id": "Qwen/Qwen3-4B-Thinking-2507", "description": "Small Qwen that emits transparent step by step reasoning." },
      { "id": "moonshotai/Kimi-K2-Instruct", "description": "MoE assistant strong coding, reasoning, agentic tasks, long context." },
      { "id": "zai-org/GLM-4.5V", "description": "Vision language MoE state of the art multimodal reasoning." },
      { "id": "zai-org/GLM-4.6", "description": "Hybrid reasoning model top choice for intelligent agent applications." },
      { "id": "deepseek-ai/DeepSeek-V3.1", "description": "Supports direct and thinking style reasoning within one model." },
      { "id": "Qwen/Qwen3-8B", "description": "Efficient Qwen assistant strong multilingual skills and formatting." },
      { "id": "Qwen/Qwen3-30B-A3B-Thinking-2507", "description": "Thinking mode Qwen explicit reasoning for complex interpretable tasks." },
      { "id": "google/gemma-3-27b-it", "description": "Multimodal Gemma long context strong text and image understanding." },
      { "id": "zai-org/GLM-4.5-Air", "description": "Efficient GLM strong reasoning and tool use at lower cost." },
      { "id": "HuggingFaceTB/SmolLM3-3B", "description": "Small multilingual long context model surprisingly strong reasoning." },
      { "id": "Qwen/Qwen3-30B-A3B", "description": "Qwen base model for general use or further fine tuning." },
      { "id": "Qwen/Qwen2.5-7B-Instruct", "description": "Compact instruction model solid for basic conversation and tasks." },
      { "id": "Qwen/Qwen3-32B", "description": "General purpose Qwen strong for complex queries and dialogues." },
      { "id": "Qwen/QwQ-32B", "description": "Preview Qwen showcasing next generation features and alignment." },
      { "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", "description": "Flagship instruction Qwen near state of the art across domains." },
      { "id": "meta-llama/Llama-3.3-70B-Instruct", "description": "Improved Llama alignment and structure powerful complex conversations." },
      { "id": "Qwen/Qwen2.5-VL-32B-Instruct", "description": "Multimodal Qwen advanced visual reasoning for complex image plus text." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B", "description": "Tiny distilled Qwen stepwise math and logic reasoning." },
      { "id": "Qwen/Qwen3-235B-A22B", "description": "Qwen base at flagship scale ideal for custom fine tuning." },
      { "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct", "description": "Processes text and images excels at summarization and cross modal reasoning." },
      { "id": "NousResearch/Hermes-4-70B", "description": "Steerable assistant strong reasoning and creativity highly helpful." },
      { "id": "Qwen/Qwen2.5-Coder-32B-Instruct", "description": "Code model strong generation and tool use bridges sizes." },
      { "id": "katanemo/Arch-Router-1.5B", "description": "Lightweight router model directs queries to specialized backends." },
      { "id": "meta-llama/Llama-3.2-1B-Instruct", "description": "Ultra small Llama handles basic Q and A and instructions." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", "description": "Distilled Qwen excels at stepwise logic in compact footprint." },
      { "id": "deepseek-ai/DeepSeek-V3", "description": "General language model direct answers strong creative and knowledge tasks." },
      { "id": "deepseek-ai/DeepSeek-V3-0324", "description": "Updated V3 better reasoning and coding strong tool use." },
      { "id": "CohereLabs/command-a-translate-08-2025", "description": "Translation focused Command model high quality multilingual translation." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", "description": "Distilled from R1 strong reasoning standout dense model." },
      { "id": "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT", "description": "Multimodal base text image pretraining for cross modal understanding." },
      { "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct", "description": "MoE multimodal Llama rivals top vision language models." },
      { "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", "description": "Quantized giant coder faster lighter retains advanced code generation." },
      { "id": "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B", "description": "Qwen3 variant with R1 reasoning improvements compact and capable." },
      { "id": "deepseek-ai/DeepSeek-R1-0528", "description": "R1 update improved reasoning, fewer hallucinations, adds function calling.", "parameters": { "max_tokens": 32000 } },
      { "id": "Qwen/Qwen3-14B", "description": "Balanced Qwen good performance and efficiency for assistants." },
      { "id": "MiniMaxAI/MiniMax-M1-80k", "description": "Long context MoE very fast excels at long range reasoning and code." },
      { "id": "Qwen/Qwen2.5-Coder-7B-Instruct", "description": "Efficient coding assistant for lightweight programming tasks." },
      { "id": "aisingapore/Gemma-SEA-LION-v4-27B-IT", "description": "Gemma SEA LION optimized for Southeast Asian languages or enterprise." },
      { "id": "CohereLabs/aya-expanse-8b", "description": "Small Aya Expanse broad knowledge and efficient general reasoning." },
      { "id": "baichuan-inc/Baichuan-M2-32B", "description": "Medical reasoning specialist fine tuned for clinical QA bilingual." },
      { "id": "Qwen/Qwen2.5-VL-72B-Instruct", "description": "Vision language Qwen detailed image interpretation and instructions." },
      { "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", "description": "FP8 Maverick efficient deployment retains top multimodal capability." },
      { "id": "zai-org/GLM-4.1V-9B-Thinking", "description": "Vision language with explicit reasoning strong for its size." },
      { "id": "zai-org/GLM-4.5-Air-FP8", "description": "FP8 efficient GLM Air hybrid reasoning with minimal compute." },
      { "id": "google/gemma-2-2b-it", "description": "Small Gemma instruction tuned safe responsible outputs easy deployment." },
      { "id": "arcee-ai/AFM-4.5B", "description": "Enterprise focused model strong CPU performance compliant and practical." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "description": "Llama distilled from R1 strong reasoning and structured outputs." },
      { "id": "CohereLabs/aya-vision-8b", "description": "Vision capable Aya handles images and text for basic multimodal." },
      { "id": "NousResearch/Hermes-3-Llama-3.1-405B", "description": "Highly aligned assistant excels at math, code, QA." },
      { "id": "Qwen/Qwen2.5-72B-Instruct", "description": "Accurate detailed instruction model supports tools and long contexts." },
      { "id": "meta-llama/Llama-Guard-4-12B", "description": "Safety guardrail model filters and enforces content policies." },
      { "id": "CohereLabs/command-a-vision-07-2025", "description": "Command model with image input captioning and visual QA." },
      { "id": "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", "description": "NVIDIA tuned Llama optimized throughput for research and production." },
      { "id": "meta-llama/Meta-Llama-3-70B-Instruct", "description": "Instruction tuned Llama improved reasoning and reliability over predecessors." },
      { "id": "NousResearch/Hermes-4-405B", "description": "Frontier Hermes hybrid reasoning excels at math, code, creativity." },
      { "id": "NousResearch/Hermes-2-Pro-Llama-3-8B", "description": "Small Hermes highly steerable maximized helpfulness for basics." },
      { "id": "google/gemma-2-9b-it", "description": "Gemma with improved accuracy and context safe, easy to deploy." },
      { "id": "Sao10K/L3-8B-Stheno-v3.2", "description": "Community Llama variant themed tuning and unique conversational style." },
      { "id": "deepcogito/cogito-v2-preview-llama-109B-MoE", "description": "MoE preview advanced reasoning tests DeepCogito v2 fine tuning." },
      { "id": "CohereLabs/c4ai-command-r-08-2024", "description": "Cohere Command variant instruction following with specialized tuning." },
      { "id": "baidu/ERNIE-4.5-300B-A47B-Base-PT", "description": "Large base model foundation for specialized language systems." },
      { "id": "CohereLabs/aya-expanse-32b", "description": "Aya Expanse large comprehensive knowledge and reasoning capabilities." },
      { "id": "CohereLabs/c4ai-command-a-03-2025", "description": "Updated Command assistant improved accuracy and general usefulness." },
      { "id": "CohereLabs/command-a-reasoning-08-2025", "description": "Command variant optimized for complex multi step logical reasoning." },
      { "id": "alpindale/WizardLM-2-8x22B", "description": "Multi expert WizardLM MoE approach for efficient high quality generation." },
      { "id": "tokyotech-llm/Llama-3.3-Swallow-70B-Instruct-v0.4", "description": "Academic fine tune potential multilingual and domain improvements." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", "description": "Llama distilled from R1 improved reasoning enterprise friendly." },
      { "id": "CohereLabs/c4ai-command-r7b-12-2024", "description": "Small Command variant research or regional adaptation focus." },
      { "id": "Sao10K/L3-70B-Euryale-v2.1", "description": "Creative community instruct model with distinctive persona." },
      { "id": "CohereLabs/aya-vision-32b", "description": "Larger Aya Vision advanced vision language with detailed reasoning." },
      { "id": "meta-llama/Llama-3.1-405B-Instruct", "description": "Massive instruction model very long context excels at complex tasks." },
      { "id": "CohereLabs/c4ai-command-r7b-arabic-02-2025", "description": "Command tuned for Arabic fluent and culturally appropriate outputs." },
      { "id": "Sao10K/L3-8B-Lunaris-v1", "description": "Community Llama creative role play oriented themed persona." },
      { "id": "Qwen/Qwen2.5-Coder-7B", "description": "Small Qwen coder basic programming assistance for low resource environments." },
      { "id": "Qwen/QwQ-32B-Preview", "description": "Preview Qwen experimental features and architecture refinements." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", "description": "Distilled Qwen mid size strong reasoning and clear steps." },
      { "id": "meta-llama/Llama-3.1-70B-Instruct", "description": "Instruction tuned Llama improved reasoning and factual reliability." },
      { "id": "Qwen/Qwen3-235B-A22B-FP8", "description": "FP8 quantized Qwen flagship efficient access to ultra large capabilities." },
      { "id": "zai-org/GLM-4-32B-0414", "description": "Open licensed GLM matches larger proprietary models on benchmarks." },
      { "id": "SentientAGI/Dobby-Unhinged-Llama-3.3-70B", "description": "Unfiltered candid creative outputs intentionally less restricted behavior." },
      { "id": "marin-community/marin-8b-instruct", "description": "Community tuned assistant helpful conversational everyday tasks." },
      { "id": "deepseek-ai/DeepSeek-Prover-V2-671B", "description": "Specialist for mathematical proofs and formal reasoning workflows." },
      { "id": "NousResearch/Hermes-3-Llama-3.1-70B", "description": "Highly aligned assistant strong complex instruction following." },
      { "id": "Qwen/Qwen2.5-Coder-3B-Instruct", "description": "Tiny coding assistant basic code completions and explanations." },
      { "id": "deepcogito/cogito-v2-preview-llama-70B", "description": "Preview fine tune enhanced reasoning and tool use indications." },
      { "id": "deepcogito/cogito-v2-preview-llama-405B", "description": "Preview at frontier scale tests advanced fine tuning methods." },
      { "id": "deepcogito/cogito-v2-preview-deepseek-671B-MoE", "description": "Experimental blend of DeepCogito and DeepSeek approaches for reasoning." }
    ]

infisical:
  enabled: true
  env: "ephemeral-us-east-1"

replicas: 1
autoscaling:
  enabled: false

resources:
  requests:
    cpu: 2
    memory: 4Gi
  limits:
    cpu: 4
    memory: 8Gi


================================================
FILE: chart/env/prod.yaml
================================================
image:
  repository: huggingface
  name: chat-ui

nodeSelector:
  role-huggingchat: "true"

tolerations:
  - key: "huggingface.co/huggingchat"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

serviceAccount:
  enabled: true
  create: true
  name: huggingchat-prod

ingress:
  path: "/chat"
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/chat/healthcheck"
    alb.ingress.kubernetes.io/listen-ports: "[{\"HTTP\": 80}, {\"HTTPS\": 443}]"
    alb.ingress.kubernetes.io/load-balancer-name: "hub-utils-prod-cloudfront"
    alb.ingress.kubernetes.io/group.name: "hub-utils-prod-cloudfront"
    alb.ingress.kubernetes.io/scheme: "internal"
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/tags: "Env=prod,Project=hub,Terraform=true"
    alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30
    alb.ingress.kubernetes.io/target-type: "ip"
    alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:707930574880:certificate/5b25b145-75db-4837-b9f3-7f238ba8a9c7,arn:aws:acm:us-east-1:707930574880:certificate/bfdf509c-f44b-400f-b9e1-6f7a861abe91"
    kubernetes.io/ingress.class: "alb"

ingressInternal:
  enabled: true
  path: "/chat"
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: "/chat/healthcheck"
    alb.ingress.kubernetes.io/listen-ports: "[{\"HTTP\": 80}, {\"HTTPS\": 443}]"
    alb.ingress.kubernetes.io/group.name: "hub-prod-internal-public"
    alb.ingress.kubernetes.io/load-balancer-name: "hub-prod-internal-public"
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/tags: "Env=prod,Project=hub,Terraform=true"
    alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30
    alb.ingress.kubernetes.io/target-type: "ip"
    alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:707930574880:certificate/5b25b145-75db-4837-b9f3-7f238ba8a9c7,arn:aws:acm:us-east-1:707930574880:certificate/bfdf509c-f44b-400f-b9e1-6f7a861abe91"
    kubernetes.io/ingress.class: "alb"

envVars:
  COUPLE_SESSION_WITH_COOKIE_NAME: "token"
  OPENID_SCOPES: "openid profile inference-api read-mcp read-billing"
  USE_USER_TOKEN: "true"
  MCP_FORWARD_HF_USER_TOKEN: "true"
  AUTOMATIC_LOGIN: "false"

  ADDRESS_HEADER: "X-Forwarded-For"
  APP_BASE: "/chat"
  ALLOW_IFRAME: "false"
  COOKIE_SAMESITE: "lax"
  COOKIE_SECURE: "true"
  EXPOSE_API: "true"
  METRICS_ENABLED: "true"
  LOG_LEVEL: "debug"
  NODE_LOG_STRUCTURED_DATA: "true"

  OPENAI_BASE_URL: "https://router.huggingface.co/v1"
  PUBLIC_APP_ASSETS: "huggingchat"
  PUBLIC_APP_NAME: "HuggingChat"
  PUBLIC_APP_DESCRIPTION: "Making the community's best AI chat models available to everyone"
  PUBLIC_ORIGIN: "https://huggingface.co"
  PUBLIC_PLAUSIBLE_SCRIPT_URL: "https://plausible.io/js/pa-Io_oigECawqdlgpf5qvHb.js"

  TASK_MODEL: "Qwen/Qwen3-4B-Instruct-2507"
  LLM_ROUTER_ARCH_BASE_URL: "https://router.huggingface.co/v1"
  LLM_ROUTER_ROUTES_PATH: "build/client/chat/huggingchat/routes.chat.json"
  LLM_ROUTER_ARCH_MODEL: "katanemo/Arch-Router-1.5B"
  LLM_ROUTER_OTHER_ROUTE: "casual_conversation"
  LLM_ROUTER_ARCH_TIMEOUT_MS: "10000"
  LLM_ROUTER_ENABLE_MULTIMODAL: "true"
  LLM_ROUTER_MULTIMODAL_MODEL: "Qwen/Qwen3.5-397B-A17B"
  LLM_ROUTER_ENABLE_TOOLS: "true"
  LLM_ROUTER_TOOLS_MODEL: "moonshotai/Kimi-K2-Instruct-0905"
  TRANSCRIPTION_MODEL: "openai/whisper-large-v3-turbo"
  MCP_SERVERS: >
    [{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp?tools=web_search_exa,get_code_context_exa,crawling_exa"}, {"name": "Hugging Face", "url": "https://hf.co/mcp?login"}]
  MCP_TOOL_TIMEOUT_MS: "120000"
  PUBLIC_LLM_ROUTER_DISPLAY_NAME: "Omni"
  PUBLIC_LLM_ROUTER_LOGO_URL: "https://cdn-uploads.huggingface.co/production/uploads/5f17f0a0925b9863e28ad517/C5V0v1xZXv6M7FXsdJH9b.png"
  PUBLIC_LLM_ROUTER_ALIAS_ID: "omni"
  MODELS: >
    [
      { "id": "Qwen/Qwen3.5-9B", "description": "Dense multimodal hybrid with 262K context excelling at reasoning on-device." },
      { "id": "CohereLabs/tiny-aya-global", "description": "Tiny multilingual assistant covering 70+ languages for on-device deployment." },
      { "id": "CohereLabs/tiny-aya-earth", "description": "Regional Aya for African languages with culturally tuned on-device inference." },
      { "id": "CohereLabs/tiny-aya-fire", "description": "Regional Aya for South Asian languages with culturally tuned on-device inference." },
      { "id": "CohereLabs/tiny-aya-water", "description": "Regional Aya for Asia-Pacific and European multilingual on-device tasks." },
      { "id": "Qwen/Qwen3.5-122B-A10B", "description": "Multimodal MoE excelling at agentic tool use with 1M context and 201 languages." },
      { "id": "Qwen/Qwen3.5-35B-A3B", "description": "Compact multimodal MoE with hybrid DeltaNet, 1M context, and 201 languages." },
      { "id": "Qwen/Qwen3.5-27B", "description": "Dense multimodal hybrid with top-tier reasoning density and 1M context." },
      { "id": "Qwen/Qwen3.5-397B-A17B", "description": "Native multimodal MoE with hybrid attention, 1M context, and 201 languages.", "parameters": { "max_tokens": 32768 } },
      { "id": "allenai/Olmo-3.1-32B-Think", "description": "Updated Olmo Think with extended RL for stronger math, code, and instruction following." },
      { "id": "MiniMaxAI/MiniMax-M2.5", "description": "Frontier 230B MoE agent for top-tier coding, tool calling, and fast inference." },
      { "id": "zai-org/GLM-5", "description": "Flagship 745B MoE for agentic reasoning, coding, and creative writing." },
      { "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", "description": "Flagship Qwen3 vision-language MoE for visual agents, documents, and GUI automation." },
      { "id": "google/gemma-3n-E4B-it", "description": "Mobile-first multimodal Gemma handling text, images, video, and audio on-device." },
      { "id": "nvidia/NVIDIA-Nemotron-Nano-9B-v2", "description": "Hybrid Mamba-Transformer with 128K context and controllable reasoning budget." },
      { "id": "mistralai/Mistral-7B-Instruct-v0.2", "description": "Efficient 7B instruction model with 32K context for dialogue and coding." },
      { "id": "Qwen/Qwen3-Coder-Next-FP8", "description": "FP8 Qwen3-Coder-Next for efficient inference with repository-scale coding agents." },
      { "id": "arcee-ai/Trinity-Mini", "description": "Compact US-built MoE for multi-turn agents, tool use, and structured outputs." },
      { "id": "Qwen/Qwen3-Coder-Next", "description": "Ultra-sparse coding MoE for repository-scale agents with 256K context." },
      { "id": "moonshotai/Kimi-K2.5", "description": "Native multimodal agent with agent swarms for parallel tool orchestration." },
      { "id": "allenai/Molmo2-8B", "description": "Open vision-language model excelling at video understanding, pointing, and object tracking." },
      { "id": "zai-org/GLM-4.7-Flash", "description": "Fast GLM-4.7 variant optimized for lower latency coding and agents." },
      { "id": "zai-org/GLM-4.7", "description": "Flagship GLM MoE for coding, reasoning, and agentic tool use." },
      { "id": "zai-org/GLM-4.7-FP8", "description": "FP8 GLM-4.7 for efficient inference with strong coding." },
      { "id": "MiniMaxAI/MiniMax-M2.1", "description": "MoE agent model with multilingual coding and fast outputs." },
      { "id": "XiaomiMiMo/MiMo-V2-Flash", "description": "Fast MoE reasoning model with speculative decoding for agents." },
      { "id": "Qwen/Qwen3-VL-32B-Instruct", "description": "Vision-language Qwen for documents, GUI agents, and visual reasoning." },
      { "id": "allenai/Olmo-3.1-32B-Instruct", "description": "Fully open chat model strong at tool use and dialogue." },
      { "id": "zai-org/AutoGLM-Phone-9B-Multilingual", "description": "Mobile agent for multilingual Android device automation." },
      { "id": "utter-project/EuroLLM-22B-Instruct-2512", "description": "European multilingual model for all EU languages and translation." },
      { "id": "dicta-il/DictaLM-3.0-24B-Thinking", "description": "Hebrew-English reasoning model with explicit thinking traces for bilingual QA and logic." },
      { "id": "EssentialAI/rnj-1-instruct", "description": "8B code and STEM model rivaling larger models on agentic coding, math, and tool use." },
      { "id": "MiniMaxAI/MiniMax-M2", "description": "Compact MoE model tuned for fast coding, agentic workflows, and long-context chat." },
      { "id": "PrimeIntellect/INTELLECT-3-FP8", "description": "FP8 INTELLECT-3 variant for cheaper frontier-level math, code, and general reasoning." },
      { "id": "Qwen/Qwen3-VL-30B-A3B-Instruct", "description": "Flagship Qwen3 vision-language model for high-accuracy image, text, and video reasoning." },
      { "id": "Qwen/Qwen3-VL-30B-A3B-Thinking", "description": "Thinking-mode Qwen3-VL that emits detailed multimodal reasoning traces for difficult problems." },
      { "id": "Qwen/Qwen3-VL-8B-Instruct", "description": "Smaller Qwen3 vision-language assistant for everyday multimodal chat, captioning, and analysis." },
      { "id": "aisingapore/Qwen-SEA-LION-v4-32B-IT", "description": "SEA-LION v4 Qwen optimized for Southeast Asian languages and regional enterprise workloads." },
      { "id": "allenai/Olmo-3-32B-Think", "description": "Fully open 32B thinking model excelling at stepwise math, coding, and research reasoning." },
      { "id": "allenai/Olmo-3-7B-Instruct", "description": "Lightweight Olmo assistant for instruction following, Q&A, and everyday open-source workflows." },
      { "id": "allenai/Olmo-3-7B-Think", "description": "7B Olmo reasoning model delivering transparent multi-step thinking on modest hardware." },
      { "id": "deepcogito/cogito-671b-v2.1", "description": "Frontier-scale 671B MoE focused on deep reasoning, math proofs, and complex coding." },
      { "id": "deepcogito/cogito-671b-v2.1-FP8", "description": "FP8 Cogito v2.1 making 671B-scale reasoning more affordable to serve and experiment with." },
      { "id": "deepseek-ai/DeepSeek-V3.2", "description": "Latest DeepSeek agent model combining strong reasoning, tool-use, and efficient long-context inference." },
      { "id": "moonshotai/Kimi-K2-Thinking", "description": "Reasoning-focused Kimi K2 variant for deep chain-of-thought and large agentic tool flows." },
      { "id": "nvidia/NVIDIA-Nemotron-Nano-12B-v2", "description": "NVIDIA Nano 12B general assistant for coding, chat, and agents with efficient deployment." },
      { "id": "ServiceNow-AI/Apriel-1.6-15b-Thinker", "description": "15B multimodal reasoning model with efficient thinking for enterprise and coding tasks." },
      { "id": "openai/gpt-oss-safeguard-20b", "description": "Safety-focused gpt-oss variant for content classification, policy enforcement, and LLM output filtering." },
      { "id": "zai-org/GLM-4.5", "description": "Flagship GLM agent model unifying advanced reasoning, coding, and tool-using capabilities." },
      { "id": "zai-org/GLM-4.5V-FP8", "description": "FP8 vision-language GLM-4.5V for efficient multilingual visual QA, understanding, and hybrid reasoning." },    
      { "id": "deepseek-ai/DeepSeek-V3.2-Exp", "description": "Experimental V3.2 release focused on faster, lower-cost inference with strong general reasoning and tool use." },
      { "id": "zai-org/GLM-4.6", "description": "Next-gen GLM with very long context and solid multilingual reasoning; good for agents and tools." },
      { "id": "Kwaipilot/KAT-Dev", "description": "Developer-oriented assistant tuned for coding, debugging, and lightweight agent workflows." },
      { "id": "Qwen/Qwen2.5-VL-72B-Instruct", "description": "Flagship multimodal Qwen (text+image) instruction model for high-accuracy visual reasoning and detailed explanations." },
      { "id": "deepseek-ai/DeepSeek-V3.1-Terminus", "description": "Refined V3.1 variant optimized for reliability on long contexts, structured outputs, and tool use." },
      { "id": "Qwen/Qwen3-VL-235B-A22B-Thinking", "description": "Deliberative multimodal Qwen that can produce step-wise visual+text reasoning traces for complex tasks." },
      { "id": "zai-org/GLM-4.6-FP8", "description": "FP8-optimized GLM-4.6 for faster/cheaper deployment with near-parity quality on most tasks." },
      { "id": "zai-org/GLM-4.6V", "description": "106B vision-language model with 128K context and native tool calling for multimodal agents.", "parameters": { "max_tokens": 8192 } },
      { "id": "zai-org/GLM-4.6V-Flash", "description": "9B lightweight vision model for fast local inference with tool calling and UI understanding." },
      { "id": "zai-org/GLM-4.6V-FP8", "description": "FP8-quantized GLM-4.6V for efficient multimodal deployment with native tool use." },
      { "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", "description": "Deliberative text-only 235B Qwen variant for transparent, step-by-step reasoning on hard problems." },
      { "id": "Qwen/Qwen3-Next-80B-A3B-Instruct", "description": "Instruction tuned Qwen for multilingual reasoning, coding, long contexts." },
      { "id": "Qwen/Qwen3-Next-80B-A3B-Thinking", "description": "Thinking mode Qwen that outputs explicit step by step reasoning." },
      { "id": "moonshotai/Kimi-K2-Instruct-0905", "description": "Instruction MoE strong coding and multi step reasoning, long context." },
      { "id": "openai/gpt-oss-20b", "description": "Efficient open model for reasoning and tool use, runs locally." },
      { "id": "swiss-ai/Apertus-8B-Instruct-2509", "description": "Open, multilingual, trained on compliant data transparent global assistant." },
      { "id": "openai/gpt-oss-120b", "description": "High performing open model suitable for large scale applications." },
      { "id": "Qwen/Qwen3-Coder-30B-A3B-Instruct", "description": "Code specialized Qwen long context strong generation and function calling." },
      { "id": "meta-llama/Llama-3.1-8B-Instruct", "description": "Instruction tuned Llama efficient conversational assistant with improved alignment." },
      { "id": "Qwen/Qwen2.5-VL-7B-Instruct", "description": "Vision language Qwen handles images and text for basic multimodal tasks." },
      { "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", "description": "Instruction tuned Qwen reliable general tasks with long context support." },
      { "id": "baidu/ERNIE-4.5-VL-28B-A3B-PT", "description": "Baidu multimodal MoE strong at complex vision language reasoning." },
      { "id": "baidu/ERNIE-4.5-0.3B-PT", "description": "Tiny efficient Baidu model surprisingly long context for lightweight chat." },
      { "id": "deepseek-ai/DeepSeek-R1", "description": "MoE reasoning model excels at math, logic, coding with steps." },
      { "id": "baidu/ERNIE-4.5-21B-A3B-PT", "description": "Efficient Baidu MoE competitive generation with fewer active parameters." },
      { "id": "swiss-ai/Apertus-70B-Instruct-2509", "description": "Open multilingual model trained on open data transparent and capable." },
      { "id": "Qwen/Qwen3-4B-Instruct-2507", "description": "Compact instruction Qwen great for lightweight assistants and apps." },
      { "id": "meta-llama/Llama-3.2-3B-Instruct", "description": "Small efficient Llama for basic conversations and instructions." },
      { "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", "description": "Huge Qwen coder repository scale understanding and advanced generation." },
      { "id": "meta-llama/Meta-Llama-3-8B-Instruct", "description": "Aligned, efficient Llama dependable open source assistant tasks." },
      { "id": "Qwen/Qwen3-4B-Thinking-2507", "description": "Small Qwen that emits transparent step by step reasoning." },
      { "id": "moonshotai/Kimi-K2-Instruct", "description": "MoE assistant strong coding, reasoning, agentic tasks, long context." },
      { "id": "zai-org/GLM-4.5V", "description": "Vision language MoE state of the art multimodal reasoning." },
      { "id": "zai-org/GLM-4.6", "description": "Hybrid reasoning model top choice for intelligent agent applications." },
      { "id": "deepseek-ai/DeepSeek-V3.1", "description": "Supports direct and thinking style reasoning within one model." },
      { "id": "Qwen/Qwen3-8B", "description": "Efficient Qwen assistant strong multilingual skills and formatting." },
      { "id": "Qwen/Qwen3-30B-A3B-Thinking-2507", "description": "Thinking mode Qwen explicit reasoning for complex interpretable tasks." },
      { "id": "google/gemma-3-27b-it", "description": "Multimodal Gemma long context strong text and image understanding." },
      { "id": "zai-org/GLM-4.5-Air", "description": "Efficient GLM strong reasoning and tool use at lower cost." },
      { "id": "HuggingFaceTB/SmolLM3-3B", "description": "Small multilingual long context model surprisingly strong reasoning." },
      { "id": "Qwen/Qwen3-30B-A3B", "description": "Qwen base model for general use or further fine tuning." },
      { "id": "Qwen/Qwen2.5-7B-Instruct", "description": "Compact instruction model solid for basic conversation and tasks." },
      { "id": "Qwen/Qwen3-32B", "description": "General purpose Qwen strong for complex queries and dialogues." },
      { "id": "Qwen/QwQ-32B", "description": "Preview Qwen showcasing next generation features and alignment." },
      { "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", "description": "Flagship instruction Qwen near state of the art across domains." },
      { "id": "meta-llama/Llama-3.3-70B-Instruct", "description": "Improved Llama alignment and structure powerful complex conversations." },
      { "id": "Qwen/Qwen2.5-VL-32B-Instruct", "description": "Multimodal Qwen advanced visual reasoning for complex image plus text." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B", "description": "Tiny distilled Qwen stepwise math and logic reasoning." },
      { "id": "Qwen/Qwen3-235B-A22B", "description": "Qwen base at flagship scale ideal for custom fine tuning." },
      { "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct", "description": "Processes text and images excels at summarization and cross modal reasoning." },
      { "id": "NousResearch/Hermes-4-70B", "description": "Steerable assistant strong reasoning and creativity highly helpful." },
      { "id": "Qwen/Qwen2.5-Coder-32B-Instruct", "description": "Code model strong generation and tool use bridges sizes." },
      { "id": "katanemo/Arch-Router-1.5B", "description": "Lightweight router model directs queries to specialized backends." },
      { "id": "meta-llama/Llama-3.2-1B-Instruct", "description": "Ultra small Llama handles basic Q and A and instructions." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", "description": "Distilled Qwen excels at stepwise logic in compact footprint." },
      { "id": "deepseek-ai/DeepSeek-V3", "description": "General language model direct answers strong creative and knowledge tasks." },
      { "id": "deepseek-ai/DeepSeek-V3-0324", "description": "Updated V3 better reasoning and coding strong tool use." },
      { "id": "CohereLabs/command-a-translate-08-2025", "description": "Translation focused Command model high quality multilingual translation." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", "description": "Distilled from R1 strong reasoning standout dense model." },
      { "id": "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT", "description": "Multimodal base text image pretraining for cross modal understanding." },
      { "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct", "description": "MoE multimodal Llama rivals top vision language models." },
      { "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", "description": "Quantized giant coder faster lighter retains advanced code generation." },
      { "id": "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B", "description": "Qwen3 variant with R1 reasoning improvements compact and capable." },
      { "id": "deepseek-ai/DeepSeek-R1-0528", "description": "R1 update improved reasoning, fewer hallucinations, adds function calling.", "parameters": { "max_tokens": 32000 } },
      { "id": "Qwen/Qwen3-14B", "description": "Balanced Qwen good performance and efficiency for assistants." },
      { "id": "MiniMaxAI/MiniMax-M1-80k", "description": "Long context MoE very fast excels at long range reasoning and code." },
      { "id": "Qwen/Qwen2.5-Coder-7B-Instruct", "description": "Efficient coding assistant for lightweight programming tasks." },
      { "id": "aisingapore/Gemma-SEA-LION-v4-27B-IT", "description": "Gemma SEA LION optimized for Southeast Asian languages or enterprise." },
      { "id": "CohereLabs/aya-expanse-8b", "description": "Small Aya Expanse broad knowledge and efficient general reasoning." },
      { "id": "baichuan-inc/Baichuan-M2-32B", "description": "Medical reasoning specialist fine tuned for clinical QA bilingual." },
      { "id": "Qwen/Qwen2.5-VL-72B-Instruct", "description": "Vision language Qwen detailed image interpretation and instructions." },
      { "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", "description": "FP8 Maverick efficient deployment retains top multimodal capability." },
      { "id": "zai-org/GLM-4.1V-9B-Thinking", "description": "Vision language with explicit reasoning strong for its size." },
      { "id": "zai-org/GLM-4.5-Air-FP8", "description": "FP8 efficient GLM Air hybrid reasoning with minimal compute." },
      { "id": "google/gemma-2-2b-it", "description": "Small Gemma instruction tuned safe responsible outputs easy deployment." },
      { "id": "arcee-ai/AFM-4.5B", "description": "Enterprise focused model strong CPU performance compliant and practical." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "description": "Llama distilled from R1 strong reasoning and structured outputs." },
      { "id": "CohereLabs/aya-vision-8b", "description": "Vision capable Aya handles images and text for basic multimodal." },
      { "id": "NousResearch/Hermes-3-Llama-3.1-405B", "description": "Highly aligned assistant excels at math, code, QA." },
      { "id": "Qwen/Qwen2.5-72B-Instruct", "description": "Accurate detailed instruction model supports tools and long contexts." },
      { "id": "meta-llama/Llama-Guard-4-12B", "description": "Safety guardrail model filters and enforces content policies." },
      { "id": "CohereLabs/command-a-vision-07-2025", "description": "Command model with image input captioning and visual QA." },
      { "id": "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", "description": "NVIDIA tuned Llama optimized throughput for research and production." },
      { "id": "meta-llama/Meta-Llama-3-70B-Instruct", "description": "Instruction tuned Llama improved reasoning and reliability over predecessors." },
      { "id": "NousResearch/Hermes-4-405B", "description": "Frontier Hermes hybrid reasoning excels at math, code, creativity." },
      { "id": "NousResearch/Hermes-2-Pro-Llama-3-8B", "description": "Small Hermes highly steerable maximized helpfulness for basics." },
      { "id": "google/gemma-2-9b-it", "description": "Gemma with improved accuracy and context safe, easy to deploy." },
      { "id": "Sao10K/L3-8B-Stheno-v3.2", "description": "Community Llama variant themed tuning and unique conversational style." },
      { "id": "deepcogito/cogito-v2-preview-llama-109B-MoE", "description": "MoE preview advanced reasoning tests DeepCogito v2 fine tuning." },
      { "id": "CohereLabs/c4ai-command-r-08-2024", "description": "Cohere Command variant instruction following with specialized tuning." },
      { "id": "baidu/ERNIE-4.5-300B-A47B-Base-PT", "description": "Large base model foundation for specialized language systems." },
      { "id": "CohereLabs/aya-expanse-32b", "description": "Aya Expanse large comprehensive knowledge and reasoning capabilities." },
      { "id": "CohereLabs/c4ai-command-a-03-2025", "description": "Updated Command assistant improved accuracy and general usefulness." },
      { "id": "CohereLabs/command-a-reasoning-08-2025", "description": "Command variant optimized for complex multi step logical reasoning." },
      { "id": "alpindale/WizardLM-2-8x22B", "description": "Multi expert WizardLM MoE approach for efficient high quality generation." },
      { "id": "tokyotech-llm/Llama-3.3-Swallow-70B-Instruct-v0.4", "description": "Academic fine tune potential multilingual and domain improvements." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", "description": "Llama distilled from R1 improved reasoning enterprise friendly." },
      { "id": "CohereLabs/c4ai-command-r7b-12-2024", "description": "Small Command variant research or regional adaptation focus." },
      { "id": "Sao10K/L3-70B-Euryale-v2.1", "description": "Creative community instruct model with distinctive persona." },
      { "id": "CohereLabs/aya-vision-32b", "description": "Larger Aya Vision advanced vision language with detailed reasoning." },
      { "id": "meta-llama/Llama-3.1-405B-Instruct", "description": "Massive instruction model very long context excels at complex tasks." },
      { "id": "CohereLabs/c4ai-command-r7b-arabic-02-2025", "description": "Command tuned for Arabic fluent and culturally appropriate outputs." },
      { "id": "Sao10K/L3-8B-Lunaris-v1", "description": "Community Llama creative role play oriented themed persona." },
      { "id": "Qwen/Qwen2.5-Coder-7B", "description": "Small Qwen coder basic programming assistance for low resource environments." },
      { "id": "Qwen/QwQ-32B-Preview", "description": "Preview Qwen experimental features and architecture refinements." },
      { "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", "description": "Distilled Qwen mid size strong reasoning and clear steps." },
      { "id": "meta-llama/Llama-3.1-70B-Instruct", "description": "Instruction tuned Llama improved reasoning and factual reliability." },
      { "id": "Qwen/Qwen3-235B-A22B-FP8", "description": "FP8 quantized Qwen flagship efficient access to ultra large capabilities." },
      { "id": "zai-org/GLM-4-32B-0414", "description": "Open licensed GLM matches larger proprietary models on benchmarks." },
      { "id": "SentientAGI/Dobby-Unhinged-Llama-3.3-70B", "description": "Unfiltered candid creative outputs intentionally less restricted behavior." },
      { "id": "marin-community/marin-8b-instruct", "description": "Community tuned assistant helpful conversational everyday tasks." },
      { "id": "deepseek-ai/DeepSeek-Prover-V2-671B", "description": "Specialist for mathematical proofs and formal reasoning workflows." },
      { "id": "NousResearch/Hermes-3-Llama-3.1-70B", "description": "Highly aligned assistant strong complex instruction following." },
      { "id": "Qwen/Qwen2.5-Coder-3B-Instruct", "description": "Tiny coding assistant basic code completions and explanations." },
      { "id": "deepcogito/cogito-v2-preview-llama-70B", "description": "Preview fine tune enhanced reasoning and tool use indications." },
      { "id": "deepcogito/cogito-v2-preview-llama-405B", "description": "Preview at frontier scale tests advanced fine tuning methods." },
      { "id": "deepcogito/cogito-v2-preview-deepseek-671B-MoE", "description": "Experimental blend of DeepCogito and DeepSeek approaches for reasoning." }
    ]

infisical:
  enabled: true
  env: "prod-us-east-1"

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 30
  targetMemoryUtilizationPercentage: "50"
  targetCPUUtilizationPercentage: "50"

resources:
  requests:
    cpu: 2
    memory: 4Gi
  limits:
    cpu: 4
    memory: 8Gi


================================================
FILE: chart/templates/_helpers.tpl
================================================
{{- define "name" -}}
{{- default $.Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{- define "app.name" -}}
chat-ui
{{- end -}}

{{- define "labels.standard" -}}
release: {{ $.Release.Name | quote }}
heritage: {{ $.Release.Service | quote }}
chart: "{{ include "name" . }}"
app: "{{ include "app.name" . }}"
{{- end -}}

{{- define "labels.resolver" -}}
release: {{ $.Release.Name | quote }}
heritage: {{ $.Release.Service | quote }}
chart: "{{ include "name" . }}"
app: "{{ include "app.name" . }}-resolver"
{{- end -}}



================================================
FILE: chart/templates/config.yaml
================================================
apiVersion: v1
kind: ConfigMap
metadata:
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
data:
  {{- range $key, $value := $.Values.envVars }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}


================================================
FILE: chart/templates/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
  {{- if .Values.infisical.enabled }}
  annotations:
    secrets.infisical.com/auto-reload: "true"
  {{- end }}
spec:
  progressDeadlineSeconds: 600
  {{- if not $.Values.autoscaling.enabled }}
  replicas: {{ .Values.replicas }}
  {{- end }}
  revisionHistoryLimit: 10
  selector:
    matchLabels: {{ include "labels.standard" . | nindent 6 }}
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels: {{ include "labels.standard" . | nindent 8 }}
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }}
        {{- if $.Values.envVars.NODE_LOG_STRUCTURED_DATA }}
        co.elastic.logs/json.expand_keys: "true"
        {{- end }}
    spec:
      {{- if .Values.serviceAccount.enabled }}
      serviceAccountName: "{{ .Values.serviceAccount.name | default (include "name" .) }}"
      {{- end }}
      containers:
        - name: chat-ui
          image: "{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          readinessProbe:
            failureThreshold: 30
            periodSeconds: 10
            httpGet:
              path: {{ $.Values.envVars.APP_BASE | default "" }}/healthcheck
              port: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
          livenessProbe:
            failureThreshold: 30
            periodSeconds: 10
            httpGet:
              path: {{ $.Values.envVars.APP_BASE | default "" }}/healthcheck
              port: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
          ports:
            - containerPort: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
              name: http
              protocol: TCP
            {{- if eq "true" $.Values.envVars.METRICS_ENABLED }}
            - containerPort: {{ $.Values.envVars.METRICS_PORT | default 5565 | int }}
              name: metrics
              protocol: TCP
            {{- end }}
          resources: {{ toYaml .Values.resources | nindent 12 }}
          {{- with $.Values.extraEnv }}
          env:
            {{- toYaml . | nindent 14 }}
          {{- end }}
          envFrom:
            - configMapRef:
                name: {{ include "name" . }}
          {{- if $.Values.infisical.enabled }}
            - secretRef:
                name: {{ include "name" $ }}-secs
          {{- end }}
          {{- with $.Values.extraEnvFrom }}
            {{- toYaml . | nindent 14 }}
          {{- end }}
      nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }}
      tolerations: {{ toYaml .Values.tolerations | nindent 8 }}
      volumes:
        - name: config
          configMap:
            name: {{ include "name" . }}


================================================
FILE: chart/templates/hpa.yaml
================================================
{{- if $.Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ include "name" . }}
  minReplicas: {{ $.Values.autoscaling.minReplicas }}
  maxReplicas: {{ $.Values.autoscaling.maxReplicas }}
  metrics:
    {{- if ne "" $.Values.autoscaling.targetMemoryUtilizationPercentage }}
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: {{ $.Values.autoscaling.targetMemoryUtilizationPercentage | int }}
    {{- end }}
    {{- if ne "" $.Values.autoscaling.targetCPUUtilizationPercentage }}
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: {{ $.Values.autoscaling.targetCPUUtilizationPercentage | int }}
    {{- end }}
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 600
      policies:
        - type: Percent
          value: 10
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Pods
          value: 1
          periodSeconds: 30
{{- end }}


================================================
FILE: chart/templates/infisical.yaml
================================================
{{- if .Values.infisical.enabled }}
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: {{ include "name" $ }}-infisical-secret
  namespace: {{ $.Release.Namespace }}
spec:
  authentication:
    universalAuth:
      credentialsRef:
        secretName: {{ .Values.infisical.operatorSecretName | quote }}
        secretNamespace: {{ .Values.infisical.operatorSecretNamespace | quote }}
      secretsScope:
        envSlug: {{ .Values.infisical.env | quote }}
        projectSlug: {{ .Values.infisical.project | quote }}
        secretsPath: /
  hostAPI: {{ .Values.infisical.url | quote }}
  managedSecretReference:
    creationPolicy: Owner
    secretName: {{ include "name" $ }}-secs
    secretNamespace: {{ .Release.Namespace | quote }}
    secretType: Opaque
  resyncInterval: {{ .Values.infisical.resyncInterval }}
{{- end }}


================================================
FILE: chart/templates/ingress-internal.yaml
================================================
{{- if $.Values.ingressInternal.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations: {{ toYaml .Values.ingressInternal.annotations | nindent 4 }}
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}-internal
  namespace: {{ .Release.Namespace }}
spec:
  {{ if $.Values.ingressInternal.className }}
  ingressClassName: {{ .Values.ingressInternal.className }}
  {{ end }}
  {{- with .Values.ingressInternal.tls }}
  tls:
    - hosts:
        - {{ $.Values.domain | quote }}
      {{- with .secretName }}
      secretName: {{ . }}
      {{- end }}
  {{- end }}
  rules:
    - host: {{ .Values.domain }}
      http:
        paths:
          - backend:
              service:
                name: {{ include "name" . }}
                port:
                  name: http
            path: {{ $.Values.ingressInternal.path | default "/" }}
            pathType: Prefix
{{- end }}


================================================
FILE: chart/templates/ingress.yaml
================================================
{{- if $.Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations: {{ toYaml .Values.ingress.annotations | nindent 4 }}
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
spec:
  {{ if $.Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{ end }}
  {{- with .Values.ingress.tls }}
  tls:
    - hosts:
        - {{ $.Values.domain | quote }}
      {{- with .secretName }}
      secretName: {{ . }}
      {{- end }}
  {{- end }}
  rules:
    - host: {{ .Values.domain }}
      http:
        paths:
          - backend:
              service:
                name: {{ include "name" . }}
                port:
                  name: http
            path: {{ $.Values.ingress.path | default "/" }}
            pathType: Prefix
{{- end }}


================================================
FILE: chart/templates/network-policy.yaml
================================================
{{- if $.Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
spec:
  egress:
    - ports:
        - port: 53
          protocol: UDP
      to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
    - to:
        {{- range $ip := .Values.networkPolicy.allowedBlocks }}
        - ipBlock:
            cidr: {{ $ip | quote }}
        {{- end }}
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
              - 169.254.169.254/32
  podSelector:
    matchLabels: {{ include "labels.standard" . | nindent 6 }}
  policyTypes:
    - Egress
{{- end }}


================================================
FILE: chart/templates/service-account.yaml
================================================
{{- if and .Values.serviceAccount.enabled .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
metadata:
  name: "{{ .Values.serviceAccount.name | default (include "name" .) }}"
  namespace: {{ .Release.Namespace }}
  labels: {{ include "labels.standard" . | nindent 4 }}
  {{- with .Values.serviceAccount.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
{{- end }}


================================================
FILE: chart/templates/service-monitor.yaml
================================================
{{- if eq "true" $.Values.envVars.METRICS_ENABLED }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels: {{ include "labels.standard" . | nindent 4 }}
  name: {{ include "name" . }}
  namespace: {{ .Release.Namespace }}
spec:
  selector:
    matchLabels: {{ include "labels.standard" . | nindent 6 }}
  endpoints:
    - port: metrics
      path: /metrics
      interval: 10s
      scheme: http	
      scrapeTimeout: 10s
{{- end }}


================================================
FILE: chart/templates/service.yaml
================================================
apiVersion: v1
kind: Service
metadata:
  name: "{{ include "name" . }}"
  annotations: {{ toYaml .Values.service.annotations | nindent 4 }}
  namespace: {{ .Release.Namespace }}
  labels: {{ include "labels.standard" . | nindent 4 }}
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: http
  {{- if eq "true" $.Values.envVars.METRICS_ENABLED }}
  - name: metrics
    port: {{ $.Values.envVars.METRICS_PORT | default 5565 | int }}
    protocol: TCP
    targetPort: metrics
  {{- end }}
  selector: {{ include "labels.standard" . | nindent 4 }}
  type: {{.Values.service.type}}


================================================
FILE: chart/values.yaml
================================================
image:
  repository: ghcr.io/huggingface
  name: chat-ui
  tag: 0.0.0-latest
  pullPolicy: IfNotPresent

replicas: 3

domain: huggingface.co

networkPolicy:
  enabled: false
  allowedBlocks: []

service:
  type: NodePort
  annotations: { }

serviceAccount:
  enabled: false
  create: false
  name: ""
  automountServiceAccountToken: true
  annotations: { }

ingress:
  enabled: true
  path: "/"
  annotations: { }
  # className: "nginx"
  tls: { }
    # secretName: XXX

ingressInternal:
  enabled: false
  path: "/"
  annotations: { }
  # className: "nginx"
  tls: { }

resources:
  requests:
    cpu: 2
    memory: 4Gi
  limits:
    cpu: 2
    memory: 4Gi
nodeSelector: {}
tolerations: []

envVars: { }

infisical:
  enabled: false
  env: ""
  project: "huggingchat-v2-a1"
  url: ""
  resyncInterval: 60
  operatorSecretName: "huggingchat-operator-secrets"
  operatorSecretNamespace: "hub-utils"

# Allow to environment injections on top or instead of infisical
extraEnvFrom: []
extraEnv: []

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 2
  targetMemoryUtilizationPercentage: ""
  targetCPUUtilizationPercentage: ""

## Metrics removed; monitoring configuration no longer used


================================================
FILE: docker-compose.yml
================================================
# For development only
# Set MONGODB_URL=mongodb://localhost:27017 in .env.local to use this container
services:
  mongo:
    image: mongo:8
    hostname: mongodb
    ports:
      - ${LOCAL_MONGO_PORT:-27017}:27017
    command: --replSet rs0 --bind_ip_all #--setParameter notablescan=1
    mem_limit: "5g"
    mem_reservation: "3g"
    healthcheck:
      # need to specify the hostname here because the default is the container name, and we run the app outside of docker
      test: test $$(mongosh --quiet --eval 'try {rs.status().ok} catch(e) {rs.initiate({_id:"rs0",members:[{_id:0,host:"127.0.0.1:${LOCAL_MONGO_PORT:-27017}"}]}).ok}') -eq 1
      interval: 5s
    volumes:
      - mongodb-data:/data/db
    restart: always

volumes:
  mongodb-data:


================================================
FILE: docs/source/_toctree.yml
================================================
- local: index
  title: Chat UI
- title: Installation
  sections:
    - local: installation/local
      title: Local
    - local: installation/docker
      title: Docker
    - local: installation/helm
      title: Helm
- title: Configuration
  sections:
    - local: configuration/overview
      title: Overview
    - local: configuration/theming
      title: Theming
    - local: configuration/open-id
      title: OpenID
    - local: configuration/mcp-tools
      title: MCP Tools
    - local: configuration/llm-router
      title: LLM Router
    - local: configuration/metrics
      title: Metrics
    - local: configuration/common-issues
      title: Common Issues
- title: Developing
  sections:
    - local: developing/architecture
      title: Architecture


================================================
FILE: docs/source/configuration/common-issues.md
================================================
# Common Issues

## 403: You don't have access to this conversation

This usually happens when running Chat UI over HTTP without proper cookie configuration.

**Recommended:** Set up a reverse proxy (NGINX, Caddy) to handle HTTPS.

**Alternative:** If you must run over HTTP, configure cookies:

```ini
COOKIE_SECURE=false
COOKIE_SAMESITE=lax
```

Also ensure `PUBLIC_ORIGIN` matches your actual URL:

```ini
PUBLIC_ORIGIN=http://localhost:5173
```

## Models not loading

If models aren't appearing in the UI:

1. Verify `OPENAI_BASE_URL` is correct and accessible
2. Check that `OPENAI_API_KEY` is valid
3. Ensure the endpoint returns models at `${OPENAI_BASE_URL}/models`

## Database connection errors

For development, you can skip MongoDB entirely - Chat UI will use an embedded database.

For production, verify:

- `MONGODB_URL` is a valid connection string
- Your IP is whitelisted (for MongoDB Atlas)
- The database user has read/write permissions


================================================
FILE: docs/source/configuration/llm-router.md
================================================
# LLM Router

Chat UI includes an intelligent routing system that automatically selects the best model for each request. When enabled, users see a virtual "Omni" model that routes to specialized models based on the conversation context.

The router uses [katanemo/Arch-Router-1.5B](https://huggingface.co/katanemo/Arch-Router-1.5B) for route selection.

## Configuration

### Basic Setup

```ini
# Arch router endpoint (OpenAI-compatible)
LLM_ROUTER_ARCH_BASE_URL=https://router.huggingface.co/v1
LLM_ROUTER_ARCH_MODEL=katanemo/Arch-Router-1.5B

# Path to your routes policy JSON
LLM_ROUTER_ROUTES_PATH=./config/routes.json
```

### Routes Policy

Create a JSON file defining your routes. Each route specifies:

```json
[
	{
		"name": "coding",
		"description": "Programming, debugging, code review",
		"primary_model": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
		"fallback_models": ["meta-llama/Llama-3.3-70B-Instruct"]
	},
	{
		"name": "casual_conversation",
		"description": "General chat, questions, explanations",
		"primary_model": "meta-llama/Llama-3.3-70B-Instruct"
	}
]
```

### Fallback Behavior

```ini
# Route to use when Arch returns "other"
LLM_ROUTER_OTHER_ROUTE=casual_conversation

# Model to use if Arch selection fails entirely
LLM_ROUTER_FALLBACK_MODEL=meta-llama/Llama-3.3-70B-Instruct

# Selection timeout (milliseconds)
LLM_ROUTER_ARCH_TIMEOUT_MS=10000
```

## Multimodal Routing

When a user sends an image, the router can bypass Arch and route directly to a vision model:

```ini
LLM_ROUTER_ENABLE_MULTIMODAL=true
LLM_ROUTER_MULTIMODAL_MODEL=meta-llama/Llama-3.2-90B-Vision-Instruct
```

## Tools Routing

When a user has MCP servers enabled, the router can automatically select a tools-capable model:

```ini
LLM_ROUTER_ENABLE_TOOLS=true
LLM_ROUTER_TOOLS_MODEL=meta-llama/Llama-3.3-70B-Instruct
```

## UI Customization

Customize how the router appears in the model selector:

```ini
PUBLIC_LLM_ROUTER_ALIAS_ID=omni
PUBLIC_LLM_ROUTER_DISPLAY_NAME=Omni
PUBLIC_LLM_ROUTER_LOGO_URL=https://example.com/logo.png
```

## How It Works

When a user selects Omni:

1. Chat UI sends the conversation context to the Arch router
2. Arch analyzes the content and returns a route name
3. Chat UI maps the route to the corresponding model
4. The request streams from the selected model
5. On errors, fallback models are tried in order

The route selection is displayed in the UI so users can see which model was chosen.

## Message Length Limits

To optimize router performance, message content is trimmed before sending to Arch:

```ini
# Max characters for assistant messages (default: 500)
LLM_ROUTER_MAX_ASSISTANT_LENGTH=500

# Max characters for previous user messages (default: 400)
LLM_ROUTER_MAX_PREV_USER_LENGTH=400
```

The latest user message is never trimmed.


================================================
FILE: docs/source/configuration/mcp-tools.md
================================================
# MCP Tools

Chat UI supports tool calling via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). MCP servers expose tools that models can invoke during conversations.

## Server Types

Chat UI supports two types of MCP servers:

### Base Servers (Admin-configured)

Base servers are configured by the administrator via environment variables. They appear for all users and can be enabled/disabled per-user but not removed.

```ini
MCP_SERVERS=[
  {"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"},
  {"name": "Hugging Face", "url": "https://hf.co/mcp"}
]
```

Each server entry requires:

- `name` - Display name shown in the UI
- `url` - MCP server endpoint URL
- `headers` (optional) - Custom headers for authentication

### User Servers (Added from UI)

Users can add their own MCP servers directly from the UI:

1. Open the chat input and click the **+** button (or go to Settings)
2. Select **MCP Servers**
3. Click **Add Server**
4. Enter the server name and URL
5. Run **Health Check** to verify connectivity

User-added servers are stored in the browser and can be removed at any time. They work alongside base servers.

## User Token Forwarding

When users are logged in via Hugging Face, you can forward their access token to MCP servers:

```ini
MCP_FORWARD_HF_USER_TOKEN=true
```

This allows MCP servers to access user-specific resources on their behalf.

## Using Tools

1. Enable the servers you want to use from the MCP Servers panel
2. Start chatting - models will automatically use tools when appropriate

### Model Requirements

Not all models support tool calling. To enable tools for a specific model, add it to your `MODELS` override:

```ini
MODELS=`[
  {
    "id": "meta-llama/Llama-3.3-70B-Instruct",
    "supportsTools": true
  }
]`
```

## Tool Execution Flow

When a model decides to use a tool:

1. The model generates a tool call with parameters
2. Chat UI executes the call against the MCP server
3. Results are displayed in the chat as a collapsible "tool" block
4. Results are fed back to the model for follow-up responses

## Integration with LLM Router

When using the [LLM Router](./llm-router), you can configure automatic routing to a tools-capable model:

```ini
LLM_ROUTER_ENABLE_TOOLS=true
LLM_ROUTER_TOOLS_MODEL=meta-llama/Llama-3.3-70B-Instruct
```

When a user has MCP servers enabled and selects the Omni model, the router will automatically use the specified tools model.


================================================
FILE: docs/source/configuration/metrics.md
================================================
# Metrics

The server can expose prometheus metrics on port `5565` but is off by default. You may enable the metrics server with `METRICS_ENABLED=true` and change the port with `METRICS_PORT=1234`.

<Tip>

In development with `npm run dev`, the metrics server does not shutdown gracefully due to Sveltekit not providing hooks for restart. It's recommended to disable the metrics server in this case.

</Tip>


================================================
FILE: docs/source/configuration/open-id.md
================================================
# OpenID

By default, users are attributed a unique ID based on their browser session. To authenticate users with OpenID Connect, configure the following:

```ini
OPENID_CLIENT_ID=your_client_id
OPENID_CLIENT_SECRET=your_client_secret
OPENID_SCOPES="openid profile"
```

Use the provider URL for standard OpenID Connect discovery:

```ini
OPENID_PROVIDER_URL=https://your-provider.com
```

Advanced: you can also provide a client metadata document via `OPENID_CONFIG`. This value must be a JSON/JSON5 object (for example, a CIMD document) and is parsed server‑side to populate OpenID settings.

**Redirect URI:** `https://your-domain.com/login/callback`

## Access Control

Restrict access to specific users:

```ini
# Allow only specific email addresses
ALLOWED_USER_EMAILS=["user@example.com", "admin@example.com"]

# Allow all users from specific domains
ALLOWED_USER_DOMAINS=["example.com", "company.org"]
```

## Hugging Face Login

For Hugging Face authentication, you can use automatic client registration:

```ini
OPENID_CLIENT_ID=__CIMD__
```

This creates an OAuth app automatically when deployed. See the [CIMD spec](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/) for details.

## User Token Forwarding

When users log in via Hugging Face, you can forward their token for inference:

```ini
USE_USER_TOKEN=true
```

## Auto-Login

Force authentication on all routes:

```ini
AUTOMATIC_LOGIN=true
```


================================================
FILE: docs/source/configuration/overview.md
================================================
# Configuration Overview

Chat UI is configured through environment variables. Default values are in `.env`; override them in `.env.local` or via your environment.

## Required Configuration

Chat UI connects to any OpenAI-compatible API endpoint:

```ini
OPENAI_BASE_URL=https://router.huggingface.co/v1
OPENAI_API_KEY=hf_************************
```

Models are automatically discovered from `${OPENAI_BASE_URL}/models`. No manual model configuration is required.

## Database

```ini
MONGODB_URL=mongodb://localhost:27017
MONGODB_DB_NAME=chat-ui
```

For development, `MONGODB_URL` is optional - Chat UI falls back to an embedded MongoDB that persists to `./db`.

## Model Overrides

To customize model behavior, use the `MODELS` environment variable (JSON5 format):

```ini
MODELS=`[
  {
    "id": "meta-llama/Llama-3.3-70B-Instruct",
    "name": "Llama 3.3 70B",
    "multimodal": false,
    "supportsTools": true
  }
]`
```

Override properties:

- `id` - Model identifier (must match an ID from the `/models` endpoint)
- `name` - Display name in the UI
- `multimodal` - Enable image uploads
- `supportsTools` - Enable MCP tool calling for models that don’t advertise tool support
- `parameters` - Override default parameters (temperature, max_tokens, etc.)

## Task Model

Set a specific model for internal tasks (title generation, etc.):

```ini
TASK_MODEL=meta-llama/Llama-3.1-8B-Instruct
```

If not set, the current conversation model is used.

## Voice Transcription

Enable voice input with Whisper:

```ini
TRANSCRIPTION_MODEL=openai/whisper-large-v3-turbo
TRANSCRIPTION_BASE_URL=https://router.huggingface.co/hf-inference/models
```

## Feature Flags

```ini
LLM_SUMMARIZATION=true          # Enable automatic conversation title generation
ENABLE_DATA_EXPORT=true         # Allow users to export their data
ALLOW_IFRAME=false              # Disallow embedding in iframes (set to true to allow)
```

## User Authentication

Use OpenID Connect for authentication:

```ini
OPENID_CLIENT_ID=your_client_id
OPENID_CLIENT_SECRET=your_client_secret
OPENID_SCOPES="openid profile"
```

See [OpenID configuration](./open-id) for details.

## Environment Variable Reference

See the [`.env` file](https://github.com/huggingface/chat-ui/blob/main/.env) for the complete list of available options.


================================================
FILE: docs/source/configuration/theming.md
================================================
# Theming

Customize the look and feel of Chat UI with these environment variables:

```ini
PUBLIC_APP_NAME=ChatUI
PUBLIC_APP_ASSETS=chatui
PUBLIC_APP_DESCRIPTION="Making the community's best AI chat models available to everyone."
```

- `PUBLIC_APP_NAME` - The name used as a title throughout the app
- `PUBLIC_APP_ASSETS` - Directory for logos & favicons in `static/$PUBLIC_APP_ASSETS`. Options: `chatui`, `huggingchat`
- `PUBLIC_APP_DESCRIPTION` - Description shown in meta tags and about sections

## Additional Options

```ini
PUBLIC_APP_DATA_SHARING=1    # Show data sharing opt-in toggle in settings
PUBLIC_ORIGIN=https://chat.example.com  # Your public URL (required for sharing)
```


================================================
FILE: docs/source/developing/architecture.md
================================================
# Architecture

This document provides a high-level overview of the Chat UI codebase. If you're looking to contribute or understand how the codebase works, this is the place for you!

## Overview

Chat UI provides a simple interface connecting LLMs to external tools via MCP. The project uses [MongoDB](https://www.mongodb.com/) and [SvelteKit](https://kit.svelte.dev/) with [Tailwind](https://tailwindcss.com/).

Key architectural decisions:

- **OpenAI-compatible only**: All model interactions use the OpenAI API format
- **MCP for tools**: Tool calling is handled via Model Context Protocol servers
- **Auto-discovery**: Models are discovered from the `/models` endpoint

## Code Map

### `routes`

All routes rendered with SSR via SvelteKit. The majority of backend and frontend logic lives here, with shared modules in `lib` (client) and `lib/server` (server).

### `textGeneration`

Provides a standard interface for chat features including model output, tool calls, and streaming. Outputs `MessageUpdate`s for fine-grained status updates (new tokens, tool results, etc.).

### `endpoints`

Provides the streaming interface for OpenAI-compatible endpoints. Models are fetched and cached from `${OPENAI_BASE_URL}/models`.

### `mcp`

Implements MCP client functionality for tool discovery and execution. See [MCP Tools](../configuration/mcp-tools) for configuration.

### `llmRouter`

Intelligent routing logic that selects the best model for each request. Uses the Arch router model for classification. See [LLM Router](../configuration/llm-router) for details.

### `migrations`

MongoDB migrations for maintaining backwards compatibility across schema changes. Any schema changes must include a migration.

## Development

```bash
npm install
npm run dev
```

The dev server runs at `http://localhost:5173` with hot reloading.


================================================
FILE: docs/source/index.md
================================================
# Chat UI

Open source chat interface with support for tools, multimodal inputs, and intelligent routing across models. The app uses MongoDB and SvelteKit behind the scenes. Try the live version called [HuggingChat on hf.co/chat](https://huggingface.co/chat) or [setup your own instance](./installation/local).

Chat UI connects to any OpenAI-compatible API endpoint, making it work with:

- [Hugging Face Inference Providers](https://huggingface.co/docs/inference-providers)
- [Ollama](https://ollama.ai)
- [llama.cpp](https://github.com/ggerganov/llama.cpp)
- [OpenRouter](https://openrouter.ai)
- Any other OpenAI-compatible service

**[MCP Tools](./configuration/mcp-tools)**: Function calling via Model Context Protocol (MCP) servers

**[LLM Router](./configuration/llm-router)**: Intelligent routing to select the best model for each request

**[Multimodal](./configuration/overview)**: Image uploads on models that support vision

**[OpenID](./configuration/open-id)**: Optional user authentication via OpenID Connect

## Quickstart

**Step 1 - Create `.env.local`:**

```ini
OPENAI_BASE_URL=https://router.huggingface.co/v1
OPENAI_API_KEY=hf_************************
```

You can use any OpenAI-compatible endpoint:

| Provider     | `OPENAI_BASE_URL`                  | `OPENAI_API_KEY` |
| ------------ | ---------------------------------- | ---------------- |
| Hugging Face | `https://router.huggingface.co/v1` | `hf_xxx`         |
| Ollama       | `http://127.0.0.1:11434/v1`        | `ollama`         |
| llama.cpp    | `http://127.0.0.1:8080/v1`         | `sk-local`       |
| OpenRouter   | `https://openrouter.ai/api/v1`     | `sk-or-v1-xxx`   |

**Step 2 - Install and run:**

```bash
git clone https://github.com/huggingface/chat-ui
cd chat-ui
npm install
npm run dev -- --open
```

That's it! Chat UI will automatically discover available models from your endpoint.

> [!TIP]
> MongoDB is optional for development. When `MONGODB_URL` is not set, Chat UI uses an embedded database that persists to `./db`.

For production deployments, see the [installation guides](./installation/local).


================================================
FILE: docs/source/installation/docker.md
================================================
# Running on Docker

Pre-built Docker images are available:

- **`ghcr.io/huggingface/chat-ui-db`** - Includes MongoDB (recommended for quick setup)
- **`ghcr.io/huggingface/chat-ui`** - Requires external MongoDB

## Quick Start (with bundled MongoDB)

```bash
docker run -p 3000:3000 \
  -e OPENAI_BASE_URL=https://router.huggingface.co/v1 \
  -e OPENAI_API_KEY=hf_*** \
  -v chat-ui-data:/data \
  ghcr.io/huggingface/chat-ui-db
```

## With External MongoDB

If you have an existing MongoDB instance:

```bash
docker run -p 3000:3000 \
  -e OPENAI_BASE_URL=https://router.huggingface.co/v1 \
  -e OPENAI_API_KEY=hf_*** \
  -e MONGODB_URL=mongodb://host.docker.internal:27017 \
  ghcr.io/huggingface/chat-ui
```

Use `host.docker.internal` to reach MongoDB running on your host machine, or provide your MongoDB Atlas connection string.

## Using an Environment File

For more configuration options, use `--env-file` to avoid leaking secrets in shell history:

```bash
docker run -p 3000:3000 \
  --env-file .env.local \
  -v chat-ui-data:/data \
  ghcr.io/huggingface/chat-ui-db
```

See the [configuration overview](../configuration/overview) for all available environment variables.


================================================
FILE: docs/source/installation/helm.md
================================================
# Helm

<Tip warning={true}>

The Helm chart is a work in progress and should be considered unstable. Breaking changes may be pushed without migration guides. Contributions welcome!

</Tip>

For Kubernetes deployment, use the Helm chart in `/chart`. No chart repository is published, so clone the repository and install by path.

## Installation

```bash
git clone https://github.com/huggingface/chat-ui
cd chat-ui
helm install chat-ui ./chart -f values.yaml
```

## Example values.yaml

```yaml
replicas: 1

domain: example.com

service:
  type: ClusterIP

resources:
  requests:
    cpu: 100m
    memory: 2Gi
  limits:
    cpu: "4"
    memory: 6Gi

envVars:
  OPENAI_BASE_URL: https://router.huggingface.co/v1
  OPENAI_API_KEY: hf_***
  MONGODB_URL: mongodb://chat-ui-mongo:27017
```

See the [configuration overview](../configuration/overview) for all available environment variables.


================================================
FILE: docs/source/installation/local.md
================================================
# Running Locally

## Quick Start

1. Create a `.env.local` file with your API credentials:

```ini
OPENAI_BASE_URL=https://router.huggingface.co/v1
OPENAI_API_KEY=hf_************************
```

2. Install and run:

```bash
npm install
npm run dev -- --open
```

That's it! Chat UI will discover available models automatically from your endpoint.

## Configuration

Chat UI connects to any OpenAI-compatible API. Set `OPENAI_BASE_URL` to your provider:

| Provider     | `OPENAI_BASE_URL`                  |
| ------------ | ---------------------------------- |
| Hugging Face | `https://router.huggingface.co/v1` |
| Ollama       | `http://127.0.0.1:11434/v1`        |
| llama.cpp    | `http://127.0.0.1:8080/v1`         |
| OpenRouter   | `https://openrouter.ai/api/v1`     |

See the [configuration overview](../configuration/overview) for all available options.

## Database

For **development**, MongoDB is optional. When `MONGODB_URL` is not set, Chat UI uses an embedded MongoDB server that persists data to the `./db` folder.

For **production**, you should use a dedicated MongoDB instance:

### Option 1: Local MongoDB (Docker)

```bash
docker run -d -p 27017:27017 -v mongo-chat-ui:/data --name mongo-chat-ui mongo:latest
```

Then set `MONGODB_URL=mongodb://localhost:27017` in `.env.local`.

### Option 2: MongoDB Atlas (Managed)

Use [MongoDB Atlas free tier](https://www.mongodb.com/pricing) for a managed database. Copy the connection string to `MONGODB_URL`.

## Running in Production

For production deployments:

```bash
npm install
npm run build
npm run preview
```

The server listens on `http://localhost:4173` by default.


================================================
FILE: entrypoint.sh
================================================
ENV_LOCAL_PATH=/app/.env.local

if test -z "${DOTENV_LOCAL}" ; then
    if ! test -f "${ENV_LOCAL_PATH}" ; then
        echo "DOTENV_LOCAL was not found in the ENV variables and .env.local is not set using a bind volume. Make sure to set environment variables properly. "
    fi;
else
    echo "DOTENV_LOCAL was found in the ENV variables. Creating .env.local file."
    cat <<< "$DOTENV_LOCAL" > ${ENV_LOCAL_PATH}
fi;

if [ "$INCLUDE_DB" = "true" ] ; then
    echo "Starting local MongoDB instance"
    nohup mongod &
fi;

export PUBLIC_VERSION=$(node -p "require('./package.json').version")

dotenv -e /app/.env -c -- node --dns-result-order=ipv4first /app/build/index.js -- --host 0.0.0.0 --port 3000

================================================
FILE: models/add-your-models-here.txt
================================================
You can add .gguf files to this folder, and they will be picked up automatically by chat-ui. 

================================================
FILE: package.json
================================================
{
	"name": "chat-ui",
	"version": "0.20.0",
	"private": true,
	"packageManager": "npm@9.5.0",
	"scripts": {
		"dev": "vite dev",
		"build": "vite build",
		"build:static": "ADAPTER=static vite build",
		"preview": "vite preview",
		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
		"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
		"lint": "prettier --check . && eslint .",
		"format": "prettier --write .",
		"test": "vitest",
		"updateLocalEnv": "vite-node --options.transformMode.ssr='/.*/' scripts/updateLocalEnv.ts",
		"populate": "vite-node --options.transformMode.ssr='/.*/' scripts/populate.ts",
		"config": "vite-node --options.transformMode.ssr='/.*/' scripts/config.ts",
		"prepare": "husky"
	},
	"devDependencies": {
		"@faker-js/faker": "^8.4.1",
		"@iconify-json/carbon": "^1.1.16",
		"@iconify-json/eos-icons": "^1.1.6",
		"@iconify-json/lucide": "^1.2.77",
		"@sveltejs/adapter-node": "^5.2.12",
		"@sveltejs/adapter-static": "^3.0.8",
		"@sveltejs/kit": "^2.52.2",
		"@sveltejs/vite-plugin-svelte": "^5.0.3",
		"@tailwindcss/typography": "^0.5.9",
		"@types/dompurify": "^3.0.5",
		"@types/js-yaml": "^4.0.9",
		"@types/katex": "^0.16.7",
		"@types/mime-types": "^2.1.4",
		"@types/minimist": "^1.2.5",
		"@types/node": "^22.1.0",
		"@types/parquetjs": "^0.10.3",
		"@types/uuid": "^9.0.8",
		"@types/yazl": "^3.3.0",
		"@typescript-eslint/eslint-plugin": "^6.x",
		"@typescript-eslint/parser": "^6.x",
		"bson-objectid": "^2.0.4",
		"dompurify": "^3.2.4",
		"eslint": "^8.28.0",
		"eslint-config-prettier": "^8.5.0",
		"eslint-plugin-svelte": "^2.45.1",
		"husky": "^9.0.11",
		"isomorphic-dompurify": "2.13.0",
		"js-yaml": "^4.1.1",
		"lint-staged": "^15.2.7",
		"minimist": "^1.2.8",
		"mongodb-memory-server": "^10.1.2",
		"playwright": "^1.55.1",
		"prettier": "^3.5.3",
		"prettier-plugin-svelte": "^3.2.6",
		"prettier-plugin-tailwindcss": "^0.6.11",
		"sade": "^1.8.1",
		"superjson": "^2.2.2",
		"svelte": "^5.53.7",
		"svelte-check": "^4.0.0",
		"tslib": "^2.4.1",
		"typescript": "^5.5.0",
		"unplugin-icons": "^0.16.1",
		"vite": "^6.3.5",
		"vite-node": "^3.0.9",
		"vitest": "^3.1.4",
		"vitest-browser-svelte": "^0.1.0",
		"yazl": "^3.3.1"
	},
	"type": "module",
	"dependencies": {
		"@huggingface/hub": "^2.2.0",
		"@huggingface/inference": "^4.11.3",
		"@iconify-json/bi": "^1.1.21",
		"@modelcontextprotocol/sdk": "^1.26.0",
		"@resvg/resvg-js": "^2.6.2",
		"ajv": "^8.18.0",
		"autoprefixer": "^10.4.14",
		"bits-ui": "^2.14.2",
		"date-fns": "^2.29.3",
		"devalue": "^5.6.4",
		"dotenv": "^16.5.0",
		"file-type": "^21.3.1",
		"handlebars": "^4.7.8",
		"highlight.js": "^11.7.0",
		"htmlparser2": "^10.0.0",
		"ip-address": "^9.0.5",
		"jsdom": "^28.1.0",
		"json5": "^2.2.3",
		"katex": "^0.16.21",
		"marked": "^12.0.1",
		"mime-types": "^2.1.35",
		"mongodb": "^5.8.0",
		"nanoid": "^5.0.9",
		"openai": "^4.44.0",
		"openid-client": "^5.4.2",
		"parquetjs": "^0.11.2",
		"pino": "^9.0.0",
		"pino-pretty": "^11.0.0",
		"postcss": "^8.4.31",
		"prom-client": "^15.1.3",
		"qs": "^6.14.2",
		"satori": "^0.10.11",
		"satori-html": "^0.3.2",
		"sharp": "^0.33.4",
		"tailwind-scrollbar": "^3.0.0",
		"tailwindcss": "^3.4.0",
		"undici": "^7.18.2",
		"uuid": "^10.0.0",
		"web-haptics": "^0.0.6",
		"zod": "^3.22.3"
	},
	"overrides": {
		"@reflink/reflink": "file:stub/@reflink/reflink"
	}
}


================================================
FILE: postcss.config.js
================================================
export default {
	plugins: {
		tailwindcss: {},
		autoprefixer: {},
	},
};


================================================
FILE: scripts/config.ts
================================================
import sade from "sade";

// @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
import { config, ready } from "$lib/server/config";

const prog = sade("config");
await ready;
prog
	.command("clear")
	.describe("Clear all config keys")
	.action(async () => {
		console.log("Clearing config...");
		await clear();
	});

prog
	.command("add <key> <value>")
	.describe("Add a new config key")
	.action(async (key: string, value: string) => {
		await add(key, value);
	});

prog
	.command("remove <key>")
	.describe("Remove a config key")
	.action(async (key: string) => {
		console.log(`Removing ${key}`);
		await remove(key);
		process.exit(0);
	});

prog
	.command("help")
	.describe("Show help information")
	.action(() => {
		prog.help();
		process.exit(0);
	});

async function clear() {
	await config.clear();
	process.exit(0);
}

async function add(key: string, value: string) {
	if (!key || !value) {
		console.error("Key and value are required");
		process.exit(1);
	}
	await config.set(key as keyof typeof config.keysFromEnv, value);
	process.exit(0);
}

async function remove(key: string) {
	if (!key) {
		console.error("Key is required");
		process.exit(1);
	}
	await config.delete(key as keyof typeof config.keysFromEnv);
	process.exit(0);
}

// Parse arguments and handle help automatically
prog.parse(process.argv);


================================================
FILE: scripts/populate.ts
================================================
import readline from "readline";
import minimist from "minimist";

// @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
import { env } from "$env/dynamic/private";

import { faker } from "@faker-js/faker";
import { ObjectId } from "mongodb";

// @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
import { ready } from "$lib/server/config";
import { collections } from "$lib/server/database.ts";
import { models } from "../src/lib/server/models.ts";
import type { User } from "../src/lib/types/User";
import type { Assistant } from "../src/lib/types/Assistant";
import type { Conversation } from "../src/lib/types/Conversation";
import type { Settings } from "../src/lib/types/Settings";
import { Message } from "../src/lib/types/Message.ts";

import { addChildren } from "../src/lib/utils/tree/addChildren.ts";
import { generateSearchTokens } from "../src/lib/utils/searchTokens.ts";
import { ReviewStatus } from "../src/lib/types/Review.ts";
import fs from "fs";
import path from "path";

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});

await ready;

rl.on("close", function () {
	process.exit(0);
});

const samples = fs.readFileSync(path.join(__dirname, "samples.txt"), "utf8").split("\n---\n");

const possibleFlags = ["reset", "all", "users", "settings", "assistants", "conversations"];
const argv = minimist(process.argv.slice(2));
const flags = argv["_"].filter((flag) => possibleFlags.includes(flag));

async function generateMessages(preprompt?: string): Promise<Message[]> {
	const isLinear = faker.datatype.boolean(0.5);
	const isInterrupted = faker.datatype.boolean(0.05);

	const messages: Message[] = [];

	messages.push({
		id: crypto.randomUUID(),
		from: "system",
		content: preprompt ?? "",
		createdAt: faker.date.recent({ days: 30 }),
		updatedAt: faker.date.recent({ days: 30 }),
	});

	let isUser = true;
	let lastId = messages[0].id;
	if (isLinear) {
		const convLength = faker.number.int({ min: 1, max: 25 }) * 2; // must always be even

		for (let i = 0; i < convLength; i++) {
			lastId = addChildren(
				{
					messages,
					rootMessageId: messages[0].id,
				},
				{
					from: isUser ? "user" : "assistant",
					content:
						faker.lorem.sentence({
							min: 10,
							max: isUser ? 50 : 200,
						}) +
						(!isUser && Math.random() < 0.1
							? "\n```\n" + faker.helpers.arrayElement(samples) + "\n```\n"
							: ""),
					createdAt: faker.date.recent({ days: 30 }),
					updatedAt: faker.date.recent({ days: 30 }),
					interrupted: !isUser && i === convLength - 1 && isInterrupted,
				},
				lastId
			);
			isUser = !isUser;
		}
	} else {
		const convLength = faker.number.int({ min: 2, max: 200 });

		for (let i = 0; i < convLength; i++) {
			addChildren(
				{
					messages,
					rootMessageId: messages[0].id,
				},
				{
					from: isUser ? "user" : "assistant",
					content:
						faker.lorem.sentence({
							min: 10,
							max: isUser ? 50 : 200,
						}) +
						(!isUser && Math.random() < 0.1
							? "\n```\n" + faker.helpers.arrayElement(samples) + "\n```\n"
							: ""),
					createdAt: faker.date.recent({ days: 30 }),
					updatedAt: faker.date.recent({ days: 30 }),
					interrupted: !isUser && i === convLength - 1 && isInterrupted,
				},
				faker.helpers.arrayElement([
					messages[0].id,
					...messages.filter((m) => m.from === (isUser ? "assistant" : "user")).map((m) => m.id),
				])
			);

			isUser = !isUser;
		}
	}
	return messages;
}

async function seed() {
	console.log("Seeding...");
	const modelIds = models.map((model) => model.id);

	if (flags.includes("reset")) {
		console.log("Starting reset of DB");
		await collections.users.deleteMany({});
		await collections.settings.deleteMany({});
		await collections.assistants.deleteMany({});
		await collections.conversations.deleteMany({});
		await collections.migrationResults.deleteMany({});
		await collections.semaphores.deleteMany({});
		console.log("Reset done");
	}

	if (flags.includes("users") || flags.includes("all")) {
		console.log("Creating 100 new users");
		const newUsers: User[] = Array.from({ length: 100 }, () => ({
			_id: new ObjectId(),
			createdAt: faker.date.recent({ days: 30 }),
			updatedAt: faker.date.recent({ days: 30 }),
			username: faker.internet.userName(),
			name: faker.person.fullName(),
			hfUserId: faker.string.alphanumeric(24),
			avatarUrl: faker.image.avatar(),
		}));

		await collections.users.insertMany(newUsers);
		console.log("Done creating users.");
	}

	const users = await collections.users.find().toArray();
	if (flags.includes("settings") || flags.includes("all")) {
		console.log("Updating settings for all users");
		users.forEach(async (user) => {
			const settings: Settings = {
				userId: user._id,
				shareConversationsWithModelAuthors: faker.datatype.boolean(0.25),
				hideEmojiOnSidebar: faker.datatype.boolean(0.25),
				activeModel: faker.helpers.arrayElement(modelIds),
				createdAt: faker.date.recent({ days: 30 }),
				updatedAt: faker.date.recent({ days: 30 }),
				disableStream: faker.datatype.boolean(0.25),
				directPaste: faker.datatype.boolean(0.25),
				hidePromptExamples: {},
				customPrompts: {},
				assistants: [],
			};
			await collections.settings.updateOne(
				{ userId: user._id },
				{ $set: { ...settings } },
				{ upsert: true }
			);
		});
		console.log("Done updating settings.");
	}

	if (flags.includes("assistants") || flags.includes("all")) {
		console.log("Creating assistants for all users");
		await Promise.all(
			users.map(async (user) => {
				const name = faker.animal.insect();
				const assistants = faker.helpers.multiple<Assistant>(
					() => ({
						_id: new ObjectId(),
						name,
						createdById: user._id,
						createdByName: user.username,
						createdAt: faker.date.recent({ days: 30 }),
						updatedAt: faker.date.recent({ days: 30 }),
						userCount: faker.number.int({ min: 1, max: 100000 }),
						review: faker.helpers.enumValue(ReviewStatus),
						modelId: faker.helpers.arrayElement(modelIds),
						description: faker.lorem.sentence(),
						preprompt: faker.hacker.phrase(),
						exampleInputs: faker.helpers.multiple(() => faker.lorem.sentence(), {
							count: faker.number.int({ min: 0, max: 4 }),
						}),
						searchTokens: generateSearchTokens(name),
						last24HoursCount: faker.number.int({ min: 0, max: 1000 }),
					}),
					{ count: faker.number.int({ min: 3, max: 10 }) }
				);
				await collections.assistants.insertMany(assistants);
				await collections.settings.updateOne(
					{ userId: user._id },
					{ $set: { assistants: assistants.map((a) => a._id.toString()) } },
					{ upsert: true }
				);
			})
		);
		console.log("Done creating assistants.");
	}

	if (flags.includes("conversations") || flags.includes("all")) {
		console.log("Creating conversations for all users");
		await Promise.all(
			users.map(async (user) => {
				const conversations = faker.helpers.multiple(
					async () => {
						const settings = await collections.settings.findOne<Settings>({ userId: user._id });

						const assistantId =
							settings?.assistants && settings.assistants.length > 0 && faker.datatype.boolean(0.1)
								? faker.helpers.arrayElement<ObjectId>(settings.assistants)
								: undefined;

						const preprompt =
							(assistantId
								? await collections.assistants
										.findOne({ _id: assistantId })
										.then((assistant: Assistant) => assistant?.preprompt ?? "")
								: faker.helpers.maybe(() => faker.hacker.phrase(), { probability: 0.5 })) ?? "";

						const messages = await generateMessages(preprompt);

						const conv = {
							_id: new ObjectId(),
							userId: user._id,
							assistantId,
							preprompt,
							createdAt: faker.date.recent({ days: 145 }),
							updatedAt: faker.date.recent({ days: 145 }),
							model: faker.helpers.arrayElement(modelIds),
							title: faker.internet.emoji() + " " + faker.hacker.phrase(),
							// embeddings removed in this build
							messages,
							rootMessageId: messages[0].id,
						} satisfies Conversation;

						return conv;
					},
					{ count: faker.number.int({ min: 10, max: 200 }) }
				);

				await collections.conversations.insertMany(await Promise.all(conversations));
			})
		);
		console.log("Done creating conversations.");
	}
}

// run seed
(async () => {
	try {
		rl.question(
			"You're about to run a seeding script on the following MONGODB_URL: \x1b[31m" +
				env.MONGODB_URL +
				"\x1b[0m\n\n With the following flags: \x1b[31m" +
				flags.join("\x1b[0m , \x1b[31m") +
				"\x1b[0m\n \n\n Are you sure you want to continue? (yes/no): ",
			async (confirm) => {
				if (confirm !== "yes") {
					console.log("Not 'yes', exiting.");
					rl.close();
					process.exit(0);
				}
				console.log("Starting seeding...");
				await seed();
				console.log("Seeding done.");
				rl.close();
			}
		);
	} catch (e) {
		console.error(e);
		process.exit(1);
	}
})();


================================================
FILE: scripts/samples.txt
================================================
import { Observable, of, from, interval, throwError } from 'rxjs';
import { map, filter, catchError, switchMap, take, tap } from 'rxjs/operators';

// Mock function to fetch stock prices (simulates API call)
const fetchStockPrice = (ticker: string): Observable<number> => {
    return new Observable<number>((observer) => {
        const intervalId = setInterval(() => {
            if (Math.random() < 0.1) { // Simulating an error 10% of the time
                observer.error(`Error fetching stock price for ${ticker}`);
            } else {
                const price = parseFloat((Math.random() * 1000).toFixed(2));
                observer.next(price);
            }
        }, 1000);

        return () => {
            clearInterval(intervalId);
            console.log(`Stopped fetching prices for ${ticker}`);
        };
    });
};

// Example usage: Tracking stock price updates
const stockTicker = 'AAPL';
const stockPrice$ = fetchStockPrice(stockTicker).pipe(
    map(price => ({ ticker: stockTicker, price })),  // Transform data
    filter(data => data.price > 500), // Only keep prices above 500
    tap(data => console.log(`Price update:`, data)), // Side effect: Logging
    catchError(err => {
        console.error(err);
        return of({ ticker: stockTicker, price: null }); // Fallback observable
    })
);

// Subscribe to the stock price updates
const subscription = stockPrice$.subscribe({
    next: data => console.log(`Subscriber received:`, data),
    error: err => console.error(`Subscription error:`, err),
    complete: () => console.log('Stream complete'),
});

// Automatically unsubscribe after 10 seconds
setTimeout(() => {
    subscription.unsubscribe();
    console.log('Unsubscribed from stock price updates.');
}, 10000);
---
class EnforceAttrsMeta(type):
    """
    Metaclass that enforces the presence of specific attributes in a class
    and automatically decorates methods with a logging wrapper.
    """
    
    required_attributes = ['name', 'version']

    def __new__(cls, name, bases, class_dict):
        """
        Create a new class with enforced attributes and method logging.

        :param name: Name of the class being created.
        :param bases: Tuple of base classes.
        :param class_dict: Dictionary of attributes and methods of the class.
        :return: Newly created class object.
        """
        # Ensure required attributes exist
        for attr in cls.required_attributes:
            if attr not in class_dict:
                raise TypeError(f"Class '{name}' is missing required attribute '{attr}'")

        # Wrap all methods in a logging decorator
        for key, value in class_dict.items():
            if callable(value):  # Check if it's a method
                class_dict[key] = cls.log_calls(value)

        return super().__new__(cls, name, bases, class_dict)

    @staticmethod
    def log_calls(func):
        """
        Decorator that logs method calls and arguments.

        :param func: Function to be wrapped.
        :return: Wrapped function with logging.
        """
        def wrapper(*args, **kwargs):
            print(f"Calling {func.__name__} with args={args} kwargs={kwargs}")
            result = func(*args, **kwargs)
            print(f"{func.__name__} returned {result}")
            return result
        return wrapper


class PluginBase(metaclass=EnforceAttrsMeta):
    """
    Base class for plugins that enforces required attributes and logging.
    """
    name = "BasePlugin"
    version = "1.0"

    def run(self, data):
        """
        Process the input data.

        :param data: The data to be processed.
        :return: Processed result.
        """
        return f"Processed {data}"


class CustomPlugin(PluginBase):
    """
    Custom plugin that extends PluginBase and adheres to enforced rules.
    """
    name = "CustomPlugin"
    version = "2.0"

    def run(self, data):
        """
        Custom processing logic.

        :param data: The data to process.
        :return: Modified data.
        """
        return f"Custom processing of {data}"


# Uncommenting the following class definition will raise a TypeError
# because 'version' attribute is missing.
# class InvalidPlugin(PluginBase):
#     name = "InvalidPlugin"


if __name__ == "__main__":
    # Instantiate and use the plugin
    plugin = CustomPlugin()
    print(plugin.run("example data"))
---
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Click the Box Game</title>
    <style>
        body {
            text-align: center;
            font-family: Arial, sans-serif;
        }
        #game-container {
            position: relative;
            width: 300px;
            height: 300px;
            margin: 20px auto;
            border: 2px solid black;
            overflow: hidden;
        }
        #target {
            width: 50px;
            height: 50px;
            background-color: red;
            position: absolute;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>Click the Box!</h1>
    <p>Score: <span id="score">0</span></p>
    <div id="game-container">
        <div id="target"></div>
    </div>
    <script>
        let score = 0;
        const target = document.getElementById("target");
        const scoreDisplay = document.getElementById("score");
        const container = document.getElementById("game-container");
        
        function moveTarget() {
            const maxX = container.clientWidth - target.clientWidth;
            const maxY = container.clientHeight - target.clientHeight;
            target.style.left = Math.random() * maxX + "px";
            target.style.top = Math.random() * maxY + "px";
        }
        
        target.addEventListener("click", function() {
            score++;
            scoreDisplay.textContent = score;
            moveTarget();
        });
        
        moveTarget();
    </script>
</body>
</html>


================================================
FILE: scripts/setups/vitest-setup-client.ts
================================================


================================================
FILE: scripts/setups/vitest-setup-server.ts
================================================
import { vi, afterAll } from "vitest";
import dotenv from "dotenv";
import { resolve } from "path";
import fs from "fs";
import { MongoMemoryServer } from "mongodb-memory-server";

let mongoServer: MongoMemoryServer;
// Load the .env file
const envPath = resolve(__dirname, "../../.env");
dotenv.config({ path: envPath });

// Read the .env file content
const envContent = fs.readFileSync(envPath, "utf-8");

// Parse the .env content
const envVars = dotenv.parse(envContent);

// Separate public and private variables
const publicEnv = {};
const privateEnv = {};

for (const [key, value] of Object.entries(envVars)) {
	if (key.startsWith("PUBLIC_")) {
		publicEnv[key] = value;
	} else {
		privateEnv[key] = value;
	}
}

vi.mock("$env/dynamic/public", () => ({
	env: publicEnv,
}));

vi.mock("$env/dynamic/private", async () => {
	mongoServer = await MongoMemoryServer.create();

	return {
		env: {
			...privateEnv,
			MONGODB_URL: mongoServer.getUri(),
		},
	};
});

afterAll(async () => {
	if (mongoServer) {
		await mongoServer.stop();
	}
});


================================================
FILE: scripts/updateLocalEnv.ts
================================================
import fs from "fs";
import yaml from "js-yaml";

const file = fs.readFileSync("chart/env/prod.yaml", "utf8");

// have to do a weird stringify/parse because of some node error
const prod = JSON.parse(JSON.stringify(yaml.load(file)));
const vars = prod.envVars as Record<string, string>;

let PUBLIC_CONFIG = "";

Object.entries(vars)
	// filter keys used in prod with the proxy
	.filter(
		([key]) =>
			![
				"XFF_DEPTH",
				"ADDRESS_HEADER",
				"APP_BASE",
				"PUBLIC_ORIGIN",
				"PUBLIC_SHARE_PREFIX",
				"ADMIN_CLI_LOGIN",
			].includes(key)
	)
	.forEach(([key, value]) => {
		PUBLIC_CONFIG += `${key}=\`${value}\`\n`;
	});

const SECRET_CONFIG =
	(fs.existsSync(".env.SECRET_CONFIG")
		? fs.readFileSync(".env.SECRET_CONFIG", "utf8")
		: process.env.SECRET_CONFIG) ?? "";

// Prepend the content of the env variable SECRET_CONFIG
let full_config = `${PUBLIC_CONFIG}\n${SECRET_CONFIG}`;

// replace the internal proxy url with the public endpoint
full_config = full_config.replaceAll(
	"https://internal.api-inference.huggingface.co",
	"https://router.huggingface.co/hf-inference"
);

full_config = full_config.replaceAll("COOKIE_SECURE=`true`", "COOKIE_SECURE=`false`");
full_config = full_config.replaceAll("LOG_LEVEL=`debug`", "LOG_LEVEL=`info`");
full_config = full_config.replaceAll("NODE_ENV=`prod`", "NODE_ENV=`development`");

// Write full_config to .env.local
fs.writeFileSync(".env.local", full_config);


================================================
FILE: server.log
================================================
/Users/vm/.venv/bin/python3: No module named uvicorn
/Users/vm/.venv/bin/python3: No module named uvicorn


================================================
FILE: src/ambient.d.ts
================================================
declare module "*.ttf" {
	const value: ArrayBuffer;
	export default value;
}

// Legacy helpers removed: web search support is deprecated, so we intentionally
// avoid leaking those shapes into the global ambient types.


================================================
FILE: src/app.d.ts
================================================
/// <reference types="@sveltejs/kit" />
/// <reference types="unplugin-icons/types/svelte" />

import type { User } from "$lib/types/User";

// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
	namespace App {
		// interface Error {}
		interface Locals {
			sessionId: string;
			user?: User;
			isAdmin: boolean;
			token?: string;
			/** Organization to bill inference requests to (from settings) */
			billingOrganization?: string;
		}

		interface Error {
			message: string;
			errorId?: ReturnType<typeof crypto.randomUUID>;
		}
		// interface PageData {}
		// interface Platform {}
	}
}

export {};


================================================
FILE: src/app.html
================================================
<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta
			name="viewport"
			content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
		/>
		<meta name="theme-color" content="rgb(249, 250, 251)" />
		<script>
			(function () {
				try {
					var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
					var stored = localStorage.getItem("theme");
					var followSystem = stored === null || stored === "system";
					var isDark = stored === "dark" || (followSystem && prefersDark);
					if (isDark) {
						document.documentElement.classList.add("dark");
						document.querySelector('meta[name="theme-color"]').setAttribute("content", "#07090d");
					}
				} catch (e) {}
			})();

			// For some reason, Sveltekit doesn't let us load env variables from .env here, so we load it from hooks.server.ts
			window.gaId = "%gaId%";
		</script>
		%sveltekit.head%
	</head>
	<body data-sveltekit-preload-data="hover" class="h-dvh dark:bg-gray-900">
		<div id="app" class="contents h-full">%sveltekit.body%</div>

		<!-- Google Tag Manager -->
		<script>
			if (window.gaId) {
				const script = document.createElement("script");
				script.src = "https://www.googletagmanager.com/gtag/js?id=" + window.gaId;
				script.async = true;
				document.head.appendChild(script);

				window.dataLayer = window.dataLayer || [];
				function gtag() {
					dataLayer.push(arguments);
				}
				gtag("js", new Date());
				/// ^ See https://developers.google.com/tag-platform/gtagjs/install
				gtag("config", window.gaId);
				gtag("consent", "default", { ad_storage: "denied", analytics_storage: "denied" });
				/// ^ See https://developers.google.com/tag-platform/gtagjs/reference#consent
				/// TODO: ask the user for their consent and update this with gtag('consent', 'update')
			}
		</script>
	</body>
</html>


================================================
FILE: src/hooks.server.ts
================================================
import { building } from "$app/environment";
import type { Handle, HandleServerError, ServerInit, HandleFetch } from "@sveltejs/kit";
import { initServer } from "$lib/server/hooks/init";
import { handleRequest } from "$lib/server/hooks/handle";
import { handleServerError } from "$lib/server/hooks/error";
import { handleFetchRequest } from "$lib/server/hooks/fetch";

export const init: ServerInit = async () => {
	if (building) return;
	return initServer();
};

export const handle: Handle = async (input) => {
	if (building) {
		// During static build, still replace %gaId% placeholder with empty string
		// to prevent the GA script from loading with an invalid ID
		return input.resolve(input.event, {
			transformPageChunk: ({ html }) => html.replace("%gaId%", ""),
		});
	}
	return handleRequest(input);
};

export const handleError: HandleServerError = async (input) => {
	if (building) throw input.error;
	return handleServerError(input);
};

export const handleFetch: HandleFetch = async (input) => {
	if (building) return input.fetch(input.request);
	return handleFetchRequest(input);
};


================================================
FILE: src/hooks.ts
================================================
import { publicConfigTransporter } from "$lib/utils/PublicConfig.svelte";
import type { Transport } from "@sveltejs/kit";

export const transport: Transport = {
	PublicConfig: publicConfigTransporter,
};


================================================
FILE: src/lib/APIClient.ts
================================================
import { base } from "$app/paths";
import { browser } from "$app/environment";
import superjson from "superjson";
import ObjectId from "bson-objectid";

superjson.registerCustom<ObjectId, string>(
	{
		isApplicable: (value): value is ObjectId => {
			if (typeof value !== "string" && ObjectId.isValid(value)) {
				const str = value.toString();
				return /^[0-9a-fA-F]{24}$/.test(str);
			}
			return false;
		},
		serialize: (value) => value.toString(),
		deserialize: (value) => new ObjectId(value),
	},
	"ObjectId"
);

type FetchFn = typeof globalThis.fetch;

interface ApiResponse<T = unknown> {
	data: T | null;
	error: unknown;
	status: number;
}

async function apiCall<T = unknown>(
	fetcher: FetchFn,
	url: string,
	method: string,
	body?: unknown,
	query?: Record<string, string | number | undefined>
): Promise<ApiResponse<T>> {
	const u = new URL(url);
	if (query) {
		for (const [k, v] of Object.entries(query)) {
			if (v !== undefined && v !== null) {
				u.searchParams.set(k, String(v));
			}
		}
	}

	const init: RequestInit = { method };
	if (body !== undefined && body !== null) {
		init.headers = { "Content-Type": "application/json" };
		init.body = JSON.stringify(body);
	}

	const res = await fetcher(u.toString(), init);
	if (!res.ok) {
		let errorBody: unknown;
		try {
			errorBody = await res.json();
		} catch {
			errorBody = await res.text().catch(() => res.statusText);
		}
		return { data: null, error: errorBody, status: res.status };
	}

	// Handle empty responses (e.g. POST /user/settings returns empty body)
	const text = await res.text();
	if (!text) {
		return { data: null, error: null, status: res.status };
	}

	return { data: text as unknown as T, error: null, status: res.status };
}

function endpoint(fetcher: FetchFn, baseUrl: string) {
	return {
		get(opts?: { query?: Record<string, string | number | undefined> }) {
			return apiCall(fetcher, baseUrl, "GET", undefined, opts?.query);
		},
		post(body?: unknown) {
			return apiCall(fetcher, baseUrl, "POST", body);
		},
		patch(body?: unknown) {
			return apiCall(fetcher, baseUrl, "PATCH", body);
		},
		delete() {
			return apiCall(fetcher, baseUrl, "DELETE");
		},
	};
}

export function useAPIClient({
	fetch: customFetch,
	origin,
}: {
	fetch?: FetchFn;
	origin?: string;
} = {}) {
	const fetcher = customFetch ?? globalThis.fetch;
	const baseUrl = browser
		? `${window.location.origin}${base}/api/v2`
		: `${origin ?? `http://localhost:5173`}${base}/api/v2`;

	return {
		conversations: Object.assign(
			// client.conversations({ id: "..." }) — returns endpoint for /conversations/:id
			(params: { id: string }) => ({
				...endpoint(fetcher, `${baseUrl}/conversations/${params.id}`),
				message: (msgParams: { messageId: string }) =>
					endpoint(fetcher, `${baseUrl}/conversations/${params.id}/message/${msgParams.messageId}`),
			}),
			// client.conversations.get(), .delete()
			{
				...endpoint(fetcher, `${baseUrl}/conversations`),
				"import-share": endpoint(fetcher, `${baseUrl}/conversations/import-share`),
			}
		),
		user: {
			...endpoint(fetcher, `${baseUrl}/user`),
			settings: endpoint(fetcher, `${baseUrl}/user/settings`),
			reports: endpoint(fetcher, `${baseUrl}/user/reports`),
			"billing-orgs": endpoint(fetcher, `${baseUrl}/user/billing-orgs`),
		},
		models: {
			...endpoint(fetcher, `${baseUrl}/models`),
			old: endpoint(fetcher, `${baseUrl}/models/old`),
			refresh: endpoint(fetcher, `${baseUrl}/models/refresh`),
		},
		"public-config": endpoint(fetcher, `${baseUrl}/public-config`),
		"feature-flags": endpoint(fetcher, `${baseUrl}/feature-flags`),
		debug: {
			config: endpoint(fetcher, `${baseUrl}/debug/config`),
			refresh: endpoint(fetcher, `${baseUrl}/debug/refresh`),
		},
		export: endpoint(fetcher, `${baseUrl}/export`),
	};
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function handleResponse(response: ApiResponse<any>): any {
	if (response.error) {
		throw new Error(JSON.stringify(response.error));
	}

	if (response.data === null) {
		return null;
	}

	return superjson.parse(
		typeof response.data === "string" ? response.data : JSON.stringify(response.data)
	);
}


================================================
FILE: src/lib/actions/clickOutside.ts
================================================
export function clickOutside(element: HTMLElement, callbackFunction: () => void) {
	function onClick(event: MouseEvent) {
		if (!element.contains(event.target as Node)) {
			callbackFunction();
		}
	}

	document.body.addEventListener("click", onClick);

	return {
		update(newCallbackFunction: () => void) {
			callbackFunction = newCallbackFunction;
		},
		destroy() {
			document.body.removeEventListener("click", onClick);
		},
	};
}


================================================
FILE: src/lib/actions/snapScrollToBottom.ts
================================================
import { navigating } from "$app/state";
import { tick } from "svelte";

// Threshold to determine if user is "at bottom" - larger value prevents false detachment
const BOTTOM_THRESHOLD = 50;
const USER_SCROLL_DEBOUNCE_MS = 150;
const PROGRAMMATIC_SCROLL_GRACE_MS = 100;
const TOUCH_DETACH_THRESHOLD_PX = 10;

interface ScrollDependency {
	signal: unknown;
	forceReattach?: number;
}

type MaybeScrollDependency = ScrollDependency | unknown;

const getForceReattach = (value: MaybeScrollDependency): number => {
	if (typeof value === "object" && value !== null && "forceReattach" in value) {
		return (value as ScrollDependency).forceReattach ?? 0;
	}
	return 0;
};

/**
 * Auto-scroll action that snaps to bottom while respecting user scroll intent.
 *
 * Key behaviors:
 * 1. Uses wheel/touch events to detect actual user intent
 * 2. Uses IntersectionObserver on a sentinel element to reliably detect "at bottom" state
 * 3. Larger threshold to prevent edge-case false detachments
 *
 * @param node element to snap scroll to bottom
 * @param dependency pass in { signal, forceReattach } - signal triggers scroll updates,
 *                   forceReattach (counter) forces re-attachment when incremented
 */
export const snapScrollToBottom = (node: HTMLElement, dependency: MaybeScrollDependency) => {
	// --- State ----------------------------------------------------------------

	// Track whether user has intentionally scrolled away from bottom
	let isDetached = false;

	// Track the last forceReattach value to detect changes
	let lastForceReattach = getForceReattach(dependency);

	// Track if user is actively scrolling (via wheel/touch)
	let userScrolling = false;
	let userScrollTimeout: ReturnType<typeof setTimeout> | undefined;

	// Track programmatic scrolls to avoid treating them as user scrolls
	let isProgrammaticScroll = false;
	let lastProgrammaticScrollTime = 0;

	// Track previous scroll position to detect scrollbar drags
	let prevScrollTop = node.scrollTop;

	// Touch handling state
	let touchStartY = 0;

	// Observers and sentinel
	let resizeObserver: ResizeObserver | undefined;
	let intersectionObserver: IntersectionObserver | undefined;
	let sentinel: HTMLDivElement | undefined;

	// Track content height for early-return optimization during streaming
	let lastScrollHeight = node.scrollHeight;

	// --- Helpers --------------------------------------------------------------

	const clearUserScrollTimeout = () => {
		if (userScrollTimeout) {
			clearTimeout(userScrollTimeout);
			userScrollTimeout = undefined;
		}
	};

	const distanceFromBottom = () => node.scrollHeight - node.scrollTop - node.clientHeight;

	const isAtBottom = () => distanceFromBottom() <= BOTTOM_THRESHOLD;

	const scrollToBottom = () => {
		isProgrammaticScroll = true;
		lastProgrammaticScrollTime = Date.now();

		node.scrollTo({ top: node.scrollHeight });

		if (typeof requestAnimationFrame === "function") {
			requestAnimationFrame(() => {
				isProgrammaticScroll = false;
			});
		} else {
			isProgrammaticScroll = false;
		}
	};

	const settleScrollAfterLayout = async () => {
		if (typeof requestAnimationFrame !== "function") return;

		const raf = () => new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));

		await raf();
		if (!userScrolling && !isDetached) {
			scrollToBottom();
		}

		await raf();
		if (!userScrolling && !isDetached) {
			scrollToBottom();
		}
	};

	const scheduleUserScrollEndCheck = () => {
		userScrolling = true;
		clearUserScrollTimeout();

		userScrollTimeout = setTimeout(() => {
			userScrolling = false;

			// If user scrolled back to bottom, re-attach
			if (isAtBottom()) {
				isDetached = false;
			}

			// Re-trigger scroll if still attached, to catch content that arrived during scrolling
			if (!isDetached) {
				scrollToBottom();
			}
		}, USER_SCROLL_DEBOUNCE_MS);
	};

	const createSentinel = () => {
		sentinel = document.createElement("div");
		sentinel.style.height = "1px";
		sentinel.style.width = "100%";
		sentinel.setAttribute("aria-hidden", "true");
		sentinel.setAttribute("data-scroll-sentinel", "");

		// Find the content container (first child) and append sentinel there
		const container = node.firstElementChild;
		if (container) {
			container.appendChild(sentinel);
		} else {
			node.appendChild(sentinel);
		}
	};

	const setupIntersectionObserver = () => {
		if (typeof IntersectionObserver === "undefined" || !sentinel) return;

		intersectionObserver = new IntersectionObserver(
			(entries) => {
				const entry = entries[0];

				// If sentinel is visible and user isn't actively scrolling, we're at bottom
				if (entry?.isIntersecting && !userScrolling) {
					isDetached = false;
					// Immediately scroll to catch up with any content that arrived while detached
					scrollToBottom();
				}
			},
			{
				root: node,
				threshold: 0,
				rootMargin: `0px 0px ${BOTTOM_THRESHOLD}px 0px`,
			}
		);

		intersectionObserver.observe(sentinel);
	};

	const setupResizeObserver = () => {
		if (typeof ResizeObserver === "undefined") return;

		const target = node.firstElementChild ?? node;
		resizeObserver = new ResizeObserver(() => {
			// Don't auto-scroll if user has detached and we're not navigating
			if (isDetached && !navigating.to) return;
			// Don't interrupt active user scrolling
			if (userScrolling) return;

			scrollToBottom();
		});

		resizeObserver.observe(target);
	};

	// --- Action update logic --------------------------------------------------

	const handleForceReattach = async (newDependency: MaybeScrollDependency) => {
		const forceReattach = getForceReattach(newDependency);

		if (forceReattach > lastForceReattach) {
			lastForceReattach = forceReattach;
			isDetached = false;
			userScrolling = false;
			clearUserScrollTimeout();

			await tick();
			scrollToBottom();
			return true;
		}

		return false;
	};

	async function updateScroll(newDependency?: MaybeScrollDependency) {
		// 1. Explicit force re-attach
		if (newDependency && (await handleForceReattach(newDependency))) {
			return;
		}

		// 2. Don't scroll if user has detached and we're not navigating
		if (isDetached && !navigating.to) return;

		// 3. Don't scroll if user is actively scrolling
		if (userScrolling) return;

		// 4. Early return if already at bottom and no content change (perf optimization for streaming)
		const currentHeight = node.scrollHeight;
		if (isAtBottom() && currentHeight === lastScrollHeight) {
			return;
		}
		lastScrollHeight = currentHeight;

		// 5. Wait for DOM to update, then scroll and settle after layout shifts
		await tick();
		scrollToBottom();
		await settleScrollAfterLayout();
	}

	// --- Event handlers -------------------------------------------------------

	// Detect user scroll intent via wheel events (mouse/trackpad)
	const handleWheel = (event: WheelEvent) => {
		const { deltaY } = event;

		// User is scrolling up - detach
		if (deltaY < 0) {
			isDetached = true;
		}

		// User is scrolling down - check for re-attachment immediately
		// This ensures fast re-attachment when user scrolls to bottom during fast generation
		if (deltaY > 0 && isAtBottom()) {
			isDetached = false;
			userScrolling = false;
			clearUserScrollTimeout();
			scrollToBottom();
			return;
		}

		scheduleUserScrollEndCheck();
	};

	// Detect user scroll intent via touch events (mobile)
	const handleTouchStart = (event: TouchEvent) => {
		touchStartY = event.touches[0]?.clientY ?? 0;
	};

	const handleTouchMove = (event: TouchEvent) => {
		const touchY = event.touches[0]?.clientY ?? 0;
		const deltaY = touchStartY - touchY;

		// User is scrolling up (finger moving down)
		if (deltaY < -TOUCH_DETACH_THRESHOLD_PX) {
			isDetached = true;
		}

		// User is scrolling down (finger moving up) - check for re-attachment immediately
		if (deltaY > TOUCH_DETACH_THRESHOLD_PX && isAtBottom()) {
			isDetached = false;
			userScrolling = false;
			clearUserScrollTimeout();
			scrollToBottom();
			touchStartY = touchY;
			return;
		}

		scheduleUserScrollEndCheck();
		touchStartY = touchY;
	};

	// Handle scroll events to detect scrollbar usage and re-attach when at bottom
	const handleScroll = () => {
		const now = Date.now();
		const timeSinceLastProgrammaticScroll = now - lastProgrammaticScrollTime;
		const inGracePeriod =
			isProgrammaticScroll || timeSinceLastProgrammaticScroll < PROGRAMMATIC_SCROLL_GRACE_MS;

		// If not from wheel/touch, this is likely a scrollbar drag
		if (!userScrolling) {
			const scrollingUp = node.scrollTop < prevScrollTop;

			// Always allow detach (scrolling up) - don't ignore user intent
			if (scrollingUp) {
				isDetached = true;
			}

			// Only re-attach when at bottom if NOT in grace period
			// (avoids false re-attach from content resize pushing scroll position)
			if (!inGracePeriod && isAtBottom()) {
				isDetached = false;
				// Immediately scroll to catch up with any content that arrived while detached
				scrollToBottom();
			}
		}

		prevScrollTop = node.scrollTop;
	};

	// --- Setup ----------------------------------------------------------------

	node.addEventListener("wheel", handleWheel, { passive: true });
	node.addEventListener("touchstart", handleTouchStart, { passive: true });
	node.addEventListener("touchmove", handleTouchMove, { passive: true });
	node.addEventListener("scroll", handleScroll, { passive: true });

	createSentinel();
	setupIntersectionObserver();
	setupResizeObserver();

	// Initial scroll if we have content
	if (dependency) {
		void (async () => {
			await tick();
			scrollToBottom();
		})();
	}

	// --- Cleanup --------------------------------------------------------------

	return {
		update: updateScroll,
		destroy: () => {
			clearUserScrollTimeout();

			node.removeEventListener("wheel", handleWheel);
			node.removeEventListener("touchstart", handleTouchStart);
			node.removeEventListener("touchmove", handleTouchMove);
			node.removeEventListener("scroll", handleScroll);

			resizeObserver?.disconnect();
			intersectionObserver?.disconnect();
			sentinel?.remove();
		},
	};
};


================================================
FILE: src/lib/buildPrompt.ts
================================================
import type { EndpointParameters } from "./server/endpoints/endpoints";
import type { BackendModel } from "./server/models";

type buildPromptOptions = Pick<EndpointParameters, "messages" | "preprompt"> & {
	model: BackendModel;
};

export async function buildPrompt({
	messages,
	model,
	preprompt,
}: buildPromptOptions): Promise<string> {
	const filteredMessages = messages;

	if (filteredMessages[0].from === "system" && preprompt) {
		filteredMessages[0].content = preprompt;
	}

	const prompt = model
		.chatPromptRender({
			messages: filteredMessages.map((m) => ({
				...m,
				role: m.from,
			})),
			preprompt,
		})
		// Not super precise, but it's truncated in the model's backend anyway
		.split(" ")
		.slice(-(model.parameters?.truncate ?? 0))
		.join(" ");

	return prompt;
}


================================================
FILE: src/lib/components/AnnouncementBanner.svelte
================================================
<script lang="ts">
	interface Props {
		title?: string;
		classNames?: string;
		children?: import("svelte").Snippet;
	}

	let { title = "", classNames = "", children }: Props = $props();
</script>

<div class="flex items-center rounded-xl bg-gray-100 p-1 text-sm dark:bg-gray-800 {classNames}">
	<span
		class="mr-2 inline-flex items-center rounded-lg bg-gradient-to-br from-gray-300 px-2 py-1 text-xxs font-medium uppercase leading-3 text-gray-700 dark:from-gray-900 dark:text-gray-400"
		>New</span
	>
	{title}
	<div class="ml-auto shrink-0">
		{@render children?.()}
	</div>
</div>


==========
Download .txt
gitextract_mfj9ft39/

├── .devcontainer/
│   ├── Dockerfile
│   └── devcontainer.json
├── .dockerignore
├── .env
├── .env.ci
├── .eslintignore
├── .eslintrc.cjs
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report--chat-ui-.md
│   │   ├── config-support.md
│   │   ├── feature-request--chat-ui-.md
│   │   └── huggingchat.md
│   ├── release.yml
│   └── workflows/
│       ├── build-docs.yml
│       ├── build-image.yml
│       ├── build-pr-docs.yml
│       ├── deploy-dev.yml
│       ├── deploy-prod.yml
│       ├── lint-and-test.yml
│       ├── slugify.yaml
│       ├── trufflehog.yml
│       └── upload-pr-documentation.yml
├── .gitignore
├── .husky/
│   ├── lint-stage-config.js
│   └── pre-commit
├── .npmrc
├── .prettierignore
├── .prettierrc
├── .vscode/
│   ├── launch.json
│   └── settings.json
├── CLAUDE.md
├── Dockerfile
├── LICENSE
├── PRIVACY.md
├── README.md
├── chart/
│   ├── Chart.yaml
│   ├── env/
│   │   ├── dev.yaml
│   │   └── prod.yaml
│   ├── templates/
│   │   ├── _helpers.tpl
│   │   ├── config.yaml
│   │   ├── deployment.yaml
│   │   ├── hpa.yaml
│   │   ├── infisical.yaml
│   │   ├── ingress-internal.yaml
│   │   ├── ingress.yaml
│   │   ├── network-policy.yaml
│   │   ├── service-account.yaml
│   │   ├── service-monitor.yaml
│   │   └── service.yaml
│   └── values.yaml
├── docker-compose.yml
├── docs/
│   └── source/
│       ├── _toctree.yml
│       ├── configuration/
│       │   ├── common-issues.md
│       │   ├── llm-router.md
│       │   ├── mcp-tools.md
│       │   ├── metrics.md
│       │   ├── open-id.md
│       │   ├── overview.md
│       │   └── theming.md
│       ├── developing/
│       │   └── architecture.md
│       ├── index.md
│       └── installation/
│           ├── docker.md
│           ├── helm.md
│           └── local.md
├── entrypoint.sh
├── models/
│   └── add-your-models-here.txt
├── package.json
├── postcss.config.js
├── scripts/
│   ├── config.ts
│   ├── populate.ts
│   ├── samples.txt
│   ├── setups/
│   │   ├── vitest-setup-client.ts
│   │   └── vitest-setup-server.ts
│   └── updateLocalEnv.ts
├── server.log
├── src/
│   ├── ambient.d.ts
│   ├── app.d.ts
│   ├── app.html
│   ├── hooks.server.ts
│   ├── hooks.ts
│   ├── lib/
│   │   ├── APIClient.ts
│   │   ├── actions/
│   │   │   ├── clickOutside.ts
│   │   │   └── snapScrollToBottom.ts
│   │   ├── buildPrompt.ts
│   │   ├── components/
│   │   │   ├── AnnouncementBanner.svelte
│   │   │   ├── BackgroundGenerationPoller.svelte
│   │   │   ├── CodeBlock.svelte
│   │   │   ├── CopyToClipBoardBtn.svelte
│   │   │   ├── DeleteConversationModal.svelte
│   │   │   ├── EditConversationModal.svelte
│   │   │   ├── ExpandNavigation.svelte
│   │   │   ├── HoverTooltip.svelte
│   │   │   ├── HtmlPreviewModal.svelte
│   │   │   ├── InfiniteScroll.svelte
│   │   │   ├── MobileNav.svelte
│   │   │   ├── Modal.svelte
│   │   │   ├── ModelCardMetadata.svelte
│   │   │   ├── NavConversationItem.svelte
│   │   │   ├── NavMenu.svelte
│   │   │   ├── Pagination.svelte
│   │   │   ├── PaginationArrow.svelte
│   │   │   ├── Portal.svelte
│   │   │   ├── RetryBtn.svelte
│   │   │   ├── ScrollToBottomBtn.svelte
│   │   │   ├── ScrollToPreviousBtn.svelte
│   │   │   ├── ShareConversationModal.svelte
│   │   │   ├── StopGeneratingBtn.svelte
│   │   │   ├── SubscribeModal.svelte
│   │   │   ├── Switch.svelte
│   │   │   ├── SystemPromptModal.svelte
│   │   │   ├── Toast.svelte
│   │   │   ├── Tooltip.svelte
│   │   │   ├── WelcomeModal.svelte
│   │   │   ├── chat/
│   │   │   │   ├── Alternatives.svelte
│   │   │   │   ├── BlockWrapper.svelte
│   │   │   │   ├── ChatInput.svelte
│   │   │   │   ├── ChatIntroduction.svelte
│   │   │   │   ├── ChatMessage.svelte
│   │   │   │   ├── ChatWindow.svelte
│   │   │   │   ├── FileDropzone.svelte
│   │   │   │   ├── ImageLightbox.svelte
│   │   │   │   ├── MarkdownBlock.svelte
│   │   │   │   ├── MarkdownRenderer.svelte
│   │   │   │   ├── MarkdownRenderer.svelte.test.ts
│   │   │   │   ├── MessageAvatar.svelte
│   │   │   │   ├── ModelSwitch.svelte
│   │   │   │   ├── OpenReasoningResults.svelte
│   │   │   │   ├── ToolUpdate.svelte
│   │   │   │   ├── UploadedFile.svelte
│   │   │   │   ├── UrlFetchModal.svelte
│   │   │   │   └── VoiceRecorder.svelte
│   │   │   ├── icons/
│   │   │   │   ├── IconBurger.svelte
│   │   │   │   ├── IconCheap.svelte
│   │   │   │   ├── IconChevron.svelte
│   │   │   │   ├── IconDazzled.svelte
│   │   │   │   ├── IconFast.svelte
│   │   │   │   ├── IconLoading.svelte
│   │   │   │   ├── IconMCP.svelte
│   │   │   │   ├── IconMoon.svelte
│   │   │   │   ├── IconNew.svelte
│   │   │   │   ├── IconOmni.svelte
│   │   │   │   ├── IconPaperclip.svelte
│   │   │   │   ├── IconPro.svelte
│   │   │   │   ├── IconShare.svelte
│   │   │   │   ├── IconSun.svelte
│   │   │   │   ├── Logo.svelte
│   │   │   │   └── LogoHuggingFaceBorderless.svelte
│   │   │   ├── mcp/
│   │   │   │   ├── AddServerForm.svelte
│   │   │   │   ├── MCPServerManager.svelte
│   │   │   │   └── ServerCard.svelte
│   │   │   ├── players/
│   │   │   │   └── AudioPlayer.svelte
│   │   │   └── voice/
│   │   │       └── AudioWaveform.svelte
│   │   ├── constants/
│   │   │   ├── mcpExamples.ts
│   │   │   ├── mime.ts
│   │   │   ├── pagination.ts
│   │   │   ├── publicSepToken.ts
│   │   │   └── routerExamples.ts
│   │   ├── createShareLink.ts
│   │   ├── jobs/
│   │   │   └── refresh-conversation-stats.ts
│   │   ├── migrations/
│   │   │   ├── lock.ts
│   │   │   ├── migrations.spec.ts
│   │   │   ├── migrations.ts
│   │   │   └── routines/
│   │   │       ├── 01-update-search-assistants.ts
│   │   │       ├── 02-update-assistants-models.ts
│   │   │       ├── 04-update-message-updates.ts
│   │   │       ├── 05-update-message-files.ts
│   │   │       ├── 06-trim-message-updates.ts
│   │   │       ├── 08-update-featured-to-review.ts
│   │   │       ├── 09-delete-empty-conversations.spec.ts
│   │   │       ├── 09-delete-empty-conversations.ts
│   │   │       ├── 10-update-reports-assistantid.ts
│   │   │       └── index.ts
│   │   ├── server/
│   │   │   ├── __tests__/
│   │   │   │   └── conversation-stop-generating.spec.ts
│   │   │   ├── abortRegistry.ts
│   │   │   ├── abortedGenerations.ts
│   │   │   ├── adminToken.ts
│   │   │   ├── api/
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── conversations-id.spec.ts
│   │   │   │   │   ├── conversations-message.spec.ts
│   │   │   │   │   ├── conversations.spec.ts
│   │   │   │   │   ├── misc.spec.ts
│   │   │   │   │   ├── testHelpers.ts
│   │   │   │   │   ├── user-reports.spec.ts
│   │   │   │   │   └── user.spec.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── requireAuth.ts
│   │   │   │       ├── resolveConversation.ts
│   │   │   │       ├── resolveModel.ts
│   │   │   │       └── superjsonResponse.ts
│   │   │   ├── apiToken.ts
│   │   │   ├── auth.ts
│   │   │   ├── config.ts
│   │   │   ├── conversation.ts
│   │   │   ├── database.ts
│   │   │   ├── endpoints/
│   │   │   │   ├── document.ts
│   │   │   │   ├── endpoints.ts
│   │   │   │   ├── images.ts
│   │   │   │   ├── openai/
│   │   │   │   │   ├── endpointOai.ts
│   │   │   │   │   ├── openAIChatToTextGenerationStream.ts
│   │   │   │   │   └── openAICompletionToTextGenerationStream.ts
│   │   │   │   └── preprocessMessages.ts
│   │   │   ├── exitHandler.ts
│   │   │   ├── files/
│   │   │   │   ├── downloadFile.ts
│   │   │   │   └── uploadFile.ts
│   │   │   ├── findRepoRoot.ts
│   │   │   ├── generateFromDefaultEndpoint.ts
│   │   │   ├── hooks/
│   │   │   │   ├── error.ts
│   │   │   │   ├── fetch.ts
│   │   │   │   ├── handle.ts
│   │   │   │   └── init.ts
│   │   │   ├── isURLLocal.spec.ts
│   │   │   ├── isURLLocal.ts
│   │   │   ├── logger.ts
│   │   │   ├── mcp/
│   │   │   │   ├── clientPool.ts
│   │   │   │   ├── hf.ts
│   │   │   │   ├── httpClient.ts
│   │   │   │   ├── registry.ts
│   │   │   │   └── tools.ts
│   │   │   ├── metrics.ts
│   │   │   ├── models.ts
│   │   │   ├── requestContext.ts
│   │   │   ├── router/
│   │   │   │   ├── arch.ts
│   │   │   │   ├── endpoint.ts
│   │   │   │   ├── multimodal.ts
│   │   │   │   ├── policy.ts
│   │   │   │   ├── toolsRoute.ts
│   │   │   │   └── types.ts
│   │   │   ├── sendSlack.ts
│   │   │   ├── textGeneration/
│   │   │   │   ├── generate.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── mcp/
│   │   │   │   │   ├── fileRefs.ts
│   │   │   │   │   ├── routerResolution.ts
│   │   │   │   │   ├── runMcpFlow.ts
│   │   │   │   │   └── toolInvocation.ts
│   │   │   │   ├── reasoning.ts
│   │   │   │   ├── title.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── prepareFiles.ts
│   │   │   │       ├── routing.ts
│   │   │   │       └── toolPrompt.ts
│   │   │   ├── urlSafety.ts
│   │   │   └── usageLimits.ts
│   │   ├── stores/
│   │   │   ├── backgroundGenerations.svelte.ts
│   │   │   ├── backgroundGenerations.ts
│   │   │   ├── errors.ts
│   │   │   ├── isAborted.ts
│   │   │   ├── isPro.ts
│   │   │   ├── loading.ts
│   │   │   ├── mcpServers.ts
│   │   │   ├── pendingChatInput.ts
│   │   │   ├── pendingMessage.ts
│   │   │   ├── settings.ts
│   │   │   ├── shareModal.ts
│   │   │   └── titleUpdate.ts
│   │   ├── switchTheme.ts
│   │   ├── types/
│   │   │   ├── AbortedGeneration.ts
│   │   │   ├── Assistant.ts
│   │   │   ├── AssistantStats.ts
│   │   │   ├── ConfigKey.ts
│   │   │   ├── ConvSidebar.ts
│   │   │   ├── Conversation.ts
│   │   │   ├── ConversationStats.ts
│   │   │   ├── Message.ts
│   │   │   ├── MessageEvent.ts
│   │   │   ├── MessageUpdate.ts
│   │   │   ├── MigrationResult.ts
│   │   │   ├── Model.ts
│   │   │   ├── Report.ts
│   │   │   ├── Review.ts
│   │   │   ├── Semaphore.ts
│   │   │   ├── Session.ts
│   │   │   ├── Settings.ts
│   │   │   ├── SharedConversation.ts
│   │   │   ├── Template.ts
│   │   │   ├── Timestamps.ts
│   │   │   ├── TokenCache.ts
│   │   │   ├── Tool.ts
│   │   │   ├── UrlDependency.ts
│   │   │   └── User.ts
│   │   ├── utils/
│   │   │   ├── PublicConfig.svelte.ts
│   │   │   ├── auth.ts
│   │   │   ├── chunk.ts
│   │   │   ├── cookiesAreEnabled.ts
│   │   │   ├── debounce.ts
│   │   │   ├── deepestChild.ts
│   │   │   ├── favicon.ts
│   │   │   ├── fetchJSON.ts
│   │   │   ├── file2base64.ts
│   │   │   ├── formatUserCount.ts
│   │   │   ├── generationState.spec.ts
│   │   │   ├── generationState.ts
│   │   │   ├── getHref.ts
│   │   │   ├── getReturnFromGenerator.ts
│   │   │   ├── haptics.ts
│   │   │   ├── hashConv.ts
│   │   │   ├── hf.ts
│   │   │   ├── isDesktop.ts
│   │   │   ├── isUrl.ts
│   │   │   ├── isVirtualKeyboard.ts
│   │   │   ├── loadAttachmentsFromUrls.ts
│   │   │   ├── marked.spec.ts
│   │   │   ├── marked.ts
│   │   │   ├── mcpValidation.ts
│   │   │   ├── mergeAsyncGenerators.ts
│   │   │   ├── messageUpdates.spec.ts
│   │   │   ├── messageUpdates.ts
│   │   │   ├── mime.ts
│   │   │   ├── models.ts
│   │   │   ├── parseBlocks.ts
│   │   │   ├── parseIncompleteMarkdown.ts
│   │   │   ├── parseStringToList.ts
│   │   │   ├── randomUuid.ts
│   │   │   ├── searchTokens.ts
│   │   │   ├── sha256.ts
│   │   │   ├── stringifyError.ts
│   │   │   ├── sum.ts
│   │   │   ├── template.spec.ts
│   │   │   ├── template.ts
│   │   │   ├── timeout.ts
│   │   │   ├── toolProgress.spec.ts
│   │   │   ├── toolProgress.ts
│   │   │   ├── tree/
│   │   │   │   ├── addChildren.spec.ts
│   │   │   │   ├── addChildren.ts
│   │   │   │   ├── addSibling.spec.ts
│   │   │   │   ├── addSibling.ts
│   │   │   │   ├── buildSubtree.spec.ts
│   │   │   │   ├── buildSubtree.ts
│   │   │   │   ├── convertLegacyConversation.spec.ts
│   │   │   │   ├── convertLegacyConversation.ts
│   │   │   │   ├── isMessageId.spec.ts
│   │   │   │   ├── isMessageId.ts
│   │   │   │   ├── tree.d.ts
│   │   │   │   └── treeHelpers.spec.ts
│   │   │   ├── updates.ts
│   │   │   └── urlParams.ts
│   │   └── workers/
│   │       └── markdownWorker.ts
│   ├── routes/
│   │   ├── +error.svelte
│   │   ├── +layout.svelte
│   │   ├── +layout.ts
│   │   ├── +page.svelte
│   │   ├── .well-known/
│   │   │   └── oauth-cimd/
│   │   │       └── +server.ts
│   │   ├── __debug/
│   │   │   └── openai/
│   │   │       └── +server.ts
│   │   ├── admin/
│   │   │   ├── export/
│   │   │   │   └── +server.ts
│   │   │   └── stats/
│   │   │       └── compute/
│   │   │           └── +server.ts
│   │   ├── api/
│   │   │   ├── conversation/
│   │   │   │   └── [id]/
│   │   │   │       ├── +server.ts
│   │   │   │       └── message/
│   │   │   │           └── [messageId]/
│   │   │   │               └── +server.ts
│   │   │   ├── conversations/
│   │   │   │   └── +server.ts
│   │   │   ├── fetch-url/
│   │   │   │   └── +server.ts
│   │   │   ├── mcp/
│   │   │   │   ├── health/
│   │   │   │   │   └── +server.ts
│   │   │   │   └── servers/
│   │   │   │       └── +server.ts
│   │   │   ├── models/
│   │   │   │   └── +server.ts
│   │   │   ├── transcribe/
│   │   │   │   └── +server.ts
│   │   │   ├── user/
│   │   │   │   ├── +server.ts
│   │   │   │   └── validate-token/
│   │   │   │       └── +server.ts
│   │   │   └── v2/
│   │   │       ├── conversations/
│   │   │       │   ├── +server.ts
│   │   │       │   ├── [id]/
│   │   │       │   │   ├── +server.ts
│   │   │       │   │   └── message/
│   │   │       │   │       └── [messageId]/
│   │   │       │   │           └── +server.ts
│   │   │       │   └── import-share/
│   │   │       │       └── +server.ts
│   │   │       ├── debug/
│   │   │       │   ├── config/
│   │   │       │   │   └── +server.ts
│   │   │       │   └── refresh/
│   │   │       │       └── +server.ts
│   │   │       ├── export/
│   │   │       │   └── +server.ts
│   │   │       ├── feature-flags/
│   │   │       │   └── +server.ts
│   │   │       ├── models/
│   │   │       │   ├── +server.ts
│   │   │       │   ├── [namespace]/
│   │   │       │   │   ├── +server.ts
│   │   │       │   │   ├── [model]/
│   │   │       │   │   │   ├── +server.ts
│   │   │       │   │   │   └── subscribe/
│   │   │       │   │   │       └── +server.ts
│   │   │       │   │   └── subscribe/
│   │   │       │   │       └── +server.ts
│   │   │       │   ├── old/
│   │   │       │   │   └── +server.ts
│   │   │       │   └── refresh/
│   │   │       │       └── +server.ts
│   │   │       ├── public-config/
│   │   │       │   └── +server.ts
│   │   │       └── user/
│   │   │           ├── +server.ts
│   │   │           ├── billing-orgs/
│   │   │           │   └── +server.ts
│   │   │           ├── reports/
│   │   │           │   └── +server.ts
│   │   │           └── settings/
│   │   │               └── +server.ts
│   │   ├── conversation/
│   │   │   ├── +server.ts
│   │   │   └── [id]/
│   │   │       ├── +page.svelte
│   │   │       ├── +page.ts
│   │   │       ├── +server.ts
│   │   │       ├── message/
│   │   │       │   └── [messageId]/
│   │   │       │       └── prompt/
│   │   │       │           └── +server.ts
│   │   │       ├── output/
│   │   │       │   └── [sha256]/
│   │   │       │       └── +server.ts
│   │   │       ├── share/
│   │   │       │   └── +server.ts
│   │   │       └── stop-generating/
│   │   │           └── +server.ts
│   │   ├── healthcheck/
│   │   │   └── +server.ts
│   │   ├── login/
│   │   │   ├── +server.ts
│   │   │   └── callback/
│   │   │       ├── +server.ts
│   │   │       ├── updateUser.spec.ts
│   │   │       └── updateUser.ts
│   │   ├── logout/
│   │   │   └── +server.ts
│   │   ├── metrics/
│   │   │   └── +server.ts
│   │   ├── models/
│   │   │   ├── +page.svelte
│   │   │   └── [...model]/
│   │   │       ├── +page.svelte
│   │   │       └── +page.ts
│   │   ├── privacy/
│   │   │   └── +page.svelte
│   │   ├── r/
│   │   │   └── [id]/
│   │   │       └── +page.ts
│   │   └── settings/
│   │       ├── (nav)/
│   │       │   ├── +layout.svelte
│   │       │   ├── +layout.ts
│   │       │   ├── +page.svelte
│   │       │   ├── +server.ts
│   │       │   ├── [...model]/
│   │       │   │   ├── +page.svelte
│   │       │   │   └── +page.ts
│   │       │   └── application/
│   │       │       └── +page.svelte
│   │       └── +layout.svelte
│   └── styles/
│       ├── highlight-js.css
│       └── main.css
├── static/
│   ├── chatui/
│   │   └── manifest.json
│   ├── huggingchat/
│   │   ├── manifest.json
│   │   └── routes.chat.json
│   └── robots.txt
├── stub/
│   └── @reflink/
│       └── reflink/
│           ├── index.js
│           └── package.json
├── svelte.config.js
├── tailwind.config.cjs
├── tsconfig.json
└── vite.config.ts
Download .txt
SYMBOL INDEX (589 symbols across 187 files)

FILE: scripts/config.ts
  function clear (line 40) | async function clear() {
  function add (line 45) | async function add(key: string, value: string) {
  function remove (line 54) | async function remove(key: string) {

FILE: scripts/populate.ts
  function generateMessages (line 43) | async function generateMessages(preprompt?: string): Promise<Message[]> {
  function seed (line 121) | async function seed() {

FILE: scripts/updateLocalEnv.ts
  constant PUBLIC_CONFIG (line 10) | let PUBLIC_CONFIG = "";
  constant SECRET_CONFIG (line 29) | const SECRET_CONFIG =

FILE: src/app.d.ts
  type Locals (line 11) | interface Locals {
  type Error (line 20) | interface Error {

FILE: src/lib/APIClient.ts
  type FetchFn (line 21) | type FetchFn = typeof globalThis.fetch;
  type ApiResponse (line 23) | interface ApiResponse<T = unknown> {
  function apiCall (line 29) | async function apiCall<T = unknown>(
  function endpoint (line 71) | function endpoint(fetcher: FetchFn, baseUrl: string) {
  function useAPIClient (line 88) | function useAPIClient({
  function handleResponse (line 136) | function handleResponse(response: ApiResponse<any>): any {

FILE: src/lib/actions/clickOutside.ts
  function clickOutside (line 1) | function clickOutside(element: HTMLElement, callbackFunction: () => void) {

FILE: src/lib/actions/snapScrollToBottom.ts
  constant BOTTOM_THRESHOLD (line 5) | const BOTTOM_THRESHOLD = 50;
  constant USER_SCROLL_DEBOUNCE_MS (line 6) | const USER_SCROLL_DEBOUNCE_MS = 150;
  constant PROGRAMMATIC_SCROLL_GRACE_MS (line 7) | const PROGRAMMATIC_SCROLL_GRACE_MS = 100;
  constant TOUCH_DETACH_THRESHOLD_PX (line 8) | const TOUCH_DETACH_THRESHOLD_PX = 10;
  type ScrollDependency (line 10) | interface ScrollDependency {
  type MaybeScrollDependency (line 15) | type MaybeScrollDependency = ScrollDependency | unknown;
  function updateScroll (line 205) | async function updateScroll(newDependency?: MaybeScrollDependency) {

FILE: src/lib/buildPrompt.ts
  type buildPromptOptions (line 4) | type buildPromptOptions = Pick<EndpointParameters, "messages" | "preprom...
  function buildPrompt (line 8) | async function buildPrompt({

FILE: src/lib/constants/mime.ts
  constant TEXT_MIME_ALLOWLIST (line 4) | const TEXT_MIME_ALLOWLIST = [
  constant IMAGE_MIME_ALLOWLIST_DEFAULT (line 11) | const IMAGE_MIME_ALLOWLIST_DEFAULT = ["image/jpeg", "image/png"] as const;

FILE: src/lib/constants/pagination.ts
  constant CONV_NUM_PER_PAGE (line 1) | const CONV_NUM_PER_PAGE = 30;

FILE: src/lib/constants/publicSepToken.ts
  constant PUBLIC_SEP_TOKEN (line 1) | const PUBLIC_SEP_TOKEN = "</s>";

FILE: src/lib/constants/routerExamples.ts
  type RouterFollowUp (line 1) | type RouterFollowUp = {
  type RouterExampleAttachment (line 6) | type RouterExampleAttachment = {
  type RouterExample (line 10) | type RouterExample = {

FILE: src/lib/createShareLink.ts
  function createShareLink (line 6) | async function createShareLink(id: string): Promise<string> {

FILE: src/lib/jobs/refresh-conversation-stats.ts
  function getLastComputationTime (line 8) | async function getLastComputationTime(): Promise<Date> {
  function shouldComputeStats (line 13) | async function shouldComputeStats(): Promise<boolean> {
  function computeAllStats (line 19) | async function computeAllStats() {
  function computeStats (line 33) | async function computeStats(params: {
  function maintainLock (line 268) | async function maintainLock() {
  function refreshConversationStats (line 283) | function refreshConversationStats() {

FILE: src/lib/migrations/lock.ts
  function acquireLock (line 8) | async function acquireLock(key: Semaphores | string): Promise<ObjectId |...
  function releaseLock (line 27) | async function releaseLock(key: Semaphores | string, lockId: ObjectId) {
  function isDBLocked (line 34) | async function isDBLocked(key: Semaphores | string): Promise<boolean> {
  function refreshLock (line 41) | async function refreshLock(key: Semaphores | string, lockId: ObjectId): ...

FILE: src/lib/migrations/migrations.ts
  function checkAndRunMigrations (line 8) | async function checkAndRunMigrations() {

FILE: src/lib/migrations/routines/04-update-message-updates.ts
  type FinalAnswer (line 15) | type FinalAnswer = {
  type TextStreamUpdate (line 20) | type TextStreamUpdate = {
  type WebSearchUpdate (line 25) | type WebSearchUpdate = {
  type StatusUpdate (line 33) | type StatusUpdate = {
  type ErrorUpdate (line 39) | type ErrorUpdate = {
  type FileUpdate (line 45) | type FileUpdate = {
  type OldMessageUpdate (line 50) | type OldMessageUpdate =
  function convertMessageUpdate (line 59) | function convertMessageUpdate(message: Message, update: OldMessageUpdate...

FILE: src/lib/migrations/routines/06-trim-message-updates.ts
  function convertMessageUpdate (line 12) | function convertMessageUpdate(message: Message, update: unknown): Messag...

FILE: src/lib/migrations/routines/09-delete-empty-conversations.spec.ts
  type Message (line 9) | type Message = Conversation["messages"][number];

FILE: src/lib/migrations/routines/09-delete-empty-conversations.ts
  constant BATCH_SIZE (line 7) | const BATCH_SIZE = 1000;
  constant DELETE_THRESHOLD_MS (line 8) | const DELETE_THRESHOLD_MS = 60 * 60 * 1000;
  function deleteBatch (line 10) | async function deleteBatch(conversations: Collection<Conversation>, ids:...
  function processCursor (line 16) | async function processCursor<T>(
  function deleteConversations (line 36) | async function deleteConversations(

FILE: src/lib/migrations/routines/index.ts
  type Migration (line 5) | interface Migration {

FILE: src/lib/server/abortRegistry.ts
  class AbortRegistry (line 7) | class AbortRegistry {
    method getInstance (line 12) | public static getInstance(): AbortRegistry {
    method register (line 19) | public register(conversationId: string, controller: AbortController) {
    method abort (line 36) | public abort(conversationId: string) {
    method unregister (line 49) | public unregister(conversationId: string, controller: AbortController) {

FILE: src/lib/server/abortedGenerations.ts
  class AbortedGenerations (line 7) | class AbortedGenerations {
    method constructor (line 12) | private constructor() {
    method getInstance (line 20) | public static getInstance(): AbortedGenerations {
    method getAbortTime (line 28) | public getAbortTime(conversationId: string): Date | undefined {
    method updateList (line 32) | private async updateList() {

FILE: src/lib/server/adminToken.ts
  class AdminTokenManager (line 6) | class AdminTokenManager {
    method enabled (line 11) | public get enabled() {
    method isAdmin (line 15) | public isAdmin(sessionId: Session["sessionId"]) {
    method checkToken (line 20) | public checkToken(token: string, sessionId: Session["sessionId"]) {
    method removeSession (line 32) | public removeSession(sessionId: Session["sessionId"]) {
    method displayToken (line 36) | public displayToken() {

FILE: src/lib/server/api/__tests__/conversations-id.spec.ts
  function parseResponse (line 14) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function mockUrl (line 18) | function mockUrl(): URL {

FILE: src/lib/server/api/__tests__/conversations-message.spec.ts
  function parseResponse (line 16) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function buildMessageTree (line 29) | function buildMessageTree(): {

FILE: src/lib/server/api/__tests__/conversations.spec.ts
  function parseResponse (line 14) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function mockUrl (line 18) | function mockUrl(params?: Record<string, string>): URL {

FILE: src/lib/server/api/__tests__/misc.spec.ts
  function parseResponse (line 8) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function mockRequestEvent (line 12) | function mockRequestEvent(locals: App.Locals) {

FILE: src/lib/server/api/__tests__/testHelpers.ts
  function createTestLocals (line 7) | function createTestLocals(overrides?: Partial<App.Locals>): App.Locals {
  function createTestUser (line 17) | async function createTestUser(): Promise<{
  function createTestConversation (line 59) | async function createTestConversation(
  function cleanupTestData (line 78) | async function cleanupTestData() {

FILE: src/lib/server/api/__tests__/user-reports.spec.ts
  function parseResponse (line 9) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function mockRequestEvent (line 13) | function mockRequestEvent(locals: App.Locals) {

FILE: src/lib/server/api/__tests__/user.spec.ts
  function parseResponse (line 11) | async function parseResponse<T = unknown>(res: Response): Promise<T> {
  function mockRequestEvent (line 15) | function mockRequestEvent(locals: App.Locals, overrides?: Record<string,...

FILE: src/lib/server/api/types.ts
  type GETModelsResponse (line 3) | type GETModelsResponse = Array<{
  type GETOldModelsResponse (line 25) | type GETOldModelsResponse = Array<{
  type FeatureFlags (line 32) | interface FeatureFlags {

FILE: src/lib/server/api/utils/requireAuth.ts
  function requireAuth (line 6) | function requireAuth(locals: App.Locals): void {
  function requireAdmin (line 15) | function requireAdmin(locals: App.Locals): void {

FILE: src/lib/server/api/utils/resolveConversation.ts
  function resolveConversation (line 14) | async function resolveConversation(

FILE: src/lib/server/api/utils/resolveModel.ts
  function resolveModel (line 7) | async function resolveModel(namespace: string, model?: string) {

FILE: src/lib/server/api/utils/superjsonResponse.ts
  function superjsonResponse (line 7) | function superjsonResponse(data: unknown, init?: ResponseInit): Response {

FILE: src/lib/server/apiToken.ts
  function getApiToken (line 3) | function getApiToken(locals: App.Locals | undefined) {

FILE: src/lib/server/auth.ts
  type OIDCSettings (line 27) | interface OIDCSettings {
  type OIDCUserInfo (line 31) | interface OIDCUserInfo {
  function sanitizeReturnPath (line 70) | function sanitizeReturnPath(path: string | undefined | null): string | u...
  function refreshSessionCookie (line 83) | function refreshSessionCookie(cookies: Cookies, sessionId: string) {
  function findUser (line 94) | async function findUser(
  function tokenSetToSessionOauth (line 201) | function tokenSetToSessionOauth(tokenSet: TokenSet): Session["oauth"] {
  function generateCsrfToken (line 220) | async function generateCsrfToken(
  function getOIDCClient (line 246) | async function getOIDCClient(settings: OIDCSettings, url: URL): Promise<...
  function getOIDCAuthorizationUrl (line 288) | async function getOIDCAuthorizationUrl(
  function getOIDCUserData (line 319) | async function getOIDCUserData(
  function refreshOAuthToken (line 343) | async function refreshOAuthToken(
  function validateAndParseCsrfToken (line 353) | async function validateAndParseCsrfToken(
  type CookieRecord (line 385) | type CookieRecord = Cookies;
  type HeaderRecord (line 386) | type HeaderRecord = Headers;
  function getCoupledCookieHash (line 388) | async function getCoupledCookieHash(cookie: CookieRecord): Promise<strin...
  function authenticateRequest (line 402) | async function authenticateRequest(
  function triggerOauthFlow (line 524) | async function triggerOauthFlow({ url, locals, cookies }: RequestEvent):...

FILE: src/lib/server/config.ts
  type PublicConfigKey (line 9) | type PublicConfigKey = keyof typeof publicEnv;
  type ConfigKey (line 11) | type ConfigKey = keyof typeof keysFromEnv;
  class ConfigManager (line 13) | class ConfigManager {
    method init (line 21) | async init() {
    method ConfigManagerEnabled (line 40) | get ConfigManagerEnabled() {
    method isHuggingChat (line 44) | get isHuggingChat() {
    method checkForUpdates (line 48) | async checkForUpdates() {
    method isConfigStale (line 54) | async isConfigStale(): Promise<boolean> {
    method updateConfig (line 65) | async updateConfig() {
    method get (line 78) | get(key: ConfigKey): string {
    method updateSemaphore (line 85) | async updateSemaphore() {
    method set (line 100) | async set(key: ConfigKey, value: string) {
    method delete (line 107) | async delete(key: ConfigKey) {
    method clear (line 114) | async clear() {
    method getPublicConfig (line 121) | getPublicConfig() {
  type ExtraConfigKeys (line 154) | type ExtraConfigKeys =
  type ConfigProxy (line 165) | type ConfigProxy = ConfigManager & { [K in ConfigKey | ExtraConfigKeys]:...
  method get (line 168) | get(target, prop, receiver) {
  method set (line 177) | set(target, prop, value, receiver) {

FILE: src/lib/server/conversation.ts
  function createConversationFromShare (line 12) | async function createConversationFromShare(

FILE: src/lib/server/database.ts
  constant CONVERSATION_STATS_COLLECTION (line 27) | const CONVERSATION_STATS_COLLECTION = "conversations.stats";
  class Database (line 29) | class Database {
    method init (line 35) | private async init() {
    method getInstance (line 87) | public static async getInstance(): Promise<Database> {
    method getClient (line 99) | public getClient(): MongoClient {
    method getCollections (line 110) | public getCollections() {
    method initDatabase (line 176) | private initDatabase() {
  function getCollectionsEarly (line 396) | async function getCollectionsEarly(): Promise<

FILE: src/lib/server/endpoints/document.ts
  type FileProcessorOptions (line 4) | interface FileProcessorOptions<TMimeType extends string = string> {
  type AsyncDocumentProcessor (line 31) | type AsyncDocumentProcessor<TMimeType extends string = string> = (
  function makeDocumentProcessor (line 38) | function makeDocumentProcessor<TMimeType extends string = string>(

FILE: src/lib/server/endpoints/endpoints.ts
  type EndpointMessage (line 13) | type EndpointMessage = Omit<Message, "id">;
  type EndpointParameters (line 16) | interface EndpointParameters {
  type TextGenerationStreamOutputSimplified (line 28) | type TextGenerationStreamOutputSimplified = TextGenerationStreamOutput & {
  type Endpoint (line 33) | type Endpoint = (

FILE: src/lib/server/endpoints/images.ts
  type ImageProcessorOptions (line 6) | interface ImageProcessorOptions<TMimeType extends string = string> {
  type ImageProcessor (line 13) | type ImageProcessor<TMimeType extends string = string> = (file: MessageF...
  function createImageProcessorOptionsValidator (line 18) | function createImageProcessorOptionsValidator<TMimeType extends string =...
  function makeImageProcessor (line 41) | function makeImageProcessor<TMimeType extends string = string>(
  type OutputImgFormat (line 92) | type OutputImgFormat = (typeof outputFormats)[number];
  function convertImage (line 96) | function convertImage(sharpInst: Sharp, outputMime: string): Sharp {
  function chooseMimeType (line 126) | function chooseMimeType<T extends readonly string[]>(
  type ImageSizeOptions (line 150) | interface ImageSizeOptions {
  function chooseImageSize (line 160) | function chooseImageSize({
  function estimateImageSizeInBytes (line 198) | function estimateImageSizeInBytes(mime: string, width: number, height: n...
  function resizeImage (line 209) | function resizeImage(sharpInst: Sharp, maxWidth: number, maxHeight: numb...

FILE: src/lib/server/endpoints/openai/endpointOai.ts
  function endpointOai (line 53) | async function endpointOai(

FILE: src/lib/server/endpoints/preprocessMessages.ts
  function preprocessMessages (line 6) | async function preprocessMessages(
  function downloadFiles (line 16) | async function downloadFiles(messages: Message[], convId: ObjectId): Pro...
  function injectClipboardFiles (line 26) | async function injectClipboardFiles(messages: EndpointMessage[]) {
  function stripEmptyInitialSystemMessage (line 48) | function stripEmptyInitialSystemMessage(messages: EndpointMessage[]): En...

FILE: src/lib/server/exitHandler.ts
  type ExitHandler (line 5) | type ExitHandler = () => void | Promise<void>;
  type ExitHandlerUnsubscribe (line 6) | type ExitHandlerUnsubscribe = () => void;
  function onExit (line 10) | function onExit(cb: ExitHandler): ExitHandlerUnsubscribe {
  function runExitHandler (line 18) | async function runExitHandler(handler: ExitHandler): Promise<void> {
  function initExitHandler (line 24) | function initExitHandler() {

FILE: src/lib/server/files/downloadFile.ts
  function downloadFile (line 7) | async function downloadFile(

FILE: src/lib/server/files/uploadFile.ts
  function uploadFile (line 7) | async function uploadFile(file: File, conv: Conversation): Promise<Messa...

FILE: src/lib/server/findRepoRoot.ts
  function findRepoRoot (line 4) | function findRepoRoot(startPath: string): string {

FILE: src/lib/server/hooks/error.ts
  type HandleServerErrorInput (line 4) | type HandleServerErrorInput = Parameters<HandleServerError>[0];
  function handleServerError (line 6) | async function handleServerError({

FILE: src/lib/server/hooks/fetch.ts
  type HandleFetchInput (line 4) | type HandleFetchInput = Parameters<HandleFetch>[0];
  function handleFetchRequest (line 6) | async function handleFetchRequest({

FILE: src/lib/server/hooks/handle.ts
  type HandleInput (line 19) | type HandleInput = Parameters<Handle>[0];
  function getClientAddressSafe (line 21) | function getClientAddressSafe(event: RequestEvent): string | undefined {
  function handleRequest (line 29) | async function handleRequest({ event, resolve }: HandleInput): Promise<R...

FILE: src/lib/server/hooks/init.ts
  function initServer (line 11) | async function initServer(): Promise<void> {

FILE: src/lib/server/isURLLocal.ts
  function assertValidHostname (line 14) | function assertValidHostname(hostname: string): void {
  function isURLLocal (line 36) | async function isURLLocal(URL: URL): Promise<boolean> {
  function isURLStringLocal (line 57) | function isURLStringLocal(url: string) {
  function isHostLocalhost (line 67) | function isHostLocalhost(host: string): boolean {

FILE: src/lib/server/logger.ts
  method mixin (line 28) | mixin() {

FILE: src/lib/server/mcp/clientPool.ts
  function keyOf (line 8) | function keyOf(server: McpServerConfig) {
  function getClient (line 16) | async function getClient(server: McpServerConfig, signal?: AbortSignal):...
  function drainPool (line 54) | async function drainPool() {
  function evictFromPool (line 63) | function evictFromPool(server: McpServerConfig): Client | undefined {

FILE: src/lib/server/mcp/httpClient.ts
  function isConnectionClosedError (line 5) | function isConnectionClosedError(err: unknown): boolean {
  type McpServerConfig (line 10) | interface McpServerConfig {
  constant DEFAULT_TIMEOUT_MS (line 16) | const DEFAULT_TIMEOUT_MS = 120_000;
  function getMcpToolTimeoutMs (line 18) | function getMcpToolTimeoutMs(): number {
  type McpToolTextResponse (line 29) | type McpToolTextResponse = {
  type McpToolProgress (line 37) | type McpToolProgress = {
  function callMcpTool (line 43) | async function callMcpTool(

FILE: src/lib/server/mcp/registry.ts
  function parseServers (line 9) | function parseServers(raw: string): McpServerConfig[] {
  function setServers (line 42) | function setServers(raw: string) {
  function loadMcpServersOnStartup (line 53) | function loadMcpServersOnStartup(): McpServerConfig[] {
  function refreshMcpServersIfChanged (line 59) | function refreshMcpServersIfChanged(): void {
  function getMcpServers (line 71) | function getMcpServers(): McpServerConfig[] {

FILE: src/lib/server/mcp/tools.ts
  type OpenAiTool (line 8) | type OpenAiTool = {
  type McpToolMapping (line 13) | interface McpToolMapping {
  type CacheEntry (line 19) | interface CacheEntry {
  constant DEFAULT_TTL_MS (line 26) | const DEFAULT_TTL_MS = 60_000;
  function sanitizeName (line 33) | function sanitizeName(name: string) {
  function buildCacheKey (line 37) | function buildCacheKey(servers: McpServerConfig[]): string {
  type ListedTool (line 57) | type ListedTool = {
  function listServerTools (line 64) | async function listServerTools(
  function getOpenAiToolsForMcp (line 106) | async function getOpenAiToolsForMcp(
  function resetMcpToolsCache (line 194) | function resetMcpToolsCache() {

FILE: src/lib/server/metrics.ts
  type ModelLabel (line 7) | type ModelLabel = "model";
  type ToolLabel (line 8) | type ToolLabel = "tool";
  type Metrics (line 10) | interface Metrics {
  class MetricsServer (line 36) | class MetricsServer {
    method constructor (line 43) | private constructor() {
    method getInstance (line 58) | public static getInstance(): MetricsServer {
    method getMetrics (line 65) | public static getMetrics(): Metrics {
    method isEnabled (line 69) | public static isEnabled(): boolean {
    method render (line 73) | public async render(): Promise<string> {
    method createMetrics (line 81) | private createMetrics(): Metrics {
    method startStandaloneServer (line 210) | private startStandaloneServer() {

FILE: src/lib/server/models.ts
  type Optional (line 10) | type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
  type ModelConfig (line 67) | type ModelConfig = z.infer<typeof modelConfig>;
  type ModelOverride (line 79) | type ModelOverride = z.infer<typeof overrideEntrySchema>;
  function getChatPromptRender (line 106) | function getChatPromptRender(_m: ModelConfig): (inputs: ChatTemplateInpu...
  type InternalProcessedModel (line 146) | type InternalProcessedModel = Awaited<ReturnType<typeof addEndpoint>> & {
  type ModelsRefreshSummary (line 168) | type ModelsRefreshSummary = {
  type ProcessedModel (line 177) | type ProcessedModel = InternalProcessedModel;
  type BackendModel (line 495) | type BackendModel = Optional<

FILE: src/lib/server/requestContext.ts
  type RequestContext (line 4) | interface RequestContext {
  function runWithRequestContext (line 18) | function runWithRequestContext<T>(
  function updateRequestContext (line 36) | function updateRequestContext(updates: Partial<Omit<RequestContext, "req...
  function getRequestContext (line 46) | function getRequestContext(): RequestContext | undefined {
  function getRequestId (line 53) | function getRequestId(): string | undefined {

FILE: src/lib/server/router/arch.ts
  constant DEFAULT_LAST_TURNS (line 8) | const DEFAULT_LAST_TURNS = 16;
  function trimMiddle (line 17) | function trimMiddle(content: string, maxLength: number): string {
  constant PROMPT_TEMPLATE (line 44) | const PROMPT_TEMPLATE = `
  function lastNTurns (line 71) | function lastNTurns<T>(arr: T[], n = DEFAULT_LAST_TURNS) {
  function toRouterPrompt (line 76) | function toRouterPrompt(messages: EndpointMessage[], routes: Route[]) {
  function parseRouteName (line 121) | function parseRouteName(text: string): string | undefined {
  function archSelectRoute (line 136) | async function archSelectRoute(

FILE: src/lib/server/router/endpoint.ts
  constant REASONING_BLOCK_REGEX (line 23) | const REASONING_BLOCK_REGEX = /<think>[\s\S]*?(?:<\/think>|$)/g;
  constant ROUTER_MULTIMODAL_ROUTE (line 25) | const ROUTER_MULTIMODAL_ROUTE = "multimodal";
  function getModels (line 30) | async function getModels(): Promise<ProcessedModel[]> {
  class HTTPError (line 41) | class HTTPError extends Error {
    method constructor (line 42) | constructor(
  function extractUpstreamError (line 54) | function extractUpstreamError(error: unknown): { message: string; status...
  function isPolicyError (line 95) | function isPolicyError(statusCode?: number): boolean {
  function stripReasoningBlocks (line 101) | function stripReasoningBlocks(text: string): string {
  function stripReasoningFromMessage (line 106) | function stripReasoningFromMessage(message: EndpointMessage): EndpointMe...
  function makeRouterEndpoint (line 119) | async function makeRouterEndpoint(routerModel: ProcessedModel): Promise<...

FILE: src/lib/server/router/multimodal.ts
  function findConfiguredMultimodalModel (line 9) | function findConfiguredMultimodalModel(
  function getConfiguredMultimodalModelId (line 23) | function getConfiguredMultimodalModelId(

FILE: src/lib/server/router/policy.ts
  constant ROUTES (line 5) | let ROUTES: Route[] = [];
  function loadPolicy (line 8) | async function loadPolicy(): Promise<Route[]> {
  function getRoutes (line 30) | async function getRoutes(): Promise<Route[]> {
  function resolveRouteModels (line 35) | function resolveRouteModels(

FILE: src/lib/server/router/toolsRoute.ts
  constant ROUTER_TOOLS_ROUTE (line 5) | const ROUTER_TOOLS_ROUTE = "agentic";
  type LocalsWithMcp (line 7) | type LocalsWithMcp = App.Locals & {
  function isRouterToolsBypassEnabled (line 14) | function isRouterToolsBypassEnabled(): boolean {
  function hasActiveToolsSelection (line 18) | function hasActiveToolsSelection(locals: App.Locals | undefined): boolean {
  function pickToolsCapableModel (line 31) | function pickToolsCapableModel(

FILE: src/lib/server/router/types.ts
  type Route (line 1) | interface Route {
  type RouteConfig (line 8) | interface RouteConfig {
  type RouteSelection (line 13) | interface RouteSelection {
  constant ROUTER_FAILURE (line 21) | const ROUTER_FAILURE = "arch_router_failure";

FILE: src/lib/server/sendSlack.ts
  function sendSlack (line 4) | async function sendSlack(text: string) {

FILE: src/lib/server/textGeneration/generate.ts
  type GenerateContext (line 14) | type GenerateContext = Omit<TextGenerationContext, "messages"> & { messa...

FILE: src/lib/server/textGeneration/mcp/fileRefs.ts
  type FileRefPayload (line 3) | type FileRefPayload = {
  type RefKind (line 9) | type RefKind = {
  type ResolvedFileRef (line 15) | type ResolvedFileRef = FileRefPayload & { refKind: RefKind };
  type FileRefResolver (line 16) | type FileRefResolver = (ref: string) => ResolvedFileRef | undefined;
  constant IMAGE_REF_KIND (line 18) | const IMAGE_REF_KIND: RefKind = {
  constant DEFAULT_REF_KINDS (line 24) | const DEFAULT_REF_KINDS: RefKind[] = [IMAGE_REF_KIND];
  function buildFileRefResolver (line 33) | function buildFileRefResolver(
  function buildImageRefResolver (line 75) | function buildImageRefResolver(messages: EndpointMessage[]): FileRefReso...
  type FieldRule (line 79) | type FieldRule = {
  constant DEFAULT_FIELD_RULES (line 86) | const DEFAULT_FIELD_RULES: FieldRule[] = [
  function attachFileRefsToArgs (line 104) | function attachFileRefsToArgs(

FILE: src/lib/server/textGeneration/mcp/routerResolution.ts
  type RouterResolutionInput (line 16) | interface RouterResolutionInput {
  type RouterResolutionResult (line 24) | interface RouterResolutionResult {
  function resolveRouterTarget (line 31) | async function resolveRouterTarget({

FILE: src/lib/server/textGeneration/mcp/runMcpFlow.ts
  type RunMcpFlowContext (line 32) | type RunMcpFlowContext = Pick<
  type McpFlowResult (line 38) | type McpFlowResult = "completed" | "not_applicable" | "aborted";

FILE: src/lib/server/textGeneration/mcp/toolInvocation.ts
  type Primitive (line 18) | type Primitive = string | number | boolean;
  type ToolRun (line 20) | type ToolRun = {
  type NormalizedToolCall (line 26) | interface NormalizedToolCall {
  type ExecuteToolCallsParams (line 32) | interface ExecuteToolCallsParams {
  type ToolCallExecutionResult (line 47) | interface ToolCallExecutionResult {
  type ToolExecutionEvent (line 53) | type ToolExecutionEvent =
  type TaskResult (line 83) | type TaskResult = {
  function createQueue (line 148) | function createQueue<T>() {

FILE: src/lib/server/textGeneration/reasoning.ts
  function generateSummaryOfReasoning (line 4) | async function generateSummaryOfReasoning(

FILE: src/lib/server/textGeneration/title.ts
  function generateTitle (line 30) | async function generateTitle(

FILE: src/lib/server/textGeneration/types.ts
  type TextGenerationContext (line 7) | interface TextGenerationContext {

FILE: src/lib/server/textGeneration/utils/prepareFiles.ts
  function prepareMessagesWithFiles (line 13) | async function prepareMessagesWithFiles(
  function prepareFiles (line 44) | async function prepareFiles(

FILE: src/lib/server/textGeneration/utils/routing.ts
  constant ROUTER_REASONING_REGEX (line 3) | const ROUTER_REASONING_REGEX = /<think>[\s\S]*?(?:<\/think>|$)/g;
  function stripReasoningBlocks (line 5) | function stripReasoningBlocks(text: string): string {
  function stripReasoningFromMessageForRouting (line 10) | function stripReasoningFromMessageForRouting(message: EndpointMessage): ...

FILE: src/lib/server/textGeneration/utils/toolPrompt.ts
  function buildToolPreprompt (line 3) | function buildToolPreprompt(tools: OpenAiTool[]): string {

FILE: src/lib/server/urlSafety.ts
  constant UNSAFE_IPV4_SUBNETS (line 4) | const UNSAFE_IPV4_SUBNETS = [
  function isUnsafeIp (line 13) | function isUnsafeIp(address: string): boolean {
  function isValidUrl (line 37) | function isValidUrl(urlString: string): boolean {
  function assertSafeIp (line 63) | function assertSafeIp(address: string, hostname: string): void {

FILE: src/lib/stores/backgroundGenerations.svelte.ts
  type BackgroundGeneration (line 1) | type BackgroundGeneration = {
  function addBackgroundGeneration (line 8) | function addBackgroundGeneration(entry: BackgroundGeneration) {
  function removeBackgroundGeneration (line 19) | function removeBackgroundGeneration(id: string) {
  function clearBackgroundGenerations (line 26) | function clearBackgroundGenerations() {
  function hasBackgroundGeneration (line 30) | function hasBackgroundGeneration(id: string) {

FILE: src/lib/stores/errors.ts
  constant ERROR_MESSAGES (line 3) | const ERROR_MESSAGES = {

FILE: src/lib/stores/mcpServers.ts
  function toKeyPart (line 14) | function toKeyPart(s: string | undefined): string {
  constant KEY_PREFIX (line 21) | const KEY_PREFIX = appLabel || baseLabel || "app";
  constant STORAGE_KEYS (line 23) | const STORAGE_KEYS = {
  function loadCustomServers (line 32) | function loadCustomServers(): MCPServer[] {
  function loadSelectedIds (line 45) | function loadSelectedIds(): Set<string> {
  function saveCustomServers (line 59) | function saveCustomServers(servers: MCPServer[]) {
  function saveSelectedIds (line 70) | function saveSelectedIds(ids: Set<string>) {
  function loadDisabledBaseIds (line 81) | function loadDisabledBaseIds(): Set<string> {
  function saveDisabledBaseIds (line 94) | function saveDisabledBaseIds(ids: Set<string>) {
  function refreshMcpServers (line 143) | async function refreshMcpServers() {
  function toggleServer (line 194) | function toggleServer(id: string) {
  function disableAllServers (line 221) | function disableAllServers() {
  function addCustomServer (line 236) | function addCustomServer(server: Omit<MCPServer, "id" | "type" | "status...
  function updateCustomServer (line 257) | function updateCustomServer(id: string, updates: Partial<MCPServer>) {
  function deleteCustomServer (line 271) | function deleteCustomServer(id: string) {
  function updateServerStatus (line 289) | function updateServerStatus(
  function healthCheckServer (line 314) | async function healthCheckServer(

FILE: src/lib/stores/settings.ts
  type SettingsStore (line 9) | type SettingsStore = {
  type SettingsStoreWritable (line 26) | type SettingsStoreWritable = Writable<SettingsStore> & {
  function useSettingsStore (line 35) | function useSettingsStore() {
  function createSettingsStore (line 39) | function createSettingsStore(initialValue: Omit<SettingsStore, "recently...

FILE: src/lib/stores/shareModal.ts
  function createShareModalStore (line 3) | function createShareModalStore() {

FILE: src/lib/stores/titleUpdate.ts
  type TitleUpdate (line 3) | interface TitleUpdate {

FILE: src/lib/switchTheme.ts
  type ThemePreference (line 1) | type ThemePreference = "light" | "dark" | "system";
  type ThemeState (line 3) | type ThemeState = {
  type ThemeSubscriber (line 8) | type ThemeSubscriber = (state: ThemeState) => void;
  function notify (line 13) | function notify(preference: ThemePreference, isDark: boolean) {
  function subscribeToTheme (line 19) | function subscribeToTheme(subscriber: ThemeSubscriber) {
  function setMetaThemeColor (line 35) | function setMetaThemeColor(isDark: boolean) {
  function applyDarkClass (line 41) | function applyDarkClass(isDark: boolean) {
  function getThemePreference (line 49) | function getThemePreference(): ThemePreference {
  function setTheme (line 65) | function setTheme(preference: ThemePreference) {
  function switchTheme (line 119) | function switchTheme() {

FILE: src/lib/types/AbortedGeneration.ts
  type AbortedGeneration (line 6) | interface AbortedGeneration extends Timestamps {

FILE: src/lib/types/Assistant.ts
  type Assistant (line 6) | interface Assistant extends Timestamps {

FILE: src/lib/types/AssistantStats.ts
  type AssistantStats (line 4) | interface AssistantStats extends Timestamps {

FILE: src/lib/types/ConfigKey.ts
  type ConfigKey (line 1) | interface ConfigKey {

FILE: src/lib/types/ConvSidebar.ts
  type ConvSidebar (line 3) | interface ConvSidebar {

FILE: src/lib/types/Conversation.ts
  type Conversation (line 7) | interface Conversation extends Timestamps {

FILE: src/lib/types/ConversationStats.ts
  type ConversationStats (line 3) | interface ConversationStats extends Timestamps {

FILE: src/lib/types/Message.ts
  type Message (line 6) | type Message = Partial<Timestamps> & {
  type MessageFile (line 36) | type MessageFile = {

FILE: src/lib/types/MessageEvent.ts
  type MessageEvent (line 5) | interface MessageEvent extends Pick<Timestamps, "createdAt"> {

FILE: src/lib/types/MessageUpdate.ts
  type MessageUpdate (line 4) | type MessageUpdate =
  type MessageUpdateType (line 14) | enum MessageUpdateType {
  type MessageUpdateStatus (line 26) | enum MessageUpdateStatus {
  type MessageStatusUpdate (line 32) | interface MessageStatusUpdate {
  type MessageTitleUpdate (line 40) | interface MessageTitleUpdate {
  type MessageStreamUpdate (line 44) | interface MessageStreamUpdate {
  type MessageToolUpdateType (line 52) | enum MessageToolUpdateType {
  type MessageToolUpdateBase (line 60) | interface MessageToolUpdateBase<TSubtype extends MessageToolUpdateType> {
  type MessageToolCallUpdate (line 66) | interface MessageToolCallUpdate extends MessageToolUpdateBase<MessageToo...
  type MessageToolResultUpdate (line 70) | interface MessageToolResultUpdate
  type MessageToolErrorUpdate (line 75) | interface MessageToolErrorUpdate extends MessageToolUpdateBase<MessageTo...
  type MessageToolEtaUpdate (line 79) | interface MessageToolEtaUpdate extends MessageToolUpdateBase<MessageTool...
  type MessageToolProgressUpdate (line 83) | interface MessageToolProgressUpdate
  type MessageToolUpdate (line 90) | type MessageToolUpdate =
  type MessageReasoningUpdateType (line 97) | enum MessageReasoningUpdateType {
  type MessageReasoningUpdate (line 102) | type MessageReasoningUpdate = MessageReasoningStreamUpdate | MessageReas...
  type MessageReasoningStreamUpdate (line 104) | interface MessageReasoningStreamUpdate {
  type MessageReasoningStatusUpdate (line 109) | interface MessageReasoningStatusUpdate {
  type MessageFileUpdate (line 115) | interface MessageFileUpdate {
  type MessageFinalAnswerUpdate (line 121) | interface MessageFinalAnswerUpdate {
  type MessageRouterMetadataUpdate (line 126) | interface MessageRouterMetadataUpdate {

FILE: src/lib/types/MigrationResult.ts
  type MigrationResult (line 3) | interface MigrationResult {

FILE: src/lib/types/Model.ts
  type Model (line 3) | type Model = Pick<

FILE: src/lib/types/Report.ts
  type Report (line 6) | interface Report extends Timestamps {

FILE: src/lib/types/Review.ts
  type ReviewStatus (line 1) | enum ReviewStatus {

FILE: src/lib/types/Semaphore.ts
  type Semaphore (line 3) | interface Semaphore extends Timestamps {
  type Semaphores (line 8) | enum Semaphores {

FILE: src/lib/types/Session.ts
  type Session (line 5) | interface Session extends Timestamps {

FILE: src/lib/types/Settings.ts
  type StreamingMode (line 5) | type StreamingMode = "raw" | "smooth";
  type Settings (line 7) | interface Settings extends Timestamps {
  type SettingsEditable (line 66) | type SettingsEditable = Omit<Settings, "welcomeModalSeenAt" | "createdAt...
  constant DEFAULT_SETTINGS (line 68) | const DEFAULT_SETTINGS = {

FILE: src/lib/types/SharedConversation.ts
  type SharedConversation (line 3) | type SharedConversation = Pick<

FILE: src/lib/types/Template.ts
  type ChatTemplateInput (line 3) | type ChatTemplateInput = {

FILE: src/lib/types/Timestamps.ts
  type Timestamps (line 1) | interface Timestamps {

FILE: src/lib/types/TokenCache.ts
  type TokenCache (line 3) | interface TokenCache extends Timestamps {

FILE: src/lib/types/Tool.ts
  type ToolResultStatus (line 1) | enum ToolResultStatus {
  type ToolCall (line 6) | interface ToolCall {
  type ToolResultSuccess (line 12) | interface ToolResultSuccess {
  type ToolResultError (line 19) | interface ToolResultError {
  type ToolResult (line 26) | type ToolResult = ToolResultSuccess | ToolResultError;
  type ToolFront (line 28) | interface ToolFront {
  type KeyValuePair (line 43) | interface KeyValuePair {
  type ServerStatus (line 48) | type ServerStatus = "connected" | "connecting" | "disconnected" | "error";
  type MCPTool (line 50) | interface MCPTool {
  type MCPServer (line 56) | interface MCPServer {
  type MCPServerApi (line 71) | interface MCPServerApi {

FILE: src/lib/types/UrlDependency.ts
  type UrlDependency (line 2) | enum UrlDependency {

FILE: src/lib/types/User.ts
  type User (line 4) | interface User extends Timestamps {

FILE: src/lib/utils/PublicConfig.svelte.ts
  type PublicConfigKey (line 8) | type PublicConfigKey = keyof typeof publicEnv;
  class PublicConfigManager (line 10) | class PublicConfigManager {
    method constructor (line 13) | constructor(initialConfig?: Record<PublicConfigKey, string>) {
    method init (line 21) | init(publicConfig: Record<PublicConfigKey, string>) {
    method get (line 25) | get(key: PublicConfigKey) {
    method getPublicConfig (line 29) | getPublicConfig() {
    method isHuggingChat (line 33) | get isHuggingChat() {
    method assetPath (line 37) | get assetPath() {
  type ConfigProxy (line 46) | type ConfigProxy = PublicConfigManager & { [K in PublicConfigKey]: strin...
  function getConfigManager (line 48) | function getConfigManager(initialConfig?: Record<PublicConfigKey, string...

FILE: src/lib/utils/auth.ts
  function requireAuthUser (line 9) | function requireAuthUser(): boolean {

FILE: src/lib/utils/chunk.ts
  function chunk (line 6) | function chunk<T extends unknown[] | string>(arr: T, chunkSize: number):...
  function range (line 25) | function range(n: number, b?: number): number[] {

FILE: src/lib/utils/cookiesAreEnabled.ts
  function cookiesAreEnabled (line 3) | function cookiesAreEnabled(): boolean {

FILE: src/lib/utils/debounce.ts
  function debounce (line 5) | function debounce<T extends unknown[]>(

FILE: src/lib/utils/deepestChild.ts
  function deepestChild (line 1) | function deepestChild(el: HTMLElement): HTMLElement {

FILE: src/lib/utils/favicon.ts
  function getMcpServerFaviconUrl (line 7) | function getMcpServerFaviconUrl(serverUrl: string, size: number = 64): s...

FILE: src/lib/utils/fetchJSON.ts
  function fetchJSON (line 1) | async function fetchJSON<T>(

FILE: src/lib/utils/formatUserCount.ts
  function formatUserCount (line 1) | function formatUserCount(userCount: number): string {

FILE: src/lib/utils/generationState.spec.ts
  function assistantMessage (line 7) | function assistantMessage(overrides: Partial<Message> = {}): Message {

FILE: src/lib/utils/generationState.ts
  function isAssistantGenerationTerminal (line 4) | function isAssistantGenerationTerminal(message?: Message): boolean {
  function isConversationGenerationActive (line 21) | function isConversationGenerationActive(messages: Message[]): boolean {

FILE: src/lib/utils/getHref.ts
  function getHref (line 1) | function getHref(

FILE: src/lib/utils/getReturnFromGenerator.ts
  function getReturnFromGenerator (line 1) | async function getReturnFromGenerator<T, R>(generator: AsyncGenerator<T,...

FILE: src/lib/utils/haptics.ts
  function getInstance (line 11) | async function getInstance(): Promise<WebHaptics | null> {
  function setHapticsEnabled (line 25) | function setHapticsEnabled(value: boolean) {
  function supportsHaptics (line 30) | function supportsHaptics(): boolean {
  function fire (line 37) | function fire(pattern: string): void {
  function tap (line 47) | function tap() {
  function confirm (line 52) | function confirm() {
  function error (line 57) | function error() {
  function selection (line 62) | function selection() {
  function streamStart (line 67) | function streamStart(): void {

FILE: src/lib/utils/hashConv.ts
  function hashConv (line 4) | async function hashConv(conv: Conversation) {

FILE: src/lib/utils/hf.ts
  function isStrictHfMcpLogin (line 3) | function isStrictHfMcpLogin(urlString: string): boolean {

FILE: src/lib/utils/isDesktop.ts
  constant TABLET_VIEWPORT_WIDTH (line 2) | const TABLET_VIEWPORT_WIDTH = 768;
  function isDesktop (line 4) | function isDesktop(window: Window) {

FILE: src/lib/utils/isUrl.ts
  function isURL (line 1) | function isURL(url: string) {

FILE: src/lib/utils/isVirtualKeyboard.ts
  function isVirtualKeyboard (line 3) | function isVirtualKeyboard(): boolean {

FILE: src/lib/utils/loadAttachmentsFromUrls.ts
  type AttachmentLoadResult (line 4) | interface AttachmentLoadResult {
  function parseAttachmentUrls (line 13) | function parseAttachmentUrls(searchParams: URLSearchParams): string[] {
  function extractFilename (line 32) | function extractFilename(url: string, contentDisposition?: string | null...
  function loadAttachmentsFromUrls (line 69) | async function loadAttachmentsFromUrls(

FILE: src/lib/utils/marked.spec.ts
  function renderHtml (line 4) | function renderHtml(md: string): string {

FILE: src/lib/utils/marked.ts
  type SimpleSource (line 7) | type SimpleSource = {
  constant VIDEO_EXTENSIONS (line 61) | const VIDEO_EXTENSIONS = /\.(mp4|webm|ogg|mov|m4v)([?#]|$)/i;
  constant AUDIO_EXTENSIONS (line 62) | const AUDIO_EXTENSIONS = /\.(mp3|wav|m4a|aac|flac)([?#]|$)/i;
  function isVideoUrl (line 64) | function isVideoUrl(url: string): boolean {
  function isAudioUrl (line 68) | function isAudioUrl(url: string): boolean {
  constant MULTIMEDIA_TAGS (line 73) | const MULTIMEDIA_TAGS = new Set(["video", "source", "audio"]);
  constant MULTIMEDIA_ALLOWED_ATTRS (line 74) | const MULTIMEDIA_ALLOWED_ATTRS = new Set([
  constant MULTIMEDIA_BOOLEAN_ATTRS (line 87) | const MULTIMEDIA_BOOLEAN_ATTRS = new Set(["controls", "autoplay", "loop"...
  constant MULTIMEDIA_URI_ATTRS (line 88) | const MULTIMEDIA_URI_ATTRS = new Set(["src", "poster"]);
  constant MULTIMEDIA_ALLOWED_URI_PATTERN (line 89) | const MULTIMEDIA_ALLOWED_URI_PATTERN = /^(?!javascript:|data:text\/html)/i;
  constant MULTIMEDIA_HTML_REGEX (line 90) | const MULTIMEDIA_HTML_REGEX = /<\/?(video|source|audio)\b/i;
  type HtmlNode (line 92) | type HtmlNode = {
  type katexBlockToken (line 100) | interface katexBlockToken extends Tokens.Generic {
  type katexInlineToken (line 107) | interface katexInlineToken extends Tokens.Generic {
  method start (line 118) | start(src: string): number | undefined {
  method tokenizer (line 123) | tokenizer(src: string): katexBlockToken | undefined {
  method renderer (line 153) | renderer(token) {
  method start (line 168) | start(src: string): number | undefined {
  method tokenizer (line 173) | tokenizer(src: string): katexInlineToken | undefined {
  method renderer (line 203) | renderer(token) {
  function escapeHTML (line 214) | function escapeHTML(content: string) {
  function addInlineCitations (line 228) | function addInlineCitations(md: string, webSearchSources: SimpleSource[]...
  function sanitizeHref (line 248) | function sanitizeHref(href?: string | null): string | undefined {
  function highlightCode (line 258) | function highlightCode(text: string, lang?: string): string {
  function sanitizeMediaUrl (line 269) | function sanitizeMediaUrl(value: string): string | undefined {
  function serializeMediaAttributes (line 275) | function serializeMediaAttributes(attribs?: Record<string, string>): str...
  function serializeMediaNode (line 296) | function serializeMediaNode(node: HtmlNode, state: { hasDisallowedTag: b...
  function sanitizeHtmlForMultimedia (line 326) | function sanitizeHtmlForMultimedia(html: string): string {
  function createMarkedInstance (line 345) | function createMarkedInstance(sources: SimpleSource[]): Marked {
  function isFencedBlockClosed (line 380) | function isFencedBlockClosed(raw?: string): boolean {
  type CodeToken (line 393) | type CodeToken = {
  type TextToken (line 401) | type TextToken = {
  function cacheKey (line 408) | function cacheKey(index: number, blockContent: string, sources: SimpleSo...
  function processTokens (line 413) | async function processTokens(content: string, sources: SimpleSource[]): ...
  function processTokensSync (line 442) | function processTokensSync(content: string, sources: SimpleSource[]): To...
  type Token (line 462) | type Token = CodeToken | TextToken;
  type BlockToken (line 464) | type BlockToken = {
  function hashString (line 473) | function hashString(str: string): string {
  function processBlocks (line 487) | async function processBlocks(
  function processBlocksSync (line 514) | function processBlocksSync(content: string, sources: SimpleSource[] = []...

FILE: src/lib/utils/mcpValidation.ts
  function validateMcpServerUrl (line 13) | function validateMcpServerUrl(urlString: string): string | null {
  function isPrivateOrLocalhost (line 48) | function isPrivateOrLocalhost(hostname: string): boolean {
  function sanitizeUrlForDisplay (line 72) | function sanitizeUrlForDisplay(urlString: string): string {
  function checkUrlSafety (line 88) | function checkUrlSafety(urlString: string): string | null {
  function isSensitiveHeader (line 111) | function isSensitiveHeader(key: string): boolean {
  function validateHeader (line 133) | function validateHeader(key: string, value: string): string | null {

FILE: src/lib/utils/mergeAsyncGenerators.ts
  type Gen (line 1) | type Gen<T, TReturn> = AsyncGenerator<T, TReturn, undefined>;
  type GenPromiseMap (line 3) | type GenPromiseMap<T, TReturn> = Map<

FILE: src/lib/utils/messageUpdates.spec.ts
  function collect (line 15) | async function collect(iter: AsyncGenerator<MessageUpdate>) {

FILE: src/lib/utils/messageUpdates.ts
  type MessageUpdateRequestOptions (line 15) | type MessageUpdateRequestOptions = {
  type ChunkDetector (line 29) | type ChunkDetector = (buffer: string) => string | null;
  type SmoothStreamConfig (line 31) | type SmoothStreamConfig = {
  function fetchMessageUpdates (line 43) | async function fetchMessageUpdates(
  function applyStreamingMode (line 94) | function applyStreamingMode(
  function resolveStreamingMode (line 106) | function resolveStreamingMode(s: { streamingMode?: unknown }): Streaming...
  function parseMessageUpdates (line 140) | function parseMessageUpdates(value: string): {
  function createWordChunkDetector (line 264) | function createWordChunkDetector(): ChunkDetector {

FILE: src/lib/utils/mime.ts
  constant EXTENSION_TO_MIME (line 3) | const EXTENSION_TO_MIME: Record<string, string> = {
  function guessMimeFromUrl (line 30) | function guessMimeFromUrl(url: string): string | undefined {
  function pickSafeMime (line 41) | function pickSafeMime(

FILE: src/lib/utils/parseBlocks.ts
  function parseMarkdownIntoBlocks (line 12) | function parseMarkdownIntoBlocks(markdown: string): string[] {

FILE: src/lib/utils/parseStringToList.ts
  function parseStringToList (line 1) | function parseStringToList(links: unknown): string[] {

FILE: src/lib/utils/randomUuid.ts
  type UUID (line 1) | type UUID = ReturnType<typeof crypto.randomUUID>;
  function randomUUID (line 3) | function randomUUID(): UUID {

FILE: src/lib/utils/searchTokens.ts
  constant PUNCTUATION_REGEX (line 1) | const PUNCTUATION_REGEX = /\p{P}/gu;
  function removeDiacritics (line 3) | function removeDiacritics(s: string, form: "NFD" | "NFKD" = "NFD"): stri...
  function generateSearchTokens (line 7) | function generateSearchTokens(value: string): string[] {
  function escapeForRegExp (line 23) | function escapeForRegExp(s: string): string {
  function generateQueryTokens (line 27) | function generateQueryTokens(query: string): RegExp[] {

FILE: src/lib/utils/sha256.ts
  function sha256 (line 1) | async function sha256(input: string): Promise<string> {

FILE: src/lib/utils/stringifyError.ts
  function stringifyError (line 2) | function stringifyError(error: unknown): string {

FILE: src/lib/utils/sum.ts
  function sum (line 1) | function sum(nums: number[]): number {

FILE: src/lib/utils/template.ts
  function compileTemplate (line 19) | function compileTemplate<T>(

FILE: src/lib/utils/toolProgress.ts
  function formatToolProgressLabel (line 3) | function formatToolProgressLabel(progress?: MessageToolProgressUpdate): ...

FILE: src/lib/utils/tree/addChildren.ts
  function addChildren (line 4) | function addChildren<T>(conv: Tree<T>, message: NewNode<T>, parentId?: T...

FILE: src/lib/utils/tree/addSibling.ts
  function addSibling (line 4) | function addSibling<T>(conv: Tree<T>, message: NewNode<T>, siblingId: Tr...

FILE: src/lib/utils/tree/buildSubtree.ts
  function buildSubtree (line 3) | function buildSubtree<T>(conv: Tree<T>, id: TreeId): TreeNode<T>[] {

FILE: src/lib/utils/tree/convertLegacyConversation.ts
  function convertLegacyConversation (line 5) | function convertLegacyConversation(

FILE: src/lib/utils/tree/isMessageId.ts
  function isMessageId (line 3) | function isMessageId(id: string): id is Message["id"] {

FILE: src/lib/utils/tree/tree.d.ts
  type TreeId (line 1) | type TreeId = string;
  type Tree (line 3) | type Tree<T> = {
  type TreeNode (line 8) | type TreeNode<T> = T & {
  type NewNode (line 14) | type NewNode<T> = Omit<TreeNode<T>, "id">;

FILE: src/lib/utils/updates.ts
  class UpdateDebouncer (line 6) | class UpdateDebouncer {
    method maxUpdateTime (line 10) | get maxUpdateTime() {
    method startRender (line 21) | public startRender() {
    method endRender (line 25) | public endRender() {

FILE: src/lib/utils/urlParams.ts
  constant MAX_PARAM_LENGTH (line 1) | const MAX_PARAM_LENGTH = 10_000;
  function sanitizeUrlParam (line 3) | function sanitizeUrlParam(value: string | null): string | null {

FILE: src/lib/workers/markdownWorker.ts
  type SimpleSource (line 2) | type SimpleSource = {
  type IncomingMessage (line 8) | type IncomingMessage = {
  type OutgoingMessage (line 15) | type OutgoingMessage = {
  function processMessage (line 28) | async function processMessage() {

FILE: src/routes/+layout.ts
  type ConversationListItem (line 7) | interface ConversationListItem {
  type UserInfo (line 14) | interface UserInfo {
  type SettingsResponse (line 23) | interface SettingsResponse {

FILE: src/routes/__debug/openai/+server.ts
  constant DEFAULT_OPENAI_BASE (line 3) | const DEFAULT_OPENAI_BASE = "https://router.huggingface.co/v1";
  function GET (line 5) | async function GET() {

FILE: src/routes/admin/export/+server.ts
  function POST (line 15) | async function POST({ request }) {

FILE: src/routes/admin/stats/compute/+server.ts
  function POST (line 8) | async function POST() {

FILE: src/routes/api/conversation/[id]/+server.ts
  function GET (line 6) | async function GET({ locals, params }) {

FILE: src/routes/api/conversation/[id]/message/[messageId]/+server.ts
  function DELETE (line 6) | async function DELETE({ locals, params }) {

FILE: src/routes/api/conversations/+server.ts
  function GET (line 6) | async function GET({ locals, url }) {
  function DELETE (line 40) | async function DELETE({ locals }) {

FILE: src/routes/api/fetch-url/+server.ts
  constant MAX_FILE_SIZE (line 7) | const MAX_FILE_SIZE = 10 * 1024 * 1024;
  constant FETCH_TIMEOUT (line 8) | const FETCH_TIMEOUT = 30000;
  constant MAX_REDIRECTS (line 9) | const MAX_REDIRECTS = 5;
  constant SECURITY_HEADERS (line 10) | const SECURITY_HEADERS: HeadersInit = {
  function GET (line 49) | async function GET({ url }) {

FILE: src/routes/api/mcp/health/+server.ts
  type HealthCheckRequest (line 11) | interface HealthCheckRequest {
  type HealthCheckResponse (line 16) | interface HealthCheckResponse {

FILE: src/routes/api/mcp/servers/+server.ts
  function GET (line 4) | async function GET() {

FILE: src/routes/api/models/+server.ts
  function GET (line 3) | async function GET() {

FILE: src/routes/api/transcribe/+server.ts
  constant MAX_AUDIO_SIZE (line 6) | const MAX_AUDIO_SIZE = 25 * 1024 * 1024;
  constant TRANSCRIPTION_TIMEOUT (line 7) | const TRANSCRIPTION_TIMEOUT = 60000;
  constant ALLOWED_CONTENT_TYPES (line 9) | const ALLOWED_CONTENT_TYPES = [
  function POST (line 19) | async function POST({ request, locals }) {

FILE: src/routes/api/user/+server.ts
  function GET (line 1) | async function GET({ locals }) {

FILE: src/routes/conversation/[id]/+page.ts
  type ConversationData (line 8) | interface ConversationData {

FILE: src/routes/conversation/[id]/+server.ts
  function POST (line 30) | async function POST({ request, locals, params, getClientAddress }) {
  function DELETE (line 679) | async function DELETE({ locals, params }) {
  function PATCH (line 696) | async function PATCH({ request, locals, params }) {

FILE: src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts
  function GET (line 10) | async function GET({ params, locals }) {

FILE: src/routes/conversation/[id]/share/+server.ts
  function POST (line 9) | async function POST({ params, locals }) {

FILE: src/routes/conversation/[id]/stop-generating/+server.ts
  function POST (line 10) | async function POST({ params, locals }) {

FILE: src/routes/healthcheck/+server.ts
  function GET (line 1) | async function GET() {

FILE: src/routes/login/+server.ts
  function GET (line 3) | async function GET(event) {

FILE: src/routes/login/callback/+server.ts
  function GET (line 27) | async function GET({ url, locals, cookies, request, getClientAddress }) {

FILE: src/routes/login/callback/updateUser.ts
  function updateUser (line 19) | async function updateUser(params: {

FILE: src/routes/logout/+server.ts
  function POST (line 7) | async function POST({ locals, cookies }) {

FILE: src/routes/metrics/+server.ts
  function GET (line 4) | async function GET() {

FILE: src/routes/models/[...model]/+page.ts
  function load (line 3) | async function load({ params, parent, fetch }) {

FILE: src/routes/settings/(nav)/+server.ts
  function POST (line 24) | async function POST({ request, locals }) {

FILE: src/routes/settings/(nav)/[...model]/+page.ts
  function load (line 4) | async function load({ parent, params }) {

FILE: svelte.config.js
  function getCurrentCommitSHA (line 12) | function getCurrentCommitSHA() {

FILE: vite.config.ts
  function loadTTFAsArrayBuffer (line 10) | function loadTTFAsArrayBuffer() {
Condensed preview — 412 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,269K chars).
[
  {
    "path": ".devcontainer/Dockerfile",
    "chars": 643,
    "preview": "FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm\n\n# Install MongoDB tools (mongosh, mongorestore, mong"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 1174,
    "preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
  },
  {
    "path": ".dockerignore",
    "chars": 117,
    "preview": "Dockerfile\n.vscode/\n.idea\n.gitignore\nLICENSE\nREADME.md\nnode_modules/\n.svelte-kit/\n.env*\n!.env\n.env.local\ndb\nmodels/**"
  },
  {
    "path": ".env",
    "chars": 7980,
    "preview": "# Use .env.local to change these variables\n# DO NOT EDIT THIS FILE WITH SENSITIVE DATA\n\n### Models ###\n# Models are sour"
  },
  {
    "path": ".env.ci",
    "chars": 38,
    "preview": "MONGODB_URL=mongodb://localhost:27017/"
  },
  {
    "path": ".eslintignore",
    "chars": 160,
    "preview": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n.env\n.env.*\n!.env.example\n\n# Ignore files for PNPM, NPM and YARN\npnp"
  },
  {
    "path": ".eslintrc.cjs",
    "chars": 952,
    "preview": "module.exports = {\n\troot: true,\n\tparser: \"@typescript-eslint/parser\",\n\textends: [\n\t\t\"eslint:recommended\",\n\t\t\"plugin:@typ"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report--chat-ui-.md",
    "chars": 766,
    "preview": "---\nname: Bug Report (chat-ui)\nabout: Use this for confirmed issues with chat-ui\ntitle: \"\"\nlabels: bug\nassignees: \"\"\n---"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config-support.md",
    "chars": 275,
    "preview": "---\nname: Config Support\nabout: Help with setting up chat-ui locally\ntitle: \"\"\nlabels: support\nassignees: \"\"\n---\n\n**Plea"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request--chat-ui-.md",
    "chars": 427,
    "preview": "---\nname: Feature Request (chat-ui)\nabout: Suggest new features to be added to chat-ui\ntitle: \"\"\nlabels: enhancement\nass"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/huggingchat.md",
    "chars": 392,
    "preview": "---\nname: HuggingChat\nabout: Requests & reporting outages on HuggingChat, the hosted version of chat-ui.\ntitle: \"\"\nlabel"
  },
  {
    "path": ".github/release.yml",
    "chars": 267,
    "preview": "changelog:\n  exclude:\n    labels:\n      - huggingchat\n      - CI/CD\n      - documentation\n  categories:\n    - title: Fea"
  },
  {
    "path": ".github/workflows/build-docs.yml",
    "chars": 406,
    "preview": "name: Build documentation\n\non:\n  push:\n    branches:\n      - main\n      - v*-release\n\njobs:\n  build:\n    uses: huggingfa"
  },
  {
    "path": ".github/workflows/build-image.yml",
    "chars": 4784,
    "preview": "name: Build and Publish Image\n\npermissions:\n  packages: write\n\non:\n  push:\n    branches:\n      - \"main\"\n  pull_request:\n"
  },
  {
    "path": ".github/workflows/build-pr-docs.yml",
    "chars": 525,
    "preview": "name: Build PR Documentation\n\non:\n  pull_request:\n    paths:\n      - \"docs/source/**\"\n      - \".github/workflows/build-p"
  },
  {
    "path": ".github/workflows/deploy-dev.yml",
    "chars": 1921,
    "preview": "name: Deploy to ephemeral\non:\n  pull_request:\n    types: [opened, reopened, synchronize, labeled, unlabeled]\n\njobs:\n  br"
  },
  {
    "path": ".github/workflows/deploy-prod.yml",
    "chars": 2535,
    "preview": "name: Deploy to k8s\non:\n  # run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  build-and-publ"
  },
  {
    "path": ".github/workflows/lint-and-test.yml",
    "chars": 1900,
    "preview": "name: Lint and test\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n  "
  },
  {
    "path": ".github/workflows/slugify.yaml",
    "chars": 1604,
    "preview": "name: Generate Branch Slug\n\non:\n  workflow_call:\n    inputs:\n      value:\n        description: \"Value to slugify\"\n      "
  },
  {
    "path": ".github/workflows/trufflehog.yml",
    "chars": 331,
    "preview": "on:\n  push:\n\nname: Secret Leaks\n\njobs:\n  trufflehog:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n "
  },
  {
    "path": ".github/workflows/upload-pr-documentation.yml",
    "chars": 381,
    "preview": "name: Upload PR Documentation\n\non:\n  workflow_run:\n    workflows: [\"Build PR Documentation\"]\n    types:\n      - complete"
  },
  {
    "path": ".gitignore",
    "chars": 235,
    "preview": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n.env\n.env.*\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\nSE"
  },
  {
    "path": ".husky/lint-stage-config.js",
    "chars": 123,
    "preview": "export default {\n\t\"*.{js,jsx,ts,tsx}\": [\"prettier --write\", \"eslint --fix\", \"eslint\"],\n\t\"*.json\": [\"prettier --write\"],\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 62,
    "preview": "set -e\nnpx lint-staged --config ./.husky/lint-stage-config.js\n"
  },
  {
    "path": ".npmrc",
    "chars": 19,
    "preview": "engine-strict=true\n"
  },
  {
    "path": ".prettierignore",
    "chars": 167,
    "preview": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n/chart\n.env\n.env.*\n!.env.example\n\n# Ignore files for PNPM, NPM and Y"
  },
  {
    "path": ".prettierrc",
    "chars": 213,
    "preview": "{\n\t\"useTabs\": true,\n\t\"trailingComma\": \"es5\",\n\t\"printWidth\": 100,\n\t\"plugins\": [\"prettier-plugin-svelte\", \"prettier-plugin"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 174,
    "preview": "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"command\": \"npm run dev\",\n\t\t\t\"name\": \"Run development server\",\n\t\t\t\"re"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 348,
    "preview": "{\n\t\"editor.formatOnSave\": true,\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.codeActionsOnSave\": {\n\t\t\""
  },
  {
    "path": "CLAUDE.md",
    "chars": 5044,
    "preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
  },
  {
    "path": "Dockerfile",
    "chars": 2147,
    "preview": "# syntax=docker/dockerfile:1\nARG INCLUDE_DB=false\n\nFROM node:24-slim AS base\n\n# install dotenv-cli\nRUN npm install -g do"
  },
  {
    "path": "LICENSE",
    "chars": 11417,
    "preview": "Copyright 2018- The Hugging Face team. All rights reserved.\n\n                                 Apache License\n           "
  },
  {
    "path": "PRIVACY.md",
    "chars": 2623,
    "preview": "## Privacy\n\n> Last updated: Sep 15, 2025\n\nBasics:\n\n- Sign-in: You authenticate with your Hugging Face account.\n- Convers"
  },
  {
    "path": "README.md",
    "chars": 9584,
    "preview": "# Chat UI\n\n![Chat UI repository thumbnail](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main"
  },
  {
    "path": "chart/Chart.yaml",
    "chars": 141,
    "preview": "apiVersion: v2\nname: chat-ui\nversion: 0.0.1-latest\ntype: application\nicon: https://huggingface.co/front/assets/huggingfa"
  },
  {
    "path": "chart/env/dev.yaml",
    "chars": 26515,
    "preview": "image:\n  repository: huggingface\n  name: chat-ui\n\n#nodeSelector:\n#  role-huggingchat: \"true\"\n#\n#tolerations:\n#  - key: \""
  },
  {
    "path": "chart/env/prod.yaml",
    "chars": 27497,
    "preview": "image:\n  repository: huggingface\n  name: chat-ui\n\nnodeSelector:\n  role-huggingchat: \"true\"\n\ntolerations:\n  - key: \"huggi"
  },
  {
    "path": "chart/templates/_helpers.tpl",
    "chars": 534,
    "preview": "{{- define \"name\" -}}\n{{- default $.Release.Name | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n\n{{- define \"app.name\" -}}\n"
  },
  {
    "path": "chart/templates/config.yaml",
    "chars": 268,
    "preview": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  labels: {{ include \"labels.standard\" . | nindent 4 }}\n  name: {{ include \"nam"
  },
  {
    "path": "chart/templates/deployment.yaml",
    "chars": 2964,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels: {{ include \"labels.standard\" . | nindent 4 }}\n  name: {{ includ"
  },
  {
    "path": "chart/templates/hpa.yaml",
    "chars": 1318,
    "preview": "{{- if $.Values.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  labels: {{ i"
  },
  {
    "path": "chart/templates/infisical.yaml",
    "chars": 860,
    "preview": "{{- if .Values.infisical.enabled }}\napiVersion: secrets.infisical.com/v1alpha1\nkind: InfisicalSecret\nmetadata:\n  name: {"
  },
  {
    "path": "chart/templates/ingress-internal.yaml",
    "chars": 939,
    "preview": "{{- if $.Values.ingressInternal.enabled }}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  annotations: {{ to"
  },
  {
    "path": "chart/templates/ingress.yaml",
    "chars": 882,
    "preview": "{{- if $.Values.ingress.enabled }}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  annotations: {{ toYaml .Va"
  },
  {
    "path": "chart/templates/network-policy.yaml",
    "chars": 909,
    "preview": "{{- if $.Values.networkPolicy.enabled }}\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: {{ inclu"
  },
  {
    "path": "chart/templates/service-account.yaml",
    "chars": 496,
    "preview": "{{- if and .Values.serviceAccount.enabled .Values.serviceAccount.create }}\napiVersion: v1\nkind: ServiceAccount\nautomount"
  },
  {
    "path": "chart/templates/service-monitor.yaml",
    "chars": 457,
    "preview": "{{- if eq \"true\" $.Values.envVars.METRICS_ENABLED }}\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:"
  },
  {
    "path": "chart/templates/service.yaml",
    "chars": 602,
    "preview": "apiVersion: v1\nkind: Service\nmetadata:\n  name: \"{{ include \"name\" . }}\"\n  annotations: {{ toYaml .Values.service.annotat"
  },
  {
    "path": "chart/values.yaml",
    "chars": 1197,
    "preview": "image:\n  repository: ghcr.io/huggingface\n  name: chat-ui\n  tag: 0.0.0-latest\n  pullPolicy: IfNotPresent\n\nreplicas: 3\n\ndo"
  },
  {
    "path": "docker-compose.yml",
    "chars": 753,
    "preview": "# For development only\n# Set MONGODB_URL=mongodb://localhost:27017 in .env.local to use this container\nservices:\n  mongo"
  },
  {
    "path": "docs/source/_toctree.yml",
    "chars": 764,
    "preview": "- local: index\n  title: Chat UI\n- title: Installation\n  sections:\n    - local: installation/local\n      title: Local\n   "
  },
  {
    "path": "docs/source/configuration/common-issues.md",
    "chars": 958,
    "preview": "# Common Issues\n\n## 403: You don't have access to this conversation\n\nThis usually happens when running Chat UI over HTTP"
  },
  {
    "path": "docs/source/configuration/llm-router.md",
    "chars": 2782,
    "preview": "# LLM Router\n\nChat UI includes an intelligent routing system that automatically selects the best model for each request."
  },
  {
    "path": "docs/source/configuration/mcp-tools.md",
    "chars": 2449,
    "preview": "# MCP Tools\n\nChat UI supports tool calling via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). MCP"
  },
  {
    "path": "docs/source/configuration/metrics.md",
    "chars": 408,
    "preview": "# Metrics\n\nThe server can expose prometheus metrics on port `5565` but is off by default. You may enable the metrics ser"
  },
  {
    "path": "docs/source/configuration/open-id.md",
    "chars": 1444,
    "preview": "# OpenID\n\nBy default, users are attributed a unique ID based on their browser session. To authenticate users with OpenID"
  },
  {
    "path": "docs/source/configuration/overview.md",
    "chars": 2301,
    "preview": "# Configuration Overview\n\nChat UI is configured through environment variables. Default values are in `.env`; override th"
  },
  {
    "path": "docs/source/configuration/theming.md",
    "chars": 692,
    "preview": "# Theming\n\nCustomize the look and feel of Chat UI with these environment variables:\n\n```ini\nPUBLIC_APP_NAME=ChatUI\nPUBLI"
  },
  {
    "path": "docs/source/developing/architecture.md",
    "chars": 1836,
    "preview": "# Architecture\n\nThis document provides a high-level overview of the Chat UI codebase. If you're looking to contribute or"
  },
  {
    "path": "docs/source/index.md",
    "chars": 2107,
    "preview": "# Chat UI\n\nOpen source chat interface with support for tools, multimodal inputs, and intelligent routing across models. "
  },
  {
    "path": "docs/source/installation/docker.md",
    "chars": 1187,
    "preview": "# Running on Docker\n\nPre-built Docker images are available:\n\n- **`ghcr.io/huggingface/chat-ui-db`** - Includes MongoDB ("
  },
  {
    "path": "docs/source/installation/helm.md",
    "chars": 888,
    "preview": "# Helm\n\n<Tip warning={true}>\n\nThe Helm chart is a work in progress and should be considered unstable. Breaking changes m"
  },
  {
    "path": "docs/source/installation/local.md",
    "chars": 1647,
    "preview": "# Running Locally\n\n## Quick Start\n\n1. Create a `.env.local` file with your API credentials:\n\n```ini\nOPENAI_BASE_URL=http"
  },
  {
    "path": "entrypoint.sh",
    "chars": 703,
    "preview": "ENV_LOCAL_PATH=/app/.env.local\n\nif test -z \"${DOTENV_LOCAL}\" ; then\n    if ! test -f \"${ENV_LOCAL_PATH}\" ; then\n        "
  },
  {
    "path": "models/add-your-models-here.txt",
    "chars": 93,
    "preview": "You can add .gguf files to this folder, and they will be picked up automatically by chat-ui. "
  },
  {
    "path": "package.json",
    "chars": 3390,
    "preview": "{\n\t\"name\": \"chat-ui\",\n\t\"version\": \"0.20.0\",\n\t\"private\": true,\n\t\"packageManager\": \"npm@9.5.0\",\n\t\"scripts\": {\n\t\t\"dev\": \"vi"
  },
  {
    "path": "postcss.config.js",
    "chars": 75,
    "preview": "export default {\n\tplugins: {\n\t\ttailwindcss: {},\n\t\tautoprefixer: {},\n\t},\n};\n"
  },
  {
    "path": "scripts/config.ts",
    "chars": 1373,
    "preview": "import sade from \"sade\";\n\n// @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see"
  },
  {
    "path": "scripts/populate.ts",
    "chars": 9029,
    "preview": "import readline from \"readline\";\nimport minimist from \"minimist\";\n\n// @ts-expect-error: vite-node makes the var availabl"
  },
  {
    "path": "scripts/samples.txt",
    "chars": 6039,
    "preview": "import { Observable, of, from, interval, throwError } from 'rxjs';\nimport { map, filter, catchError, switchMap, take, ta"
  },
  {
    "path": "scripts/setups/vitest-setup-client.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "scripts/setups/vitest-setup-server.ts",
    "chars": 1048,
    "preview": "import { vi, afterAll } from \"vitest\";\nimport dotenv from \"dotenv\";\nimport { resolve } from \"path\";\nimport fs from \"fs\";"
  },
  {
    "path": "scripts/updateLocalEnv.ts",
    "chars": 1426,
    "preview": "import fs from \"fs\";\nimport yaml from \"js-yaml\";\n\nconst file = fs.readFileSync(\"chart/env/prod.yaml\", \"utf8\");\n\n// have "
  },
  {
    "path": "server.log",
    "chars": 106,
    "preview": "/Users/vm/.venv/bin/python3: No module named uvicorn\n/Users/vm/.venv/bin/python3: No module named uvicorn\n"
  },
  {
    "path": "src/ambient.d.ts",
    "chars": 220,
    "preview": "declare module \"*.ttf\" {\n\tconst value: ArrayBuffer;\n\texport default value;\n}\n\n// Legacy helpers removed: web search supp"
  },
  {
    "path": "src/app.d.ts",
    "chars": 658,
    "preview": "/// <reference types=\"@sveltejs/kit\" />\n/// <reference types=\"unplugin-icons/types/svelte\" />\n\nimport type { User } from"
  },
  {
    "path": "src/app.html",
    "chars": 1868,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-"
  },
  {
    "path": "src/hooks.server.ts",
    "chars": 1099,
    "preview": "import { building } from \"$app/environment\";\nimport type { Handle, HandleServerError, ServerInit, HandleFetch } from \"@s"
  },
  {
    "path": "src/hooks.ts",
    "chars": 204,
    "preview": "import { publicConfigTransporter } from \"$lib/utils/PublicConfig.svelte\";\nimport type { Transport } from \"@sveltejs/kit\""
  },
  {
    "path": "src/lib/APIClient.ts",
    "chars": 4158,
    "preview": "import { base } from \"$app/paths\";\nimport { browser } from \"$app/environment\";\nimport superjson from \"superjson\";\nimport"
  },
  {
    "path": "src/lib/actions/clickOutside.ts",
    "chars": 437,
    "preview": "export function clickOutside(element: HTMLElement, callbackFunction: () => void) {\n\tfunction onClick(event: MouseEvent) "
  },
  {
    "path": "src/lib/actions/snapScrollToBottom.ts",
    "chars": 10057,
    "preview": "import { navigating } from \"$app/state\";\nimport { tick } from \"svelte\";\n\n// Threshold to determine if user is \"at bottom"
  },
  {
    "path": "src/lib/buildPrompt.ts",
    "chars": 793,
    "preview": "import type { EndpointParameters } from \"./server/endpoints/endpoints\";\nimport type { BackendModel } from \"./server/mode"
  },
  {
    "path": "src/lib/components/AnnouncementBanner.svelte",
    "chars": 586,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\ttitle?: string;\n\t\tclassNames?: string;\n\t\tchildren?: import(\"svelte\").Snippet;\n\t}"
  },
  {
    "path": "src/lib/components/BackgroundGenerationPoller.svelte",
    "chars": 4619,
    "preview": "<script lang=\"ts\">\n\timport { browser, dev } from \"$app/environment\";\n\timport { invalidate } from \"$app/navigation\";\n\n\tim"
  },
  {
    "path": "src/lib/components/CodeBlock.svelte",
    "chars": 2509,
    "preview": "<script lang=\"ts\">\n\timport CopyToClipBoardBtn from \"./CopyToClipBoardBtn.svelte\";\n\timport DOMPurify from \"isomorphic-dom"
  },
  {
    "path": "src/lib/components/CopyToClipBoardBtn.svelte",
    "chars": 1827,
    "preview": "<script lang=\"ts\">\n\timport { onDestroy } from \"svelte\";\n\timport { confirm as hapticConfirm } from \"$lib/utils/haptics\";\n"
  },
  {
    "path": "src/lib/components/DeleteConversationModal.svelte",
    "chars": 2352,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"$lib/components/Modal.svelte\";\n\timport { onMount } from \"svelte\";\n\n\tinterface Pro"
  },
  {
    "path": "src/lib/components/EditConversationModal.svelte",
    "chars": 3092,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"$lib/components/Modal.svelte\";\n\timport { onMount } from \"svelte\";\n\n\tinterface Pro"
  },
  {
    "path": "src/lib/components/ExpandNavigation.svelte",
    "chars": 828,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tisCollapsed: boolean;\n\t\tonClick: () => void;\n\t\tclassNames: string;\n\t}\n\n\tlet { is"
  },
  {
    "path": "src/lib/components/HoverTooltip.svelte",
    "chars": 872,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tlabel?: string;\n\t\tposition?: \"top\" | \"bottom\" | \"left\" | \"right\";\n\t\tTooltipClass"
  },
  {
    "path": "src/lib/components/HtmlPreviewModal.svelte",
    "chars": 7495,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"./Modal.svelte\";\n\timport { onMount, onDestroy } from \"svelte\";\n\timport CarbonClos"
  },
  {
    "path": "src/lib/components/InfiniteScroll.svelte",
    "chars": 1051,
    "preview": "<script lang=\"ts\">\n\timport { onMount } from \"svelte\";\n\tinterface Props {\n\t\tonvisible?: () => void;\n\t}\n\n\tlet { onvisible "
  },
  {
    "path": "src/lib/components/MobileNav.svelte",
    "chars": 9204,
    "preview": "<script lang=\"ts\" module>\n\tlet isOpen = $state(false);\n\n\texport function closeMobileNav() {\n\t\tisOpen = false;\n\t}\n\n\texpor"
  },
  {
    "path": "src/lib/components/Modal.svelte",
    "chars": 3125,
    "preview": "<script lang=\"ts\">\n\timport { onDestroy, onMount } from \"svelte\";\n\timport { cubicOut } from \"svelte/easing\";\n\timport { fa"
  },
  {
    "path": "src/lib/components/ModelCardMetadata.svelte",
    "chars": 2054,
    "preview": "<script lang=\"ts\">\n\timport CarbonEarth from \"~icons/carbon/earth\";\n\timport CarbonArrowUpRight from \"~icons/carbon/arrow-"
  },
  {
    "path": "src/lib/components/NavConversationItem.svelte",
    "chars": 4194,
    "preview": "<script lang=\"ts\">\n\timport { base } from \"$app/paths\";\n\timport { page } from \"$app/state\";\n\timport { tick } from \"svelte"
  },
  {
    "path": "src/lib/components/NavMenu.svelte",
    "chars": 7954,
    "preview": "<script lang=\"ts\" module>\n\texport const titles: { [key: string]: string } = {\n\t\ttoday: \"Today\",\n\t\tweek: \"This week\",\n\t\tm"
  },
  {
    "path": "src/lib/components/Pagination.svelte",
    "chars": 2745,
    "preview": "<script lang=\"ts\">\n\timport { page } from \"$app/state\";\n\timport { getHref } from \"$lib/utils/getHref\";\n\timport Pagination"
  },
  {
    "path": "src/lib/components/PaginationArrow.svelte",
    "chars": 624,
    "preview": "<script lang=\"ts\">\n\timport CarbonCaretLeft from \"~icons/carbon/caret-left\";\n\timport CarbonCaretRight from \"~icons/carbon"
  },
  {
    "path": "src/lib/components/Portal.svelte",
    "chars": 449,
    "preview": "<script lang=\"ts\">\n\timport { onMount, onDestroy } from \"svelte\";\n\tinterface Props {\n\t\tchildren?: import(\"svelte\").Snippe"
  },
  {
    "path": "src/lib/components/RetryBtn.svelte",
    "chars": 537,
    "preview": "<script lang=\"ts\">\n\timport CarbonRotate360 from \"~icons/carbon/rotate-360\";\n\n\tinterface Props {\n\t\tclassNames?: string;\n\t"
  },
  {
    "path": "src/lib/components/ScrollToBottomBtn.svelte",
    "chars": 1382,
    "preview": "<script lang=\"ts\">\n\timport { fade } from \"svelte/transition\";\n\timport IconChevron from \"./icons/IconChevron.svelte\";\n\n\ti"
  },
  {
    "path": "src/lib/components/ScrollToPreviousBtn.svelte",
    "chars": 2025,
    "preview": "<script lang=\"ts\">\n\timport { fade } from \"svelte/transition\";\n\timport { onDestroy, untrack } from \"svelte\";\n\timport Icon"
  },
  {
    "path": "src/lib/components/ShareConversationModal.svelte",
    "chars": 5939,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"$lib/components/Modal.svelte\";\n\timport { base } from \"$app/paths\";\n\timport { page"
  },
  {
    "path": "src/lib/components/StopGeneratingBtn.svelte",
    "chars": 1561,
    "preview": "<script lang=\"ts\">\n\timport CarbonStopFilledAlt from \"~icons/carbon/stop-filled-alt\";\n\n\tinterface Props {\n\t\tclassNames?: "
  },
  {
    "path": "src/lib/components/SubscribeModal.svelte",
    "chars": 3024,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"$lib/components/Modal.svelte\";\n\timport { isPro } from \"$lib/stores/isPro\";\n\timpor"
  },
  {
    "path": "src/lib/components/Switch.svelte",
    "chars": 1101,
    "preview": "<script lang=\"ts\">\n\timport { tap } from \"$lib/utils/haptics\";\n\n\tinterface Props {\n\t\tchecked: boolean;\n\t\tname: string;\n\t}"
  },
  {
    "path": "src/lib/components/SystemPromptModal.svelte",
    "chars": 1462,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"./Modal.svelte\";\n\timport CarbonClose from \"~icons/carbon/close\";\n\timport CarbonBl"
  },
  {
    "path": "src/lib/components/Toast.svelte",
    "chars": 825,
    "preview": "<script lang=\"ts\">\n\timport { fade } from \"svelte/transition\";\n\timport Portal from \"./Portal.svelte\";\n\timport IconDazzled"
  },
  {
    "path": "src/lib/components/Tooltip.svelte",
    "chars": 653,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t\tlabel?: string;\n\t\tposition?: string;\n\t}\n\n\tlet {\n\t\tclassNa"
  },
  {
    "path": "src/lib/components/WelcomeModal.svelte",
    "chars": 2023,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"$lib/components/Modal.svelte\";\n\timport IconOmni from \"$lib/components/icons/IconO"
  },
  {
    "path": "src/lib/components/chat/Alternatives.svelte",
    "chars": 2395,
    "preview": "<script lang=\"ts\">\n\timport type { Message } from \"$lib/types/Message\";\n\timport CarbonChevronLeft from \"~icons/carbon/che"
  },
  {
    "path": "src/lib/components/chat/BlockWrapper.svelte",
    "chars": 1530,
    "preview": "<script lang=\"ts\">\n\timport type { Snippet } from \"svelte\";\n\n\tinterface Props {\n\t\ticon: Snippet;\n\t\ticonBg?: string;\n\t\tico"
  },
  {
    "path": "src/lib/components/chat/ChatInput.svelte",
    "chars": 16764,
    "preview": "<script lang=\"ts\">\n\timport { onMount, tick } from \"svelte\";\n\n\timport { afterNavigate } from \"$app/navigation\";\n\n\timport "
  },
  {
    "path": "src/lib/components/chat/ChatIntroduction.svelte",
    "chars": 2900,
    "preview": "<script lang=\"ts\">\n\timport Logo from \"$lib/components/icons/Logo.svelte\";\n\timport type { Model } from \"$lib/types/Model\""
  },
  {
    "path": "src/lib/components/chat/ChatMessage.svelte",
    "chars": 17853,
    "preview": "<script lang=\"ts\">\n\timport type { Message } from \"$lib/types/Message\";\n\timport { tick } from \"svelte\";\n\n\timport { usePub"
  },
  {
    "path": "src/lib/components/chat/ChatWindow.svelte",
    "chars": 26777,
    "preview": "<script lang=\"ts\">\n\timport type { Message, MessageFile } from \"$lib/types/Message\";\n\timport { onDestroy } from \"svelte\";"
  },
  {
    "path": "src/lib/components/chat/FileDropzone.svelte",
    "chars": 2567,
    "preview": "<script lang=\"ts\">\n\timport { requireAuthUser } from \"$lib/utils/auth\";\n\timport CarbonImage from \"~icons/carbon/image\";\n\n"
  },
  {
    "path": "src/lib/components/chat/ImageLightbox.svelte",
    "chars": 1647,
    "preview": "<script lang=\"ts\">\n\timport { onMount } from \"svelte\";\n\timport Portal from \"../Portal.svelte\";\n\timport CarbonClose from \""
  },
  {
    "path": "src/lib/components/chat/MarkdownBlock.svelte",
    "chars": 612,
    "preview": "<script lang=\"ts\">\n\timport type { Token } from \"$lib/utils/marked\";\n\timport CodeBlock from \"../CodeBlock.svelte\";\n\n\tinte"
  },
  {
    "path": "src/lib/components/chat/MarkdownRenderer.svelte",
    "chars": 2048,
    "preview": "<script lang=\"ts\">\n\timport { processBlocks, processBlocksSync, type BlockToken } from \"$lib/utils/marked\";\n\timport Markd"
  },
  {
    "path": "src/lib/components/chat/MarkdownRenderer.svelte.test.ts",
    "chars": 2595,
    "preview": "import MarkdownRenderer from \"./MarkdownRenderer.svelte\";\nimport { render } from \"vitest-browser-svelte\";\nimport { page "
  },
  {
    "path": "src/lib/components/chat/MessageAvatar.svelte",
    "chars": 2887,
    "preview": "<script lang=\"ts\">\n\timport { onDestroy } from \"svelte\";\n\n\tlet { animating = false, classNames = \"\" } = $props();\n\n\tlet b"
  },
  {
    "path": "src/lib/components/chat/ModelSwitch.svelte",
    "chars": 1665,
    "preview": "<script lang=\"ts\">\n\timport { invalidateAll } from \"$app/navigation\";\n\timport { page } from \"$app/state\";\n\timport { base "
  },
  {
    "path": "src/lib/components/chat/OpenReasoningResults.svelte",
    "chars": 2663,
    "preview": "<script lang=\"ts\">\n\timport MarkdownRenderer from \"./MarkdownRenderer.svelte\";\n\timport BlockWrapper from \"./BlockWrapper."
  },
  {
    "path": "src/lib/components/chat/ToolUpdate.svelte",
    "chars": 8947,
    "preview": "<script lang=\"ts\">\n\timport { MessageToolUpdateType, type MessageToolUpdate } from \"$lib/types/MessageUpdate\";\n\timport {\n"
  },
  {
    "path": "src/lib/components/chat/UploadedFile.svelte",
    "chars": 8695,
    "preview": "<script lang=\"ts\">\n\timport { page } from \"$app/state\";\n\timport type { MessageFile } from \"$lib/types/Message\";\n\timport C"
  },
  {
    "path": "src/lib/components/chat/UrlFetchModal.svelte",
    "chars": 6449,
    "preview": "<script lang=\"ts\">\n\timport Modal from \"../Modal.svelte\";\n\timport { base } from \"$app/paths\";\n\timport { tick } from \"svel"
  },
  {
    "path": "src/lib/components/chat/VoiceRecorder.svelte",
    "chars": 6205,
    "preview": "<script lang=\"ts\">\n\timport { onMount, onDestroy } from \"svelte\";\n\timport CarbonClose from \"~icons/carbon/close\";\n\timport"
  },
  {
    "path": "src/lib/components/icons/IconBurger.svelte",
    "chars": 427,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconCheap.svelte",
    "chars": 878,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n<"
  },
  {
    "path": "src/lib/components/icons/IconChevron.svelte",
    "chars": 392,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconDazzled.svelte",
    "chars": 1620,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconFast.svelte",
    "chars": 764,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n<"
  },
  {
    "path": "src/lib/components/icons/IconLoading.svelte",
    "chars": 603,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconMCP.svelte",
    "chars": 586,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconMoon.svelte",
    "chars": 1100,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconNew.svelte",
    "chars": 886,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconOmni.svelte",
    "chars": 5113,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconPaperclip.svelte",
    "chars": 708,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconPro.svelte",
    "chars": 988,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n\n\t// I've n"
  },
  {
    "path": "src/lib/components/icons/IconShare.svelte",
    "chars": 1948,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/IconSun.svelte",
    "chars": 11137,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/icons/Logo.svelte",
    "chars": 367,
    "preview": "<script lang=\"ts\">\n\timport { usePublicConfig } from \"$lib/utils/PublicConfig.svelte\";\n\n\tconst publicConfig = usePublicCo"
  },
  {
    "path": "src/lib/components/icons/LogoHuggingFaceBorderless.svelte",
    "chars": 4813,
    "preview": "<script lang=\"ts\">\n\tinterface Props {\n\t\tclassNames?: string;\n\t}\n\n\tlet { classNames = \"\" }: Props = $props();\n</script>\n\n"
  },
  {
    "path": "src/lib/components/mcp/AddServerForm.svelte",
    "chars": 7589,
    "preview": "<script lang=\"ts\">\n\timport type { KeyValuePair } from \"$lib/types/Tool\";\n\timport {\n\t\tvalidateMcpServerUrl,\n\t\tvalidateHea"
  },
  {
    "path": "src/lib/components/mcp/MCPServerManager.svelte",
    "chars": 6258,
    "preview": "<script lang=\"ts\">\n\timport { usePublicConfig } from \"$lib/utils/PublicConfig.svelte\";\n\timport Modal from \"$lib/component"
  },
  {
    "path": "src/lib/components/mcp/ServerCard.svelte",
    "chars": 6537,
    "preview": "<script lang=\"ts\">\n\timport type { MCPServer } from \"$lib/types/Tool\";\n\timport { toggleServer, healthCheckServer, deleteC"
  },
  {
    "path": "src/lib/components/players/AudioPlayer.svelte",
    "chars": 2291,
    "preview": "<script lang=\"ts\">\n\timport CarbonPause from \"~icons/carbon/pause\";\n\timport CarbonPlay from \"~icons/carbon/play\";\n\tinterf"
  },
  {
    "path": "src/lib/components/voice/AudioWaveform.svelte",
    "chars": 2812,
    "preview": "<script lang=\"ts\">\n\timport { onMount, onDestroy } from \"svelte\";\n\n\tinterface Props {\n\t\tfrequencyData: Uint8Array;\n\t\tminH"
  },
  {
    "path": "src/lib/constants/mcpExamples.ts",
    "chars": 3356,
    "preview": "import type { RouterExample } from \"./routerExamples\";\n\n// Examples that showcase MCP tool capabilities (web search, Hug"
  },
  {
    "path": "src/lib/constants/mime.ts",
    "chars": 333,
    "preview": "// Centralized MIME allowlists used across client and server\n// Keep these lists minimal and consistent with server proc"
  },
  {
    "path": "src/lib/constants/pagination.ts",
    "chars": 37,
    "preview": "export const CONV_NUM_PER_PAGE = 30;\n"
  },
  {
    "path": "src/lib/constants/publicSepToken.ts",
    "chars": 40,
    "preview": "export const PUBLIC_SEP_TOKEN = \"</s>\";\n"
  },
  {
    "path": "src/lib/constants/routerExamples.ts",
    "chars": 6045,
    "preview": "export type RouterFollowUp = {\n\ttitle: string;\n\tprompt: string;\n};\n\nexport type RouterExampleAttachment = {\n\tsrc: string"
  },
  {
    "path": "src/lib/createShareLink.ts",
    "chars": 793,
    "preview": "import { base } from \"$app/paths\";\nimport { page } from \"$app/state\";\n\n// Returns a public share URL for a conversation "
  },
  {
    "path": "src/lib/jobs/refresh-conversation-stats.ts",
    "chars": 6893,
    "preview": "import type { ConversationStats } from \"$lib/types/ConversationStats\";\nimport { CONVERSATION_STATS_COLLECTION, collectio"
  },
  {
    "path": "src/lib/migrations/lock.ts",
    "chars": 1389,
    "preview": "import { collections } from \"$lib/server/database\";\nimport { ObjectId } from \"mongodb\";\nimport type { Semaphores } from "
  },
  {
    "path": "src/lib/migrations/migrations.spec.ts",
    "chars": 2360,
    "preview": "import { afterEach, assert, beforeAll, describe, expect, it } from \"vitest\";\nimport { migrations } from \"./routines\";\nim"
  },
  {
    "path": "src/lib/migrations/migrations.ts",
    "chars": 3503,
    "preview": "import { Database } from \"$lib/server/database\";\nimport { migrations } from \"./routines\";\nimport { acquireLock, releaseL"
  },
  {
    "path": "src/lib/migrations/routines/01-update-search-assistants.ts",
    "chars": 1237,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { ObjectId, type AnyBulkW"
  },
  {
    "path": "src/lib/migrations/routines/02-update-assistants-models.ts",
    "chars": 1469,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { ObjectId } from \"mongod"
  },
  {
    "path": "src/lib/migrations/routines/04-update-message-updates.ts",
    "chars": 3896,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { ObjectId, type WithId }"
  },
  {
    "path": "src/lib/migrations/routines/05-update-message-files.ts",
    "chars": 1555,
    "preview": "import { ObjectId, type WithId } from \"mongodb\";\nimport { collections } from \"$lib/server/database\";\n\nimport type { Migr"
  },
  {
    "path": "src/lib/migrations/routines/06-trim-message-updates.ts",
    "chars": 1786,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { ObjectId, type WithId }"
  },
  {
    "path": "src/lib/migrations/routines/08-update-featured-to-review.ts",
    "chars": 1022,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { ObjectId } from \"mongod"
  },
  {
    "path": "src/lib/migrations/routines/09-delete-empty-conversations.spec.ts",
    "chars": 6196,
    "preview": "import type { Session } from \"$lib/types/Session\";\nimport type { User } from \"$lib/types/User\";\nimport type { Conversati"
  },
  {
    "path": "src/lib/migrations/routines/09-delete-empty-conversations.ts",
    "chars": 2811,
    "preview": "import type { Migration } from \".\";\nimport { collections } from \"$lib/server/database\";\nimport { Collection, FindCursor,"
  },
  {
    "path": "src/lib/migrations/routines/10-update-reports-assistantid.ts",
    "chars": 579,
    "preview": "import { collections } from \"$lib/server/database\";\nimport type { Migration } from \".\";\nimport { ObjectId } from \"mongod"
  },
  {
    "path": "src/lib/migrations/routines/index.ts",
    "chars": 474,
    "preview": "import type { ObjectId } from \"mongodb\";\n\nimport type { Database } from \"$lib/server/database\";\n\nexport interface Migrat"
  },
  {
    "path": "src/lib/server/__tests__/conversation-stop-generating.spec.ts",
    "chars": 3008,
    "preview": "import { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { ObjectId } from \"mongodb\";\n\nimport { collections "
  },
  {
    "path": "src/lib/server/abortRegistry.ts",
    "chars": 1515,
    "preview": "import { logger } from \"$lib/server/logger\";\n\n/**\n * Tracks active upstream generation requests so they can be cancelled"
  },
  {
    "path": "src/lib/server/abortedGenerations.ts",
    "chars": 1332,
    "preview": "// Shouldn't be needed if we dove into sveltekit internals, see https://github.com/huggingface/chat-ui/pull/88#issuecomm"
  },
  {
    "path": "src/lib/server/adminToken.ts",
    "chars": 1793,
    "preview": "import { config } from \"$lib/server/config\";\nimport type { Session } from \"$lib/types/Session\";\nimport { logger } from \""
  },
  {
    "path": "src/lib/server/api/__tests__/conversations-id.spec.ts",
    "chars": 8167,
    "preview": "import { describe, expect, it, afterEach } from \"vitest\";\nimport { ObjectId } from \"mongodb\";\nimport superjson from \"sup"
  },
  {
    "path": "src/lib/server/api/__tests__/conversations-message.spec.ts",
    "chars": 5969,
    "preview": "import { describe, expect, it, afterEach } from \"vitest\";\nimport { ObjectId } from \"mongodb\";\nimport { v4 } from \"uuid\";"
  },
  {
    "path": "src/lib/server/api/__tests__/conversations.spec.ts",
    "chars": 6949,
    "preview": "import { describe, expect, it, afterEach } from \"vitest\";\nimport superjson from \"superjson\";\nimport { collections } from"
  },
  {
    "path": "src/lib/server/api/__tests__/misc.spec.ts",
    "chars": 2431,
    "preview": "import { describe, it, expect, beforeEach } from \"vitest\";\nimport superjson from \"superjson\";\nimport { createTestLocals,"
  },
  {
    "path": "src/lib/server/api/__tests__/testHelpers.ts",
    "chars": 2137,
    "preview": "import { ObjectId } from \"mongodb\";\nimport { collections } from \"$lib/server/database\";\nimport type { User } from \"$lib/"
  },
  {
    "path": "src/lib/server/api/__tests__/user-reports.spec.ts",
    "chars": 2286,
    "preview": "import { describe, it, expect, beforeEach } from \"vitest\";\nimport { ObjectId } from \"mongodb\";\nimport superjson from \"su"
  },
  {
    "path": "src/lib/server/api/__tests__/user.spec.ts",
    "chars": 6721,
    "preview": "import { describe, it, expect, beforeEach } from \"vitest\";\nimport superjson from \"superjson\";\nimport { collections } fro"
  },
  {
    "path": "src/lib/server/api/types.ts",
    "chars": 879,
    "preview": "import type { BackendModel } from \"$lib/server/models\";\n\nexport type GETModelsResponse = Array<{\n\tid: string;\n\tname: str"
  },
  {
    "path": "src/lib/server/api/utils/requireAuth.ts",
    "chars": 544,
    "preview": "import { error } from \"@sveltejs/kit\";\n\n/**\n * Throws 401 if neither a user._id nor sessionId is present in locals.\n */\n"
  },
  {
    "path": "src/lib/server/api/utils/resolveConversation.ts",
    "chars": 1666,
    "preview": "import { collections } from \"$lib/server/database\";\nimport { ObjectId } from \"mongodb\";\nimport { authCondition } from \"$"
  },
  {
    "path": "src/lib/server/api/utils/resolveModel.ts",
    "chars": 713,
    "preview": "import { error } from \"@sveltejs/kit\";\n\n/**\n * Resolve a model by namespace and optional model name.\n * Looks up in the "
  },
  {
    "path": "src/lib/server/api/utils/superjsonResponse.ts",
    "chars": 393,
    "preview": "import superjson from \"superjson\";\n\n/**\n * Create a JSON response serialized with superjson.\n * Matches the wire format "
  },
  {
    "path": "src/lib/server/apiToken.ts",
    "chars": 299,
    "preview": "import { config } from \"$lib/server/config\";\n\nexport function getApiToken(locals: App.Locals | undefined) {\n\tif (config."
  },
  {
    "path": "src/lib/server/auth.ts",
    "chars": 15584,
    "preview": "import {\n\tIssuer,\n\ttype BaseClient,\n\ttype UserinfoResponse,\n\ttype TokenSet,\n\tcustom,\n\tgenerators,\n} from \"openid-client\""
  },
  {
    "path": "src/lib/server/config.ts",
    "chars": 4917,
    "preview": "import { env as publicEnv } from \"$env/dynamic/public\";\nimport { env as serverEnv } from \"$env/dynamic/private\";\nimport "
  },
  {
    "path": "src/lib/server/conversation.ts",
    "chars": 2745,
    "preview": "import { collections } from \"$lib/server/database\";\nimport { MetricsServer } from \"$lib/server/metrics\";\nimport { error "
  },
  {
    "path": "src/lib/server/database.ts",
    "chars": 13541,
    "preview": "import { GridFSBucket, MongoClient, ReadPreference } from \"mongodb\";\nimport type { Conversation } from \"$lib/types/Conve"
  },
  {
    "path": "src/lib/server/endpoints/document.ts",
    "chars": 1838,
    "preview": "import type { MessageFile } from \"$lib/types/Message\";\nimport { z } from \"zod\";\n\nexport interface FileProcessorOptions<T"
  },
  {
    "path": "src/lib/server/endpoints/endpoints.ts",
    "chars": 1496,
    "preview": "import type { Conversation } from \"$lib/types/Conversation\";\nimport type { Message } from \"$lib/types/Message\";\nimport t"
  },
  {
    "path": "src/lib/server/endpoints/images.ts",
    "chars": 7018,
    "preview": "import type { Sharp } from \"sharp\";\nimport sharp from \"sharp\";\nimport type { MessageFile } from \"$lib/types/Message\";\nim"
  },
  {
    "path": "src/lib/server/endpoints/openai/endpointOai.ts",
    "chars": 8914,
    "preview": "import { z } from \"zod\";\nimport { openAICompletionToTextGenerationStream } from \"./openAICompletionToTextGenerationStrea"
  },
  {
    "path": "src/lib/server/endpoints/openai/openAIChatToTextGenerationStream.ts",
    "chars": 6093,
    "preview": "import type { TextGenerationStreamOutput } from \"@huggingface/inference\";\nimport type OpenAI from \"openai\";\nimport type "
  },
  {
    "path": "src/lib/server/endpoints/openai/openAICompletionToTextGenerationStream.ts",
    "chars": 937,
    "preview": "import type { TextGenerationStreamOutput } from \"@huggingface/inference\";\nimport type OpenAI from \"openai\";\nimport type "
  },
  {
    "path": "src/lib/server/endpoints/preprocessMessages.ts",
    "chars": 1945,
    "preview": "import type { Message } from \"$lib/types/Message\";\nimport type { EndpointMessage } from \"./endpoints\";\nimport { download"
  },
  {
    "path": "src/lib/server/exitHandler.ts",
    "chars": 1532,
    "preview": "import { randomUUID } from \"$lib/utils/randomUuid\";\nimport { timeout } from \"$lib/utils/timeout\";\nimport { logger } from"
  }
]

// ... and 212 more files (download for full content)

About this extraction

This page contains the full source code of the huggingface/chat-ui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 412 files (1.1 MB), approximately 321.2k tokens, and a symbol index with 589 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!