@aigentic/ruflo 3.7.0-alpha.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +410 -0
- package/bin/ruflo.js +57 -0
- package/package.json +98 -0
- package/src/chat-ui/Dockerfile +25 -0
- package/src/chat-ui/patch-mcp-url-safety.sh +28 -0
- package/src/chat-ui/static/chatui/icon-144x144.png +0 -0
- package/src/chat-ui/static/chatui/omni-welcome.gif +0 -0
- package/src/config/config.example.json +76 -0
- package/src/mcp-bridge/Dockerfile +45 -0
- package/src/mcp-bridge/index.js +1668 -0
- package/src/mcp-bridge/mcp-stdio-kernel.js +159 -0
- package/src/mcp-bridge/package.json +17 -0
- package/src/mcp-bridge/test-harness.js +470 -0
- package/src/nginx/Dockerfile +10 -0
- package/src/nginx/nginx.conf +67 -0
- package/src/nginx/static/favicon-dark.svg +4 -0
- package/src/nginx/static/favicon.svg +4 -0
- package/src/nginx/static/icon.svg +5 -0
- package/src/nginx/static/logo.svg +9 -0
- package/src/nginx/static/manifest.json +22 -0
- package/src/nginx/static/welcome.js +184 -0
- package/src/ruvocal/.claude/skills/add-model-descriptions/SKILL.md +73 -0
- package/src/ruvocal/.devcontainer/Dockerfile +9 -0
- package/src/ruvocal/.devcontainer/devcontainer.json +36 -0
- package/src/ruvocal/.dockerignore +17 -0
- package/src/ruvocal/.eslintignore +13 -0
- package/src/ruvocal/.eslintrc.cjs +45 -0
- package/src/ruvocal/.gcloudignore +18 -0
- package/src/ruvocal/.github/ISSUE_TEMPLATE/bug-report--chat-ui-.md +43 -0
- package/src/ruvocal/.github/ISSUE_TEMPLATE/config-support.md +9 -0
- package/src/ruvocal/.github/ISSUE_TEMPLATE/feature-request--chat-ui-.md +17 -0
- package/src/ruvocal/.github/ISSUE_TEMPLATE/huggingchat.md +11 -0
- package/src/ruvocal/.github/release.yml +16 -0
- package/src/ruvocal/.github/workflows/build-docs.yml +18 -0
- package/src/ruvocal/.github/workflows/build-image.yml +142 -0
- package/src/ruvocal/.github/workflows/build-pr-docs.yml +20 -0
- package/src/ruvocal/.github/workflows/deploy-dev.yml +63 -0
- package/src/ruvocal/.github/workflows/deploy-prod.yml +78 -0
- package/src/ruvocal/.github/workflows/lint-and-test.yml +84 -0
- package/src/ruvocal/.github/workflows/slugify.yaml +72 -0
- package/src/ruvocal/.github/workflows/trufflehog.yml +17 -0
- package/src/ruvocal/.github/workflows/upload-pr-documentation.yml +16 -0
- package/src/ruvocal/.husky/lint-stage-config.js +4 -0
- package/src/ruvocal/.husky/pre-commit +2 -0
- package/src/ruvocal/.prettierignore +14 -0
- package/src/ruvocal/.prettierrc +7 -0
- package/src/ruvocal/CLAUDE.md +126 -0
- package/src/ruvocal/Dockerfile +96 -0
- package/src/ruvocal/LICENSE +203 -0
- package/src/ruvocal/PRIVACY.md +41 -0
- package/src/ruvocal/README.md +164 -0
- package/src/ruvocal/chart/Chart.yaml +5 -0
- package/src/ruvocal/chart/env/dev.yaml +260 -0
- package/src/ruvocal/chart/env/prod.yaml +273 -0
- package/src/ruvocal/chart/templates/_helpers.tpl +22 -0
- package/src/ruvocal/chart/templates/config.yaml +10 -0
- package/src/ruvocal/chart/templates/deployment.yaml +81 -0
- package/src/ruvocal/chart/templates/hpa.yaml +45 -0
- package/src/ruvocal/chart/templates/infisical.yaml +24 -0
- package/src/ruvocal/chart/templates/ingress-internal.yaml +32 -0
- package/src/ruvocal/chart/templates/ingress.yaml +32 -0
- package/src/ruvocal/chart/templates/network-policy.yaml +36 -0
- package/src/ruvocal/chart/templates/service-account.yaml +13 -0
- package/src/ruvocal/chart/templates/service-monitor.yaml +17 -0
- package/src/ruvocal/chart/templates/service.yaml +21 -0
- package/src/ruvocal/chart/values.yaml +73 -0
- package/src/ruvocal/cloudbuild.yaml +68 -0
- package/src/ruvocal/config/branding.env.example +19 -0
- package/src/ruvocal/docker-compose.yml +21 -0
- package/src/ruvocal/docs/adr/ADR-029-HUGGINGFACE-CHAT-UI-CLOUD-RUN.md +1236 -0
- package/src/ruvocal/docs/adr/ADR-033-RUVECTOR-RUFLO-MCP-INTEGRATION.md +111 -0
- package/src/ruvocal/docs/adr/ADR-034-OPTIONAL-MCP-BACKENDS.md +117 -0
- package/src/ruvocal/docs/adr/ADR-035-MCP-TOOL-GROUPS.md +186 -0
- package/src/ruvocal/docs/adr/ADR-037-AUTOPILOT-CHAT-MODE.md +1500 -0
- package/src/ruvocal/docs/adr/ADR-038-RUVOCAL-FORK.md +286 -0
- package/src/ruvocal/docs/source/_toctree.yml +30 -0
- package/src/ruvocal/docs/source/configuration/common-issues.md +38 -0
- package/src/ruvocal/docs/source/configuration/llm-router.md +105 -0
- package/src/ruvocal/docs/source/configuration/mcp-tools.md +84 -0
- package/src/ruvocal/docs/source/configuration/metrics.md +9 -0
- package/src/ruvocal/docs/source/configuration/open-id.md +57 -0
- package/src/ruvocal/docs/source/configuration/overview.md +89 -0
- package/src/ruvocal/docs/source/configuration/theming.md +20 -0
- package/src/ruvocal/docs/source/developing/architecture.md +48 -0
- package/src/ruvocal/docs/source/index.md +53 -0
- package/src/ruvocal/docs/source/installation/docker.md +43 -0
- package/src/ruvocal/docs/source/installation/helm.md +43 -0
- package/src/ruvocal/docs/source/installation/local.md +62 -0
- package/src/ruvocal/entrypoint.sh +19 -0
- package/src/ruvocal/mcp-bridge/Dockerfile +45 -0
- package/src/ruvocal/mcp-bridge/cloudbuild.yaml +49 -0
- package/src/ruvocal/mcp-bridge/index.js +1878 -0
- package/src/ruvocal/mcp-bridge/mcp-stdio-kernel.js +159 -0
- package/src/ruvocal/mcp-bridge/package-lock.json +762 -0
- package/src/ruvocal/mcp-bridge/package.json +17 -0
- package/src/ruvocal/mcp-bridge/test-harness.js +470 -0
- package/src/ruvocal/models/add-your-models-here.txt +1 -0
- package/src/ruvocal/package-lock.json +11741 -0
- package/src/ruvocal/package.json +121 -0
- package/src/ruvocal/postcss.config.js +6 -0
- package/src/ruvocal/rvf.manifest.json +204 -0
- package/src/ruvocal/scripts/config.ts +64 -0
- package/src/ruvocal/scripts/generate-welcome.mjs +181 -0
- package/src/ruvocal/scripts/populate.ts +288 -0
- package/src/ruvocal/scripts/samples.txt +194 -0
- package/src/ruvocal/scripts/setups/vitest-setup-client.ts +0 -0
- package/src/ruvocal/scripts/setups/vitest-setup-server.ts +44 -0
- package/src/ruvocal/scripts/updateLocalEnv.ts +48 -0
- package/src/ruvocal/src/ambient.d.ts +7 -0
- package/src/ruvocal/src/app.d.ts +29 -0
- package/src/ruvocal/src/app.html +53 -0
- package/src/ruvocal/src/hooks.server.ts +32 -0
- package/src/ruvocal/src/hooks.ts +6 -0
- package/src/ruvocal/src/lib/APIClient.ts +148 -0
- package/src/ruvocal/src/lib/actions/clickOutside.ts +18 -0
- package/src/ruvocal/src/lib/actions/snapScrollToBottom.ts +346 -0
- package/src/ruvocal/src/lib/buildPrompt.ts +33 -0
- package/src/ruvocal/src/lib/components/AnnouncementBanner.svelte +20 -0
- package/src/ruvocal/src/lib/components/BackgroundGenerationPoller.svelte +168 -0
- package/src/ruvocal/src/lib/components/CodeBlock.svelte +73 -0
- package/src/ruvocal/src/lib/components/CopyToClipBoardBtn.svelte +92 -0
- package/src/ruvocal/src/lib/components/DeleteConversationModal.svelte +75 -0
- package/src/ruvocal/src/lib/components/EditConversationModal.svelte +100 -0
- package/src/ruvocal/src/lib/components/ExpandNavigation.svelte +22 -0
- package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -0
- package/src/ruvocal/src/lib/components/HoverTooltip.svelte +44 -0
- package/src/ruvocal/src/lib/components/HtmlPreviewModal.svelte +143 -0
- package/src/ruvocal/src/lib/components/InfiniteScroll.svelte +50 -0
- package/src/ruvocal/src/lib/components/MobileNav.svelte +300 -0
- package/src/ruvocal/src/lib/components/Modal.svelte +115 -0
- package/src/ruvocal/src/lib/components/ModelCardMetadata.svelte +71 -0
- package/src/ruvocal/src/lib/components/NavConversationItem.svelte +151 -0
- package/src/ruvocal/src/lib/components/NavMenu.svelte +313 -0
- package/src/ruvocal/src/lib/components/Pagination.svelte +97 -0
- package/src/ruvocal/src/lib/components/PaginationArrow.svelte +27 -0
- package/src/ruvocal/src/lib/components/Portal.svelte +24 -0
- package/src/ruvocal/src/lib/components/RetryBtn.svelte +18 -0
- package/src/ruvocal/src/lib/components/RuFloUniverse.svelte +185 -0
- package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -0
- package/src/ruvocal/src/lib/components/ScrollToBottomBtn.svelte +47 -0
- package/src/ruvocal/src/lib/components/ScrollToPreviousBtn.svelte +77 -0
- package/src/ruvocal/src/lib/components/ShareConversationModal.svelte +182 -0
- package/src/ruvocal/src/lib/components/StopGeneratingBtn.svelte +69 -0
- package/src/ruvocal/src/lib/components/SubscribeModal.svelte +87 -0
- package/src/ruvocal/src/lib/components/Switch.svelte +36 -0
- package/src/ruvocal/src/lib/components/SystemPromptModal.svelte +44 -0
- package/src/ruvocal/src/lib/components/Toast.svelte +27 -0
- package/src/ruvocal/src/lib/components/Tooltip.svelte +30 -0
- package/src/ruvocal/src/lib/components/WelcomeModal.svelte +46 -0
- package/src/ruvocal/src/lib/components/chat/Alternatives.svelte +77 -0
- package/src/ruvocal/src/lib/components/chat/BlockWrapper.svelte +72 -0
- package/src/ruvocal/src/lib/components/chat/ChatInput.svelte +490 -0
- package/src/ruvocal/src/lib/components/chat/ChatIntroduction.svelte +123 -0
- package/src/ruvocal/src/lib/components/chat/ChatMessage.svelte +548 -0
- package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +1057 -0
- package/src/ruvocal/src/lib/components/chat/FileDropzone.svelte +92 -0
- package/src/ruvocal/src/lib/components/chat/ImageLightbox.svelte +66 -0
- package/src/ruvocal/src/lib/components/chat/MarkdownBlock.svelte +23 -0
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte +69 -0
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte.test.ts +58 -0
- package/src/ruvocal/src/lib/components/chat/MessageAvatar.svelte +103 -0
- package/src/ruvocal/src/lib/components/chat/ModelSwitch.svelte +64 -0
- package/src/ruvocal/src/lib/components/chat/OpenReasoningResults.svelte +81 -0
- package/src/ruvocal/src/lib/components/chat/TaskGroup.svelte +88 -0
- package/src/ruvocal/src/lib/components/chat/ToolUpdate.svelte +273 -0
- package/src/ruvocal/src/lib/components/chat/UploadedFile.svelte +253 -0
- package/src/ruvocal/src/lib/components/chat/UrlFetchModal.svelte +203 -0
- package/src/ruvocal/src/lib/components/chat/VoiceRecorder.svelte +214 -0
- package/src/ruvocal/src/lib/components/icons/IconBurger.svelte +20 -0
- package/src/ruvocal/src/lib/components/icons/IconCheap.svelte +20 -0
- package/src/ruvocal/src/lib/components/icons/IconChevron.svelte +24 -0
- package/src/ruvocal/src/lib/components/icons/IconDazzled.svelte +40 -0
- package/src/ruvocal/src/lib/components/icons/IconFast.svelte +20 -0
- package/src/ruvocal/src/lib/components/icons/IconLoading.svelte +22 -0
- package/src/ruvocal/src/lib/components/icons/IconMCP.svelte +28 -0
- package/src/ruvocal/src/lib/components/icons/IconMoon.svelte +21 -0
- package/src/ruvocal/src/lib/components/icons/IconNew.svelte +20 -0
- package/src/ruvocal/src/lib/components/icons/IconOmni.svelte +90 -0
- package/src/ruvocal/src/lib/components/icons/IconPaperclip.svelte +24 -0
- package/src/ruvocal/src/lib/components/icons/IconPro.svelte +37 -0
- package/src/ruvocal/src/lib/components/icons/IconShare.svelte +21 -0
- package/src/ruvocal/src/lib/components/icons/IconSun.svelte +93 -0
- package/src/ruvocal/src/lib/components/icons/Logo.svelte +68 -0
- package/src/ruvocal/src/lib/components/icons/LogoHuggingFaceBorderless.svelte +54 -0
- package/src/ruvocal/src/lib/components/mcp/AddServerForm.svelte +250 -0
- package/src/ruvocal/src/lib/components/mcp/MCPServerManager.svelte +185 -0
- package/src/ruvocal/src/lib/components/mcp/ServerCard.svelte +203 -0
- package/src/ruvocal/src/lib/components/players/AudioPlayer.svelte +82 -0
- package/src/ruvocal/src/lib/components/voice/AudioWaveform.svelte +96 -0
- package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -0
- package/src/ruvocal/src/lib/constants/mcpExamples.ts +114 -0
- package/src/ruvocal/src/lib/constants/mime.ts +11 -0
- package/src/ruvocal/src/lib/constants/pagination.ts +1 -0
- package/src/ruvocal/src/lib/constants/publicSepToken.ts +1 -0
- package/src/ruvocal/src/lib/constants/routerExamples.ts +133 -0
- package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -0
- package/src/ruvocal/src/lib/createShareLink.ts +27 -0
- package/src/ruvocal/src/lib/jobs/refresh-conversation-stats.ts +297 -0
- package/src/ruvocal/src/lib/migrations/lock.ts +56 -0
- package/src/ruvocal/src/lib/migrations/migrations.spec.ts +74 -0
- package/src/ruvocal/src/lib/migrations/migrations.ts +109 -0
- package/src/ruvocal/src/lib/migrations/routines/01-update-search-assistants.ts +50 -0
- package/src/ruvocal/src/lib/migrations/routines/02-update-assistants-models.ts +48 -0
- package/src/ruvocal/src/lib/migrations/routines/04-update-message-updates.ts +151 -0
- package/src/ruvocal/src/lib/migrations/routines/05-update-message-files.ts +56 -0
- package/src/ruvocal/src/lib/migrations/routines/06-trim-message-updates.ts +56 -0
- package/src/ruvocal/src/lib/migrations/routines/08-update-featured-to-review.ts +32 -0
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.spec.ts +214 -0
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.ts +88 -0
- package/src/ruvocal/src/lib/migrations/routines/10-update-reports-assistantid.ts +29 -0
- package/src/ruvocal/src/lib/migrations/routines/index.ts +15 -0
- package/src/ruvocal/src/lib/server/__tests__/conversation-stop-generating.spec.ts +103 -0
- package/src/ruvocal/src/lib/server/abortRegistry.ts +57 -0
- package/src/ruvocal/src/lib/server/abortedGenerations.ts +43 -0
- package/src/ruvocal/src/lib/server/adminToken.ts +62 -0
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-id.spec.ts +296 -0
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-message.spec.ts +216 -0
- package/src/ruvocal/src/lib/server/api/__tests__/conversations.spec.ts +235 -0
- package/src/ruvocal/src/lib/server/api/__tests__/misc.spec.ts +72 -0
- package/src/ruvocal/src/lib/server/api/__tests__/testHelpers.ts +86 -0
- package/src/ruvocal/src/lib/server/api/__tests__/user-reports.spec.ts +78 -0
- package/src/ruvocal/src/lib/server/api/__tests__/user.spec.ts +239 -0
- package/src/ruvocal/src/lib/server/api/types.ts +37 -0
- package/src/ruvocal/src/lib/server/api/utils/requireAuth.ts +22 -0
- package/src/ruvocal/src/lib/server/api/utils/resolveConversation.ts +69 -0
- package/src/ruvocal/src/lib/server/api/utils/resolveModel.ts +27 -0
- package/src/ruvocal/src/lib/server/api/utils/superjsonResponse.ts +15 -0
- package/src/ruvocal/src/lib/server/apiToken.ts +11 -0
- package/src/ruvocal/src/lib/server/auth.ts +554 -0
- package/src/ruvocal/src/lib/server/config.ts +187 -0
- package/src/ruvocal/src/lib/server/conversation.ts +83 -0
- package/src/ruvocal/src/lib/server/database/__tests__/rvf.spec.ts +709 -0
- package/src/ruvocal/src/lib/server/database/postgres.ts +700 -0
- package/src/ruvocal/src/lib/server/database/rvf.ts +1078 -0
- package/src/ruvocal/src/lib/server/database.ts +145 -0
- package/src/ruvocal/src/lib/server/endpoints/document.ts +68 -0
- package/src/ruvocal/src/lib/server/endpoints/endpoints.ts +43 -0
- package/src/ruvocal/src/lib/server/endpoints/images.ts +211 -0
- package/src/ruvocal/src/lib/server/endpoints/openai/endpointOai.ts +266 -0
- package/src/ruvocal/src/lib/server/endpoints/openai/openAIChatToTextGenerationStream.ts +212 -0
- package/src/ruvocal/src/lib/server/endpoints/openai/openAICompletionToTextGenerationStream.ts +32 -0
- package/src/ruvocal/src/lib/server/endpoints/preprocessMessages.ts +61 -0
- package/src/ruvocal/src/lib/server/exitHandler.ts +59 -0
- package/src/ruvocal/src/lib/server/files/downloadFile.ts +34 -0
- package/src/ruvocal/src/lib/server/files/uploadFile.ts +29 -0
- package/src/ruvocal/src/lib/server/findRepoRoot.ts +13 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Black.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Bold.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-ExtraBold.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-ExtraLight.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Light.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Medium.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Regular.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-SemiBold.ttf +0 -0
- package/src/ruvocal/src/lib/server/fonts/Inter-Thin.ttf +0 -0
- package/src/ruvocal/src/lib/server/generateFromDefaultEndpoint.ts +46 -0
- package/src/ruvocal/src/lib/server/hooks/error.ts +37 -0
- package/src/ruvocal/src/lib/server/hooks/fetch.ts +22 -0
- package/src/ruvocal/src/lib/server/hooks/handle.ts +250 -0
- package/src/ruvocal/src/lib/server/hooks/init.ts +51 -0
- package/src/ruvocal/src/lib/server/isURLLocal.spec.ts +31 -0
- package/src/ruvocal/src/lib/server/isURLLocal.ts +74 -0
- package/src/ruvocal/src/lib/server/logger.ts +42 -0
- package/src/ruvocal/src/lib/server/mcp/clientPool.spec.ts +175 -0
- package/src/ruvocal/src/lib/server/mcp/clientPool.ts +0 -0
- package/src/ruvocal/src/lib/server/mcp/hf.ts +32 -0
- package/src/ruvocal/src/lib/server/mcp/httpClient.ts +122 -0
- package/src/ruvocal/src/lib/server/mcp/registry.ts +76 -0
- package/src/ruvocal/src/lib/server/mcp/tools.ts +196 -0
- package/src/ruvocal/src/lib/server/metrics.ts +255 -0
- package/src/ruvocal/src/lib/server/models.ts +518 -0
- package/src/ruvocal/src/lib/server/requestContext.ts +55 -0
- package/src/ruvocal/src/lib/server/router/arch.ts +230 -0
- package/src/ruvocal/src/lib/server/router/endpoint.ts +316 -0
- package/src/ruvocal/src/lib/server/router/multimodal.ts +28 -0
- package/src/ruvocal/src/lib/server/router/policy.ts +49 -0
- package/src/ruvocal/src/lib/server/router/toolsRoute.ts +51 -0
- package/src/ruvocal/src/lib/server/router/types.ts +21 -0
- package/src/ruvocal/src/lib/server/sendSlack.ts +23 -0
- package/src/ruvocal/src/lib/server/textGeneration/generate.ts +258 -0
- package/src/ruvocal/src/lib/server/textGeneration/index.ts +96 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/fileRefs.ts +155 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/routerResolution.ts +108 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/runMcpFlow.ts +831 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/toolInvocation.ts +349 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -0
- package/src/ruvocal/src/lib/server/textGeneration/reasoning.ts +23 -0
- package/src/ruvocal/src/lib/server/textGeneration/title.ts +83 -0
- package/src/ruvocal/src/lib/server/textGeneration/types.ts +28 -0
- package/src/ruvocal/src/lib/server/textGeneration/utils/prepareFiles.ts +88 -0
- package/src/ruvocal/src/lib/server/textGeneration/utils/routing.ts +21 -0
- package/src/ruvocal/src/lib/server/textGeneration/utils/toolPrompt.ts +49 -0
- package/src/ruvocal/src/lib/server/urlSafety.ts +77 -0
- package/src/ruvocal/src/lib/server/usageLimits.ts +30 -0
- package/src/ruvocal/src/lib/stores/autopilotStore.svelte.ts +175 -0
- package/src/ruvocal/src/lib/stores/backgroundGenerations.svelte.ts +32 -0
- package/src/ruvocal/src/lib/stores/backgroundGenerations.ts +1 -0
- package/src/ruvocal/src/lib/stores/errors.ts +9 -0
- package/src/ruvocal/src/lib/stores/isAborted.ts +3 -0
- package/src/ruvocal/src/lib/stores/isPro.ts +4 -0
- package/src/ruvocal/src/lib/stores/loading.ts +3 -0
- package/src/ruvocal/src/lib/stores/mcpServers.ts +534 -0
- package/src/ruvocal/src/lib/stores/pendingChatInput.ts +3 -0
- package/src/ruvocal/src/lib/stores/pendingMessage.ts +9 -0
- package/src/ruvocal/src/lib/stores/settings.ts +182 -0
- package/src/ruvocal/src/lib/stores/shareModal.ts +13 -0
- package/src/ruvocal/src/lib/stores/titleUpdate.ts +8 -0
- package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -0
- package/src/ruvocal/src/lib/switchTheme.ts +124 -0
- package/src/ruvocal/src/lib/types/AbortedGeneration.ts +8 -0
- package/src/ruvocal/src/lib/types/Assistant.ts +31 -0
- package/src/ruvocal/src/lib/types/AssistantStats.ts +11 -0
- package/src/ruvocal/src/lib/types/ConfigKey.ts +4 -0
- package/src/ruvocal/src/lib/types/ConvSidebar.ts +9 -0
- package/src/ruvocal/src/lib/types/Conversation.ts +27 -0
- package/src/ruvocal/src/lib/types/ConversationStats.ts +13 -0
- package/src/ruvocal/src/lib/types/Message.ts +41 -0
- package/src/ruvocal/src/lib/types/MessageEvent.ts +10 -0
- package/src/ruvocal/src/lib/types/MessageUpdate.ts +139 -0
- package/src/ruvocal/src/lib/types/MigrationResult.ts +7 -0
- package/src/ruvocal/src/lib/types/Model.ts +23 -0
- package/src/ruvocal/src/lib/types/Report.ts +12 -0
- package/src/ruvocal/src/lib/types/Review.ts +6 -0
- package/src/ruvocal/src/lib/types/Semaphore.ts +19 -0
- package/src/ruvocal/src/lib/types/Session.ts +22 -0
- package/src/ruvocal/src/lib/types/Settings.ts +93 -0
- package/src/ruvocal/src/lib/types/SharedConversation.ts +9 -0
- package/src/ruvocal/src/lib/types/Template.ts +6 -0
- package/src/ruvocal/src/lib/types/Timestamps.ts +4 -0
- package/src/ruvocal/src/lib/types/TokenCache.ts +6 -0
- package/src/ruvocal/src/lib/types/Tool.ts +77 -0
- package/src/ruvocal/src/lib/types/UrlDependency.ts +5 -0
- package/src/ruvocal/src/lib/types/User.ts +14 -0
- package/src/ruvocal/src/lib/utils/PublicConfig.svelte.ts +75 -0
- package/src/ruvocal/src/lib/utils/auth.ts +17 -0
- package/src/ruvocal/src/lib/utils/chunk.ts +33 -0
- package/src/ruvocal/src/lib/utils/cookiesAreEnabled.ts +13 -0
- package/src/ruvocal/src/lib/utils/debounce.ts +17 -0
- package/src/ruvocal/src/lib/utils/deepestChild.ts +6 -0
- package/src/ruvocal/src/lib/utils/favicon.ts +21 -0
- package/src/ruvocal/src/lib/utils/fetchJSON.ts +23 -0
- package/src/ruvocal/src/lib/utils/file2base64.ts +14 -0
- package/src/ruvocal/src/lib/utils/formatUserCount.ts +37 -0
- package/src/ruvocal/src/lib/utils/generationState.spec.ts +75 -0
- package/src/ruvocal/src/lib/utils/generationState.ts +26 -0
- package/src/ruvocal/src/lib/utils/getHref.ts +41 -0
- package/src/ruvocal/src/lib/utils/getReturnFromGenerator.ts +7 -0
- package/src/ruvocal/src/lib/utils/haptics.ts +64 -0
- package/src/ruvocal/src/lib/utils/hashConv.ts +12 -0
- package/src/ruvocal/src/lib/utils/hf.ts +17 -0
- package/src/ruvocal/src/lib/utils/isDesktop.ts +7 -0
- package/src/ruvocal/src/lib/utils/isUrl.ts +8 -0
- package/src/ruvocal/src/lib/utils/isVirtualKeyboard.ts +16 -0
- package/src/ruvocal/src/lib/utils/loadAttachmentsFromUrls.ts +115 -0
- package/src/ruvocal/src/lib/utils/marked.spec.ts +96 -0
- package/src/ruvocal/src/lib/utils/marked.ts +531 -0
- package/src/ruvocal/src/lib/utils/mcpValidation.ts +147 -0
- package/src/ruvocal/src/lib/utils/mergeAsyncGenerators.ts +38 -0
- package/src/ruvocal/src/lib/utils/messageUpdates.spec.ts +262 -0
- package/src/ruvocal/src/lib/utils/messageUpdates.ts +324 -0
- package/src/ruvocal/src/lib/utils/mime.ts +56 -0
- package/src/ruvocal/src/lib/utils/models.ts +14 -0
- package/src/ruvocal/src/lib/utils/parseBlocks.ts +120 -0
- package/src/ruvocal/src/lib/utils/parseIncompleteMarkdown.ts +644 -0
- package/src/ruvocal/src/lib/utils/parseStringToList.ts +10 -0
- package/src/ruvocal/src/lib/utils/randomUuid.ts +14 -0
- package/src/ruvocal/src/lib/utils/searchTokens.ts +33 -0
- package/src/ruvocal/src/lib/utils/sha256.ts +7 -0
- package/src/ruvocal/src/lib/utils/stringifyError.ts +12 -0
- package/src/ruvocal/src/lib/utils/sum.ts +3 -0
- package/src/ruvocal/src/lib/utils/template.spec.ts +59 -0
- package/src/ruvocal/src/lib/utils/template.ts +53 -0
- package/src/ruvocal/src/lib/utils/timeout.ts +9 -0
- package/src/ruvocal/src/lib/utils/toolProgress.spec.ts +46 -0
- package/src/ruvocal/src/lib/utils/toolProgress.ts +11 -0
- package/src/ruvocal/src/lib/utils/tree/addChildren.spec.ts +102 -0
- package/src/ruvocal/src/lib/utils/tree/addChildren.ts +48 -0
- package/src/ruvocal/src/lib/utils/tree/addSibling.spec.ts +81 -0
- package/src/ruvocal/src/lib/utils/tree/addSibling.ts +41 -0
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.spec.ts +110 -0
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.ts +24 -0
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.spec.ts +31 -0
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.ts +36 -0
- package/src/ruvocal/src/lib/utils/tree/isMessageId.spec.ts +15 -0
- package/src/ruvocal/src/lib/utils/tree/isMessageId.ts +5 -0
- package/src/ruvocal/src/lib/utils/tree/tree.d.ts +14 -0
- package/src/ruvocal/src/lib/utils/tree/treeHelpers.spec.ts +167 -0
- package/src/ruvocal/src/lib/utils/updates.ts +39 -0
- package/src/ruvocal/src/lib/utils/urlParams.ts +13 -0
- package/src/ruvocal/src/lib/wasm/idb.ts +438 -0
- package/src/ruvocal/src/lib/wasm/index.ts +1213 -0
- package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -0
- package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -0
- package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -0
- package/src/ruvocal/src/lib/workers/autopilotWorker.ts +221 -0
- package/src/ruvocal/src/lib/workers/detailFetchWorker.ts +100 -0
- package/src/ruvocal/src/lib/workers/markdownWorker.ts +61 -0
- package/src/ruvocal/src/routes/+error.svelte +20 -0
- package/src/ruvocal/src/routes/+layout.svelte +324 -0
- package/src/ruvocal/src/routes/+layout.ts +91 -0
- package/src/ruvocal/src/routes/+page.svelte +168 -0
- package/src/ruvocal/src/routes/.well-known/oauth-cimd/+server.ts +37 -0
- package/src/ruvocal/src/routes/__debug/openai/+server.ts +21 -0
- package/src/ruvocal/src/routes/admin/export/+server.ts +159 -0
- package/src/ruvocal/src/routes/admin/stats/compute/+server.ts +16 -0
- package/src/ruvocal/src/routes/api/conversation/[id]/+server.ts +40 -0
- package/src/ruvocal/src/routes/api/conversation/[id]/message/[messageId]/+server.ts +42 -0
- package/src/ruvocal/src/routes/api/conversations/+server.ts +48 -0
- package/src/ruvocal/src/routes/api/fetch-url/+server.ts +147 -0
- package/src/ruvocal/src/routes/api/mcp/health/+server.ts +292 -0
- package/src/ruvocal/src/routes/api/mcp/servers/+server.ts +32 -0
- package/src/ruvocal/src/routes/api/models/+server.ts +25 -0
- package/src/ruvocal/src/routes/api/transcribe/+server.ts +104 -0
- package/src/ruvocal/src/routes/api/user/+server.ts +15 -0
- package/src/ruvocal/src/routes/api/user/validate-token/+server.ts +20 -0
- package/src/ruvocal/src/routes/api/v2/conversations/+server.ts +48 -0
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/+server.ts +94 -0
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/message/[messageId]/+server.ts +43 -0
- package/src/ruvocal/src/routes/api/v2/conversations/import-share/+server.ts +23 -0
- package/src/ruvocal/src/routes/api/v2/debug/config/+server.ts +16 -0
- package/src/ruvocal/src/routes/api/v2/debug/refresh/+server.ts +30 -0
- package/src/ruvocal/src/routes/api/v2/export/+server.ts +196 -0
- package/src/ruvocal/src/routes/api/v2/feature-flags/+server.ts +14 -0
- package/src/ruvocal/src/routes/api/v2/models/+server.ts +38 -0
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/+server.ts +8 -0
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/+server.ts +8 -0
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/subscribe/+server.ts +28 -0
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/subscribe/+server.ts +28 -0
- package/src/ruvocal/src/routes/api/v2/models/old/+server.ts +7 -0
- package/src/ruvocal/src/routes/api/v2/models/refresh/+server.ts +33 -0
- package/src/ruvocal/src/routes/api/v2/public-config/+server.ts +7 -0
- package/src/ruvocal/src/routes/api/v2/user/+server.ts +17 -0
- package/src/ruvocal/src/routes/api/v2/user/billing-orgs/+server.ts +73 -0
- package/src/ruvocal/src/routes/api/v2/user/reports/+server.ts +17 -0
- package/src/ruvocal/src/routes/api/v2/user/settings/+server.ts +110 -0
- package/src/ruvocal/src/routes/conversation/+server.ts +115 -0
- package/src/ruvocal/src/routes/conversation/[id]/+page.svelte +586 -0
- package/src/ruvocal/src/routes/conversation/[id]/+page.ts +60 -0
- package/src/ruvocal/src/routes/conversation/[id]/+server.ts +740 -0
- package/src/ruvocal/src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +66 -0
- package/src/ruvocal/src/routes/conversation/[id]/share/+server.ts +69 -0
- package/src/ruvocal/src/routes/conversation/[id]/stop-generating/+server.ts +35 -0
- package/src/ruvocal/src/routes/healthcheck/+server.ts +3 -0
- package/src/ruvocal/src/routes/login/+server.ts +5 -0
- package/src/ruvocal/src/routes/login/callback/+server.ts +103 -0
- package/src/ruvocal/src/routes/login/callback/updateUser.spec.ts +157 -0
- package/src/ruvocal/src/routes/login/callback/updateUser.ts +215 -0
- package/src/ruvocal/src/routes/logout/+server.ts +18 -0
- package/src/ruvocal/src/routes/metrics/+server.ts +18 -0
- package/src/ruvocal/src/routes/models/+page.svelte +233 -0
- package/src/ruvocal/src/routes/models/[...model]/+page.svelte +161 -0
- package/src/ruvocal/src/routes/models/[...model]/+page.ts +14 -0
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/+server.ts +64 -0
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/ModelThumbnail.svelte +28 -0
- package/src/ruvocal/src/routes/privacy/+page.svelte +11 -0
- package/src/ruvocal/src/routes/r/[id]/+page.ts +34 -0
- package/src/ruvocal/src/routes/settings/(nav)/+layout.svelte +282 -0
- package/src/ruvocal/src/routes/settings/(nav)/+layout.ts +1 -0
- package/src/ruvocal/src/routes/settings/(nav)/+page.svelte +0 -0
- package/src/ruvocal/src/routes/settings/(nav)/+server.ts +59 -0
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.svelte +464 -0
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.ts +14 -0
- package/src/ruvocal/src/routes/settings/(nav)/application/+page.svelte +362 -0
- package/src/ruvocal/src/routes/settings/+layout.svelte +40 -0
- package/src/ruvocal/src/styles/highlight-js.css +195 -0
- package/src/ruvocal/src/styles/main.css +144 -0
- package/src/ruvocal/static/chatui/apple-touch-icon.png +0 -0
- package/src/ruvocal/static/chatui/favicon-dark.svg +3 -0
- package/src/ruvocal/static/chatui/favicon-dev.svg +3 -0
- package/src/ruvocal/static/chatui/favicon.ico +0 -0
- package/src/ruvocal/static/chatui/favicon.svg +3 -0
- package/src/ruvocal/static/chatui/icon-128x128.png +0 -0
- package/src/ruvocal/static/chatui/icon-144x144.png +0 -0
- package/src/ruvocal/static/chatui/icon-192x192.png +0 -0
- package/src/ruvocal/static/chatui/icon-256x256.png +0 -0
- package/src/ruvocal/static/chatui/icon-36x36.png +0 -0
- package/src/ruvocal/static/chatui/icon-48x48.png +0 -0
- package/src/ruvocal/static/chatui/icon-512x512.png +0 -0
- package/src/ruvocal/static/chatui/icon-72x72.png +0 -0
- package/src/ruvocal/static/chatui/icon-96x96.png +0 -0
- package/src/ruvocal/static/chatui/icon.svg +3 -0
- package/src/ruvocal/static/chatui/logo.svg +7 -0
- package/src/ruvocal/static/chatui/manifest.json +54 -0
- package/src/ruvocal/static/chatui/omni-welcome.gif +0 -0
- package/src/ruvocal/static/chatui/omni-welcome.png +0 -0
- package/src/ruvocal/static/chatui/welcome.js +184 -0
- package/src/ruvocal/static/chatui/welcome.svg +1 -0
- package/src/ruvocal/static/huggingchat/apple-touch-icon.png +0 -0
- package/src/ruvocal/static/huggingchat/assistants-thumbnail.png +0 -0
- package/src/ruvocal/static/huggingchat/castle-example.jpg +0 -0
- package/src/ruvocal/static/huggingchat/favicon-dark.svg +4 -0
- package/src/ruvocal/static/huggingchat/favicon-dev.svg +4 -0
- package/src/ruvocal/static/huggingchat/favicon.ico +0 -0
- package/src/ruvocal/static/huggingchat/favicon.svg +4 -0
- package/src/ruvocal/static/huggingchat/fulltext-logo.svg +2 -0
- package/src/ruvocal/static/huggingchat/icon-128x128.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-144x144.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-192x192.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-256x256.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-36x36.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-48x48.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-512x512.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-72x72.png +0 -0
- package/src/ruvocal/static/huggingchat/icon-96x96.png +0 -0
- package/src/ruvocal/static/huggingchat/icon.svg +4 -0
- package/src/ruvocal/static/huggingchat/logo.svg +4 -0
- package/src/ruvocal/static/huggingchat/manifest.json +54 -0
- package/src/ruvocal/static/huggingchat/omni-welcome.gif +0 -0
- package/src/ruvocal/static/huggingchat/routes.chat.json +226 -0
- package/src/ruvocal/static/huggingchat/thumbnail.png +0 -0
- package/src/ruvocal/static/huggingchat/tools-thumbnail.png +0 -0
- package/src/ruvocal/static/robots.txt +10 -0
- package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -0
- package/src/ruvocal/static/wasm/rvagent_wasm_bg.wasm +0 -0
- package/src/ruvocal/stub/@reflink/reflink/index.js +0 -0
- package/src/ruvocal/stub/@reflink/reflink/package.json +5 -0
- package/src/ruvocal/svelte.config.js +53 -0
- package/src/ruvocal/tailwind.config.cjs +30 -0
- package/src/ruvocal/tsconfig.json +19 -0
- package/src/ruvocal/vite.config.ts +87 -0
- package/src/scripts/deploy.sh +116 -0
- package/src/scripts/generate-config.js +245 -0
- package/src/scripts/generate-welcome.js +187 -0
- package/src/scripts/package-rvf.sh +116 -0
|
@@ -0,0 +1,1236 @@
|
|
|
1
|
+
# ADR-029: HuggingFace Chat UI on Cloud Run — chat.conveyorclaims.ai
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Implemented (2026-02-26), Updated (2026-03-04)
|
|
5
|
+
|
|
6
|
+
## Date
|
|
7
|
+
2026-02-26
|
|
8
|
+
|
|
9
|
+
## Deployed Services
|
|
10
|
+
|
|
11
|
+
| Service | URL | Status |
|
|
12
|
+
|---------|-----|--------|
|
|
13
|
+
| **HF Chat UI** | https://hf-chat-ui-245235083640.us-central1.run.app | Live |
|
|
14
|
+
| **Custom Domain** | https://chat.conveyorclaims.ai | Live (SSL: Google Trust Services) |
|
|
15
|
+
| **MCP Bridge** | https://mcp-bridge-hwqrrwrlna-uc.a.run.app | Live (5 tools) |
|
|
16
|
+
|
|
17
|
+
## Context
|
|
18
|
+
|
|
19
|
+
The current chat system (`extensions-cloudrun/apps/chat-system`) is a custom React + Vite SPA backed by Gemini. While it serves internal workflow needs well (ADR-014, ADR-024, ADR-027), we need a **production-grade, multi-model chat interface** at `chat.conveyorclaims.ai` that:
|
|
20
|
+
|
|
21
|
+
1. Exposes **GPT-5 family models** (gpt-5, gpt-5-mini, gpt-5-nano, gpt-5-pro, gpt-5.1, gpt-5.2) plus multi-provider models (Google Gemini, Anthropic Claude) using **existing Google Secret Manager keys**
|
|
22
|
+
2. Integrates with **existing Cloud Functions** (airtable-agent, db-query-agent, simulation-agent, case-manager, workflow-search) via MCP tool calling
|
|
23
|
+
3. Connects to **ruvector-postgres** (10.128.0.2) for vector search over workflow documents (384d all-MiniLM-L6-v2 embeddings, 311 chunks) — all tool/data operations go through PostgreSQL, NOT MongoDB
|
|
24
|
+
4. Provides conversation persistence, authentication, and a polished UI out of the box
|
|
25
|
+
5. Deploys as a new Cloud Run service alongside the existing chat-system — no disruption
|
|
26
|
+
|
|
27
|
+
### Database Strategy: Hybrid PostgreSQL + MongoDB
|
|
28
|
+
|
|
29
|
+
HuggingFace Chat UI **requires MongoDB** for its internal persistence layer (conversations, users, sessions, assistants). This cannot be swapped for PostgreSQL without forking the project. However, **all business data and tool operations** route through ruvector-postgres via the MCP Bridge:
|
|
30
|
+
|
|
31
|
+
| Layer | Database | Purpose |
|
|
32
|
+
|-------|----------|---------|
|
|
33
|
+
| **Chat UI internals** | MongoDB (lightweight sidecar or Atlas free tier) | Conversations, user sessions, assistant configs |
|
|
34
|
+
| **Business data & tools** | ruvector-postgres (10.128.0.2) | Workflow search, case data, analytics, embeddings |
|
|
35
|
+
| **AI provider keys** | Google Secret Manager | `openai-api-key`, `anthropic-api-key`, `google-api-key` |
|
|
36
|
+
|
|
37
|
+
MongoDB handles only what Chat UI needs internally. All the **real work** — workflow search, case management, analytics, simulations — flows through the existing ruvector-postgres via MCP tools. The MongoDB instance can run as a sidecar container on the same Cloud Run service using the bundled `chat-ui-db` image, requiring **zero additional infrastructure**.
|
|
38
|
+
|
|
39
|
+
### Multi-Provider Strategy via Google Secret Manager
|
|
40
|
+
|
|
41
|
+
All AI provider API keys already exist in Google Secret Manager (ADR-004). Chat UI will pull these at runtime:
|
|
42
|
+
|
|
43
|
+
| Secret ID | Provider | Models |
|
|
44
|
+
|-----------|----------|--------|
|
|
45
|
+
| `openai-api-key` | OpenAI | GPT-5.2, GPT-5, GPT-5-mini, GPT-5-nano, GPT-4o, o3 |
|
|
46
|
+
| `anthropic-api-key` | Anthropic | Claude (when credits refilled) |
|
|
47
|
+
| `google-api-key` | Google | Gemini 2.5 Pro/Flash (when key renewed) |
|
|
48
|
+
|
|
49
|
+
### Why HuggingFace Chat UI
|
|
50
|
+
|
|
51
|
+
[HuggingFace Chat UI](https://github.com/huggingface/chat-ui) (Apache 2.0, 10,400+ GitHub stars) is the open-source codebase powering HuggingChat. It provides:
|
|
52
|
+
|
|
53
|
+
- **Native OpenAI-compatible API support** — connects directly to `api.openai.com/v1`, auto-discovers all available models
|
|
54
|
+
- **MCP (Model Context Protocol) tool calling** — exposes external APIs as callable tools from within chat
|
|
55
|
+
- **Multi-model selector** — users pick from GPT-5, GPT-5-mini, GPT-4o, etc. in a dropdown
|
|
56
|
+
- **Smart routing ("Omni")** — auto-selects the best model per query
|
|
57
|
+
- **Built-in web search + RAG** — retrieval-augmented generation with search grounding
|
|
58
|
+
- **MongoDB-backed persistence** — conversation history, user sessions, assistants (bundled sidecar option eliminates external dependency)
|
|
59
|
+
- **OpenID Connect auth** — Google OAuth integration
|
|
60
|
+
- **SvelteKit SSR** — fast, server-rendered UI with streaming responses
|
|
61
|
+
- **Docker-ready** — pre-built images at `ghcr.io/huggingface/chat-ui`
|
|
62
|
+
- **Whisper voice transcription** — speech-to-text input
|
|
63
|
+
|
|
64
|
+
This eliminates months of custom UI development while providing a superior chat experience.
|
|
65
|
+
|
|
66
|
+
### Why NOT Modify the Existing Chat System
|
|
67
|
+
|
|
68
|
+
| Factor | Existing Chat System | HuggingFace Chat UI |
|
|
69
|
+
|--------|---------------------|-------------------|
|
|
70
|
+
| AI Provider | Gemini-only (tightly coupled) | Any OpenAI-compatible API |
|
|
71
|
+
| Model switching | None (ADR-028 proposes abstraction) | Built-in multi-model selector |
|
|
72
|
+
| Conversation persistence | LocalStorage only | MongoDB sidecar + ruvector-postgres for tools |
|
|
73
|
+
| Tool calling | Custom FunctionExecutor | MCP standard protocol |
|
|
74
|
+
| Authentication | Custom Google OAuth | OpenID Connect (standard) |
|
|
75
|
+
| Voice input | None | Whisper transcription |
|
|
76
|
+
| Web search | None | Built-in RAG |
|
|
77
|
+
| Maintenance burden | Custom React/Vite SPA | Community-maintained OSS |
|
|
78
|
+
|
|
79
|
+
The existing chat system continues serving its current role. This ADR creates a **parallel, GPT-5-powered interface** at a separate domain.
|
|
80
|
+
|
|
81
|
+
## Decision
|
|
82
|
+
|
|
83
|
+
Deploy HuggingFace Chat UI as a new Cloud Run service (`hf-chat-ui`) with:
|
|
84
|
+
- GPT-5 model family via OpenAI API
|
|
85
|
+
- Custom MCP server bridging to existing Cloud Functions
|
|
86
|
+
- MongoDB Atlas for conversation persistence
|
|
87
|
+
- Google OAuth via OpenID Connect
|
|
88
|
+
- Custom domain mapping to `chat.conveyorclaims.ai`
|
|
89
|
+
- VPC connector for ruvector-postgres access
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Architecture
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
┌─────────────────────────────┐
|
|
97
|
+
│ chat.conveyorclaims.ai │
|
|
98
|
+
│ (Cloud Run Domain Mapping) │
|
|
99
|
+
└──────────────┬──────────────┘
|
|
100
|
+
│ HTTPS
|
|
101
|
+
▼
|
|
102
|
+
┌───────────────────────────────────────────────────────────────────────┐
|
|
103
|
+
│ Cloud Run: hf-chat-ui │
|
|
104
|
+
│ ghcr.io/huggingface/chat-ui-db │
|
|
105
|
+
│ Port 3000, 2Gi RAM, 2 CPU │
|
|
106
|
+
│ us-central1, VPC: conveyor-connector │
|
|
107
|
+
│ │
|
|
108
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌───────────┐ │
|
|
109
|
+
│ │ SvelteKit │ │ MCP Client │ │ Multi-LLM │ │ MongoDB │ │
|
|
110
|
+
│ │ Frontend │ │ (Tool Call) │ │ Provider │ │ Sidecar │ │
|
|
111
|
+
│ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘ └───────────┘ │
|
|
112
|
+
│ │ │ │ │
|
|
113
|
+
└─────────┼────────────────┼──────────────────┼─────────────────────────┘
|
|
114
|
+
│ │ │
|
|
115
|
+
│ │ ┌───────┼───────────────┐
|
|
116
|
+
│ │ │ │ │
|
|
117
|
+
│ ▼ ▼ ▼ ▼
|
|
118
|
+
│ ┌──────────────┐ ┌──────┐ ┌────────┐ ┌─────────┐
|
|
119
|
+
│ │ MCP Bridge │ │OpenAI│ │ Google │ │Anthropic│
|
|
120
|
+
│ │ (Cloud Run) │ │ API │ │Gemini │ │ Claude │
|
|
121
|
+
│ │ │ │ │ │ API │ │ API │
|
|
122
|
+
│ │ Routes to: │ │gpt-5 │ │gemini │ │claude │
|
|
123
|
+
│ │ Cloud Fns + │ │gpt-5m│ │2.5-pro │ │sonnet-4 │
|
|
124
|
+
│ │ ruvector-pg │ │gpt-4o│ │2.5-fl │ │ │
|
|
125
|
+
│ └──────┬───────┘ │o3 │ │ │ │ │
|
|
126
|
+
│ │ └──────┘ └────────┘ └─────────┘
|
|
127
|
+
│ ▼ Keys from Google Secret Manager
|
|
128
|
+
│ ┌───────────────────────────────────┐
|
|
129
|
+
│ │ Existing Cloud Functions │
|
|
130
|
+
│ │ (No Changes Required) │
|
|
131
|
+
│ │ │
|
|
132
|
+
│ │ • airtable-agent │
|
|
133
|
+
│ │ • db-query-agent │
|
|
134
|
+
│ │ • case-manager │
|
|
135
|
+
│ │ • simulation-agent │
|
|
136
|
+
│ │ • workflow-search │
|
|
137
|
+
│ └───────────────┬───────────────────┘
|
|
138
|
+
│ │ VPC (10.128.0.0/20)
|
|
139
|
+
│ ▼
|
|
140
|
+
│ ┌───────────────────────────────────┐
|
|
141
|
+
│ │ ruvector-postgres VM │
|
|
142
|
+
└─▶│ 10.128.0.2:5432 │
|
|
143
|
+
│ PostgreSQL 17.7 + ruvector │
|
|
144
|
+
│ │
|
|
145
|
+
│ PRIMARY DATA STORE: │
|
|
146
|
+
│ • workflow_chunks (311 rows) │
|
|
147
|
+
│ • embeddings (320 vectors, 384d) │
|
|
148
|
+
│ • HNSW index (m=16, ef=64) │
|
|
149
|
+
│ • Case data, analytics, metrics │
|
|
150
|
+
└───────────────────────────────────┘
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Implementation
|
|
156
|
+
|
|
157
|
+
### Phase 1: MongoDB Sidecar (Bundled with Chat UI)
|
|
158
|
+
|
|
159
|
+
HuggingFace Chat UI requires MongoDB for internal persistence (conversations, users, sessions). Rather than adding an external MongoDB dependency, we use the **bundled `chat-ui-db` image** which includes MongoDB as a sidecar process. Data is persisted via a Cloud Run volume mount.
|
|
160
|
+
|
|
161
|
+
**Why sidecar, not Atlas:**
|
|
162
|
+
- Zero additional infrastructure or accounts
|
|
163
|
+
- No network latency (localhost connection)
|
|
164
|
+
- All business data still lives in ruvector-postgres via MCP tools
|
|
165
|
+
- MongoDB only stores lightweight chat UI metadata
|
|
166
|
+
- If we outgrow this, upgrade to Atlas later (just change `MONGODB_URL`)
|
|
167
|
+
|
|
168
|
+
**Configuration:**
|
|
169
|
+
```ini
|
|
170
|
+
# Bundled MongoDB uses local storage — no connection string needed
|
|
171
|
+
# The chat-ui-db image starts MongoDB internally on localhost:27017
|
|
172
|
+
MONGODB_URL=mongodb://localhost:27017
|
|
173
|
+
MONGODB_DB_NAME=conveyor-chat
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Volume mount for persistence** (Cloud Run 2nd gen):
|
|
177
|
+
```bash
|
|
178
|
+
# Data persists across container restarts via /data volume
|
|
179
|
+
# The chat-ui-db image stores MongoDB data at /data/db
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Upgrade path:** If conversation volume grows beyond what a sidecar can handle, switch to MongoDB Atlas by updating `MONGODB_URL` in Secret Manager — zero code changes.
|
|
183
|
+
|
|
184
|
+
### Why MongoDB Cannot Be Avoided
|
|
185
|
+
|
|
186
|
+
HuggingFace Chat UI is **hardcoded to MongoDB** — its data layer uses MongoDB queries, aggregations, and GridFS throughout the SvelteKit backend. Replacing it with PostgreSQL would require forking the entire project. The sidecar approach (`chat-ui-db` image) bundles MongoDB **inside the same container**, so:
|
|
187
|
+
|
|
188
|
+
- No external MongoDB service to manage
|
|
189
|
+
- No additional infrastructure cost
|
|
190
|
+
- No MongoDB Atlas account needed
|
|
191
|
+
- Data lives on the container's ephemeral storage (conversations are lightweight and regenerable)
|
|
192
|
+
- All **business-critical data** (cases, workflows, embeddings, analytics) stays in ruvector-postgres
|
|
193
|
+
|
|
194
|
+
Think of MongoDB here as an internal implementation detail of Chat UI — like SQLite in a desktop app. The user never interacts with it directly. Ruvector-postgres remains the **single source of truth** for all Conveyor data.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### Phase 2: MCP Bridge Server
|
|
199
|
+
|
|
200
|
+
The MCP Bridge Server exposes existing Cloud Functions as MCP-compatible tools that Chat UI can call. This is a lightweight Node.js service deployed as a separate Cloud Run service.
|
|
201
|
+
|
|
202
|
+
**File: `infrastructure/gcp/mcp-bridge/index.js`**
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
206
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
207
|
+
import express from "express";
|
|
208
|
+
import { z } from "zod";
|
|
209
|
+
|
|
210
|
+
const CLOUD_FUNCTIONS = {
|
|
211
|
+
airtable: "https://airtable-agent-hwqrrwrlna-uc.a.run.app",
|
|
212
|
+
dbQuery: "https://db-query-agent-hwqrrwrlna-uc.a.run.app",
|
|
213
|
+
caseManager: "https://case-manager-hwqrrwrlna-uc.a.run.app",
|
|
214
|
+
simulation: "https://simulation-agent-hwqrrwrlna-uc.a.run.app",
|
|
215
|
+
workflowSearch: "https://us-central1-new-project-473022.cloudfunctions.net/workflow-search",
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const server = new McpServer({
|
|
219
|
+
name: "conveyor-tools",
|
|
220
|
+
version: "1.0.0",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Tool: Search workflow documents (vector search via ruvector-postgres)
|
|
224
|
+
server.tool(
|
|
225
|
+
"search_workflows",
|
|
226
|
+
"Search CLG workflow procedures, FAQs, and case management steps using semantic search. Returns relevant workflow steps for a given query.",
|
|
227
|
+
{
|
|
228
|
+
query: z.string().describe("Natural language query about workflow procedures"),
|
|
229
|
+
limit: z.number().optional().default(5).describe("Max results to return"),
|
|
230
|
+
},
|
|
231
|
+
async ({ query, limit }) => {
|
|
232
|
+
const resp = await fetch(CLOUD_FUNCTIONS.workflowSearch, {
|
|
233
|
+
method: "POST",
|
|
234
|
+
headers: { "Content-Type": "application/json" },
|
|
235
|
+
body: JSON.stringify({ action: "search", query, limit }),
|
|
236
|
+
});
|
|
237
|
+
const data = await resp.json();
|
|
238
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Tool: Query database analytics
|
|
243
|
+
server.tool(
|
|
244
|
+
"query_database",
|
|
245
|
+
"Run analytics queries against the PostgreSQL database. Supports case metrics, revenue forecasts, and trend analysis.",
|
|
246
|
+
{
|
|
247
|
+
query: z.string().describe("Natural language analytics query"),
|
|
248
|
+
type: z.enum(["metrics", "forecast", "trend", "custom"]).optional().default("metrics"),
|
|
249
|
+
},
|
|
250
|
+
async ({ query, type }) => {
|
|
251
|
+
const resp = await fetch(CLOUD_FUNCTIONS.dbQuery, {
|
|
252
|
+
method: "POST",
|
|
253
|
+
headers: { "Content-Type": "application/json" },
|
|
254
|
+
body: JSON.stringify({ query, type }),
|
|
255
|
+
});
|
|
256
|
+
const data = await resp.json();
|
|
257
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Tool: Case management operations
|
|
262
|
+
server.tool(
|
|
263
|
+
"manage_case",
|
|
264
|
+
"Look up case status, get next steps, list cases, or perform case management operations via Airtable.",
|
|
265
|
+
{
|
|
266
|
+
action: z.enum(["status", "list", "next_steps", "update"]).describe("Case action"),
|
|
267
|
+
caseId: z.string().optional().describe("Case ID (e.g., C-02420)"),
|
|
268
|
+
filters: z.record(z.string()).optional().describe("Filter criteria for list action"),
|
|
269
|
+
},
|
|
270
|
+
async ({ action, caseId, filters }) => {
|
|
271
|
+
const resp = await fetch(CLOUD_FUNCTIONS.caseManager, {
|
|
272
|
+
method: "POST",
|
|
273
|
+
headers: { "Content-Type": "application/json" },
|
|
274
|
+
body: JSON.stringify({ action, caseId, filters }),
|
|
275
|
+
});
|
|
276
|
+
const data = await resp.json();
|
|
277
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// Tool: Run RL simulations
|
|
282
|
+
server.tool(
|
|
283
|
+
"run_simulation",
|
|
284
|
+
"Run reinforcement learning strategy simulations for case settlement optimization. Uses Q-learning and Monte Carlo methods.",
|
|
285
|
+
{
|
|
286
|
+
scenario: z.string().describe("Simulation scenario description"),
|
|
287
|
+
episodes: z.number().optional().default(1000).describe("Number of simulation episodes"),
|
|
288
|
+
strategy: z.enum(["q_learning", "monte_carlo", "policy_gradient"]).optional().default("q_learning"),
|
|
289
|
+
},
|
|
290
|
+
async ({ scenario, episodes, strategy }) => {
|
|
291
|
+
const resp = await fetch(CLOUD_FUNCTIONS.simulation, {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: { "Content-Type": "application/json" },
|
|
294
|
+
body: JSON.stringify({ scenario, episodes, strategy }),
|
|
295
|
+
});
|
|
296
|
+
const data = await resp.json();
|
|
297
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// Tool: Airtable CRUD
|
|
302
|
+
server.tool(
|
|
303
|
+
"airtable_query",
|
|
304
|
+
"Query or update Airtable records. Supports listing cases, clients, carriers, and performing CRUD operations.",
|
|
305
|
+
{
|
|
306
|
+
action: z.enum(["list", "get", "create", "update"]).describe("CRUD action"),
|
|
307
|
+
table: z.string().describe("Airtable table name (e.g., Cases, Clients, Carriers)"),
|
|
308
|
+
recordId: z.string().optional().describe("Record ID for get/update"),
|
|
309
|
+
filters: z.record(z.string()).optional().describe("Filter criteria"),
|
|
310
|
+
fields: z.record(z.unknown()).optional().describe("Fields for create/update"),
|
|
311
|
+
},
|
|
312
|
+
async ({ action, table, recordId, filters, fields }) => {
|
|
313
|
+
const resp = await fetch(CLOUD_FUNCTIONS.airtable, {
|
|
314
|
+
method: "POST",
|
|
315
|
+
headers: { "Content-Type": "application/json" },
|
|
316
|
+
body: JSON.stringify({ action, table, recordId, filters, fields }),
|
|
317
|
+
});
|
|
318
|
+
const data = await resp.json();
|
|
319
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// Express HTTP transport
|
|
324
|
+
const app = express();
|
|
325
|
+
|
|
326
|
+
app.post("/mcp", async (req, res) => {
|
|
327
|
+
const transport = new StreamableHTTPServerTransport("/mcp");
|
|
328
|
+
await server.connect(transport);
|
|
329
|
+
await transport.handleRequest(req, res);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
app.get("/health", (_, res) => res.json({ status: "ok" }));
|
|
333
|
+
|
|
334
|
+
app.listen(3001, () => console.log("MCP Bridge running on :3001"));
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Deploy:**
|
|
338
|
+
```bash
|
|
339
|
+
gcloud run deploy mcp-bridge \
|
|
340
|
+
--source=infrastructure/gcp/mcp-bridge \
|
|
341
|
+
--platform=managed \
|
|
342
|
+
--region=us-central1 \
|
|
343
|
+
--port=3001 \
|
|
344
|
+
--memory=512Mi \
|
|
345
|
+
--cpu=1 \
|
|
346
|
+
--min-instances=0 \
|
|
347
|
+
--max-instances=5 \
|
|
348
|
+
--vpc-connector=conveyor-connector \
|
|
349
|
+
--allow-unauthenticated
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### Phase 3: MCP Tool Servers (3 Sources)
|
|
355
|
+
|
|
356
|
+
Chat UI supports multiple MCP servers simultaneously. We configure **three** to give GPT-5 full access to Conveyor's data ecosystem:
|
|
357
|
+
|
|
358
|
+
#### MCP Server 1: Conveyor Bridge (Custom — Cloud Functions + ruvector-postgres)
|
|
359
|
+
|
|
360
|
+
The custom MCP Bridge from Phase 2. Provides 5 tools:
|
|
361
|
+
|
|
362
|
+
| Tool | Backend | Purpose |
|
|
363
|
+
|------|---------|---------|
|
|
364
|
+
| `search_workflows` | workflow-search → ruvector-postgres | Semantic search over CLG workflow docs (311 chunks, 384d HNSW) |
|
|
365
|
+
| `query_database` | db-query-agent → ruvector-postgres | SQL analytics, revenue forecasts, trend analysis |
|
|
366
|
+
| `manage_case` | case-manager → Airtable | Case status lookup, next steps, updates |
|
|
367
|
+
| `run_simulation` | simulation-agent | RL strategy simulations (Q-learning, Monte Carlo) |
|
|
368
|
+
| `airtable_query` | airtable-agent → Airtable | Generic Airtable CRUD across all tables |
|
|
369
|
+
|
|
370
|
+
#### MCP Server 2: Official Airtable MCP
|
|
371
|
+
|
|
372
|
+
[Airtable's official MCP server](https://support.airtable.com/docs/using-the-airtable-mcp-server) provides **direct base access** — no custom bridge needed. This gives GPT-5 full schema awareness and natural language querying.
|
|
373
|
+
|
|
374
|
+
**Capabilities:**
|
|
375
|
+
- List all bases, tables, fields, and views
|
|
376
|
+
- Read, create, update, delete records
|
|
377
|
+
- Search records with filters
|
|
378
|
+
- Schema inspection (field types, options, linked records)
|
|
379
|
+
- No additional infrastructure — hosted by Airtable
|
|
380
|
+
|
|
381
|
+
**Secret:** `airtable-api-key` (already in Google Secret Manager)
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
URL: https://mcp.airtable.com/v0/mcp
|
|
385
|
+
Auth: Bearer ${AIRTABLE_API_KEY}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
> **Why both Airtable MCP AND the Conveyor Bridge airtable tool?** The official Airtable MCP gives raw CRUD access — GPT-5 can browse schemas and build ad-hoc queries. The Conveyor Bridge `manage_case` tool provides **structured, pre-built** case management workflows. Users benefit from both: exploration via Airtable MCP, workflow-guided operations via the bridge.
|
|
389
|
+
|
|
390
|
+
#### MCP Server 3: Google Drive MCP
|
|
391
|
+
|
|
392
|
+
[Google's official MCP for Drive](https://cloud.google.com/blog/products/ai-machine-learning/announcing-official-mcp-support-for-google-services) provides access to the CLG Workflow shared drive documents.
|
|
393
|
+
|
|
394
|
+
**Capabilities:**
|
|
395
|
+
- Search files across Drive (including shared drives)
|
|
396
|
+
- Read document contents (Docs, Sheets, Slides)
|
|
397
|
+
- List files in folders
|
|
398
|
+
- Read Google Sheets cells and ranges
|
|
399
|
+
- Access the 🔴CLG Workflow shared drive (0AMTB1wrVg9HLUk9PVA)
|
|
400
|
+
|
|
401
|
+
**Secrets:** `google-client-id`, `google-client-secret` (both in Secret Manager)
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
URL: https://mcp.googleapis.com/v1/drive
|
|
405
|
+
Auth: OAuth2 service account or user token
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
> **Why both Google Drive MCP AND the workflow-search tool?** The workflow-search tool provides **vector-indexed semantic search** (HNSW, <50ms) over pre-chunked workflow documents. The Google Drive MCP provides **raw file access** — read any document, list folders, access spreadsheets. Use workflow-search for "what's the process for X?" and Google Drive MCP for "show me the intake form template."
|
|
409
|
+
|
|
410
|
+
#### Combined Tool Landscape
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
414
|
+
│ HF Chat UI — MCP Clients │
|
|
415
|
+
│ │
|
|
416
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
417
|
+
│ │ Conveyor Bridge │ │ Airtable MCP │ │ Google Drive MCP│ │
|
|
418
|
+
│ │ (Custom) │ │ (Official) │ │ (Google) │ │
|
|
419
|
+
│ │ │ │ │ │ │ │
|
|
420
|
+
│ │ • search_wf │ │ • list_bases │ │ • search_files │ │
|
|
421
|
+
│ │ • query_db │ │ • list_tables │ │ • read_doc │ │
|
|
422
|
+
│ │ • manage_case │ │ • read_records │ │ • list_folder │ │
|
|
423
|
+
│ │ • run_sim │ │ • create_record│ │ • read_sheets │ │
|
|
424
|
+
│ │ • airtable_query │ │ • update_record│ │ • get_metadata │ │
|
|
425
|
+
│ │ │ │ • search │ │ │ │
|
|
426
|
+
│ └────────┬─────────┘ └───────┬────────┘ └───────┬─────────┘ │
|
|
427
|
+
│ │ │ │ │
|
|
428
|
+
└───────────┼────────────────────┼────────────────────┼─────────────┘
|
|
429
|
+
│ │ │
|
|
430
|
+
▼ ▼ ▼
|
|
431
|
+
Cloud Functions + Airtable API Google Drive API
|
|
432
|
+
ruvector-postgres (airtable.com) (googleapis.com)
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### Phase 4: Multi-Provider Model Configuration
|
|
438
|
+
|
|
439
|
+
All API keys are pulled from **Google Secret Manager** at runtime via Cloud Run `--set-secrets`. The MODELS environment variable configures multi-provider access.
|
|
440
|
+
|
|
441
|
+
#### Secrets Used (all already exist in Secret Manager)
|
|
442
|
+
|
|
443
|
+
| Secret ID | Env Var | Provider |
|
|
444
|
+
|-----------|---------|----------|
|
|
445
|
+
| `openai-api-key` | `OPENAI_API_KEY` | OpenAI (GPT-5 family) |
|
|
446
|
+
| `anthropic-api-key` | `ANTHROPIC_API_KEY` | Anthropic (Claude) |
|
|
447
|
+
| `google-api-key` | `GOOGLE_API_KEY` | Google (Gemini) |
|
|
448
|
+
|
|
449
|
+
#### Model Lineup
|
|
450
|
+
|
|
451
|
+
```ini
|
|
452
|
+
MODELS=`[
|
|
453
|
+
{
|
|
454
|
+
"name": "gpt-5.2",
|
|
455
|
+
"id": "gpt-5.2",
|
|
456
|
+
"displayName": "GPT-5.2 (Latest)",
|
|
457
|
+
"description": "OpenAI's latest flagship model. Best for complex reasoning and analysis.",
|
|
458
|
+
"supportsTools": true,
|
|
459
|
+
"parameters": {
|
|
460
|
+
"temperature": 0.7,
|
|
461
|
+
"max_new_tokens": 4096
|
|
462
|
+
},
|
|
463
|
+
"endpoints": [{
|
|
464
|
+
"type": "openai",
|
|
465
|
+
"baseURL": "https://api.openai.com/v1"
|
|
466
|
+
}]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"name": "gpt-5.2-pro",
|
|
470
|
+
"id": "gpt-5.2-pro",
|
|
471
|
+
"displayName": "GPT-5.2 Pro",
|
|
472
|
+
"description": "Pro tier with extended reasoning. Best for complex case analysis.",
|
|
473
|
+
"supportsTools": true,
|
|
474
|
+
"parameters": {
|
|
475
|
+
"temperature": 0.5,
|
|
476
|
+
"max_new_tokens": 8192
|
|
477
|
+
},
|
|
478
|
+
"endpoints": [{
|
|
479
|
+
"type": "openai",
|
|
480
|
+
"baseURL": "https://api.openai.com/v1"
|
|
481
|
+
}]
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
"name": "gpt-5",
|
|
485
|
+
"id": "gpt-5",
|
|
486
|
+
"displayName": "GPT-5",
|
|
487
|
+
"description": "Strong general-purpose reasoning. Good balance of speed and quality.",
|
|
488
|
+
"supportsTools": true,
|
|
489
|
+
"parameters": {
|
|
490
|
+
"temperature": 0.7,
|
|
491
|
+
"max_new_tokens": 4096
|
|
492
|
+
},
|
|
493
|
+
"endpoints": [{
|
|
494
|
+
"type": "openai",
|
|
495
|
+
"baseURL": "https://api.openai.com/v1"
|
|
496
|
+
}]
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"name": "gpt-5-mini",
|
|
500
|
+
"id": "gpt-5-mini",
|
|
501
|
+
"displayName": "GPT-5 Mini",
|
|
502
|
+
"description": "Fast and cost-effective. Great for FAQ lookups and simple workflow queries.",
|
|
503
|
+
"supportsTools": true,
|
|
504
|
+
"parameters": {
|
|
505
|
+
"temperature": 0.7,
|
|
506
|
+
"max_new_tokens": 4096
|
|
507
|
+
},
|
|
508
|
+
"endpoints": [{
|
|
509
|
+
"type": "openai",
|
|
510
|
+
"baseURL": "https://api.openai.com/v1"
|
|
511
|
+
}]
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"name": "gpt-5-nano",
|
|
515
|
+
"id": "gpt-5-nano",
|
|
516
|
+
"displayName": "GPT-5 Nano",
|
|
517
|
+
"description": "Ultra-fast for simple queries. Lowest cost per token.",
|
|
518
|
+
"supportsTools": true,
|
|
519
|
+
"parameters": {
|
|
520
|
+
"temperature": 0.7,
|
|
521
|
+
"max_new_tokens": 2048
|
|
522
|
+
},
|
|
523
|
+
"endpoints": [{
|
|
524
|
+
"type": "openai",
|
|
525
|
+
"baseURL": "https://api.openai.com/v1"
|
|
526
|
+
}]
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
"name": "gpt-4o",
|
|
530
|
+
"id": "gpt-4o",
|
|
531
|
+
"displayName": "GPT-4o (Multimodal)",
|
|
532
|
+
"description": "Multimodal model. Upload images of documents, forms, or damage photos.",
|
|
533
|
+
"multimodal": true,
|
|
534
|
+
"supportsTools": true,
|
|
535
|
+
"parameters": {
|
|
536
|
+
"temperature": 0.5,
|
|
537
|
+
"max_new_tokens": 4096
|
|
538
|
+
},
|
|
539
|
+
"endpoints": [{
|
|
540
|
+
"type": "openai",
|
|
541
|
+
"baseURL": "https://api.openai.com/v1"
|
|
542
|
+
}]
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"name": "o3",
|
|
546
|
+
"id": "o3",
|
|
547
|
+
"displayName": "o3 (Reasoning)",
|
|
548
|
+
"description": "Advanced reasoning model. Best for complex legal/financial analysis.",
|
|
549
|
+
"supportsTools": false,
|
|
550
|
+
"parameters": {
|
|
551
|
+
"max_new_tokens": 4096
|
|
552
|
+
},
|
|
553
|
+
"endpoints": [{
|
|
554
|
+
"type": "openai",
|
|
555
|
+
"baseURL": "https://api.openai.com/v1"
|
|
556
|
+
}]
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"name": "gemini-2.5-pro",
|
|
560
|
+
"id": "gemini-2.5-pro",
|
|
561
|
+
"displayName": "Gemini 2.5 Pro (Google)",
|
|
562
|
+
"description": "Google's most capable model. Already used in the existing chat system.",
|
|
563
|
+
"supportsTools": true,
|
|
564
|
+
"parameters": {
|
|
565
|
+
"temperature": 0.7,
|
|
566
|
+
"max_new_tokens": 4096
|
|
567
|
+
},
|
|
568
|
+
"endpoints": [{
|
|
569
|
+
"type": "openai",
|
|
570
|
+
"baseURL": "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
571
|
+
"apiKey": "${GOOGLE_API_KEY}"
|
|
572
|
+
}]
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
"name": "gemini-2.5-flash",
|
|
576
|
+
"id": "gemini-2.5-flash",
|
|
577
|
+
"displayName": "Gemini 2.5 Flash (Google)",
|
|
578
|
+
"description": "Google's fast model. Good for quick workflow lookups.",
|
|
579
|
+
"supportsTools": true,
|
|
580
|
+
"parameters": {
|
|
581
|
+
"temperature": 0.7,
|
|
582
|
+
"max_new_tokens": 4096
|
|
583
|
+
},
|
|
584
|
+
"endpoints": [{
|
|
585
|
+
"type": "openai",
|
|
586
|
+
"baseURL": "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
587
|
+
"apiKey": "${GOOGLE_API_KEY}"
|
|
588
|
+
}]
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"name": "claude-sonnet-4",
|
|
592
|
+
"id": "claude-sonnet-4",
|
|
593
|
+
"displayName": "Claude Sonnet 4 (Anthropic)",
|
|
594
|
+
"description": "Anthropic's balanced model. Strong instruction following and coding.",
|
|
595
|
+
"supportsTools": true,
|
|
596
|
+
"parameters": {
|
|
597
|
+
"temperature": 0.7,
|
|
598
|
+
"max_new_tokens": 4096
|
|
599
|
+
},
|
|
600
|
+
"endpoints": [{
|
|
601
|
+
"type": "openai",
|
|
602
|
+
"baseURL": "https://api.anthropic.com/v1",
|
|
603
|
+
"apiKey": "${ANTHROPIC_API_KEY}",
|
|
604
|
+
"defaultHeaders": {
|
|
605
|
+
"anthropic-version": "2023-06-01"
|
|
606
|
+
}
|
|
607
|
+
}]
|
|
608
|
+
}
|
|
609
|
+
]`
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
> **Note:** Google and Anthropic keys are currently expired/out of credits (tested 2026-02-26). Models will show as unavailable until keys are renewed. OpenAI GPT-5 models are **confirmed working** with $100 balance. Chat UI gracefully handles unavailable providers — users simply see those models greyed out.
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
### Phase 4: Chat UI Cloud Run Deployment
|
|
617
|
+
|
|
618
|
+
#### 4a. Secrets Setup (All Already Exist)
|
|
619
|
+
|
|
620
|
+
All required secrets already exist in Google Secret Manager (verified 2026-02-26). Just verify access:
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
# All 8 secrets needed for hf-chat-ui
|
|
624
|
+
SECRETS=(
|
|
625
|
+
openai-api-key # GPT-5 models
|
|
626
|
+
anthropic-api-key # Claude models
|
|
627
|
+
google-api-key # Gemini models
|
|
628
|
+
airtable-api-key # Airtable MCP
|
|
629
|
+
airtable-base-id # Airtable base reference
|
|
630
|
+
google-client-id # Google OAuth + Drive MCP
|
|
631
|
+
google-client-secret # Google OAuth + Drive MCP
|
|
632
|
+
gemini-api-key # Backup Gemini key
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
# Verify all secrets exist
|
|
636
|
+
for secret in "${SECRETS[@]}"; do
|
|
637
|
+
echo -n "$secret: "
|
|
638
|
+
gcloud secrets versions access latest --secret="$secret" \
|
|
639
|
+
--project=new-project-473022 2>/dev/null | head -c 12 && echo "... ✓" || echo "MISSING"
|
|
640
|
+
done
|
|
641
|
+
|
|
642
|
+
# Grant access to compute service account
|
|
643
|
+
for secret in "${SECRETS[@]}"; do
|
|
644
|
+
gcloud secrets add-iam-policy-binding "$secret" \
|
|
645
|
+
--project=new-project-473022 \
|
|
646
|
+
--member="serviceAccount:245235083640-compute@developer.gserviceaccount.com" \
|
|
647
|
+
--role="roles/secretmanager.secretAccessor" \
|
|
648
|
+
--quiet 2>/dev/null || true
|
|
649
|
+
done
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Secrets inventory for this deployment:**
|
|
653
|
+
|
|
654
|
+
| Secret | Purpose | Status |
|
|
655
|
+
|--------|---------|--------|
|
|
656
|
+
| `openai-api-key` | GPT-5 model access | Active ($100 balance) |
|
|
657
|
+
| `anthropic-api-key` | Claude model access | Needs credits |
|
|
658
|
+
| `google-api-key` | Gemini model access | Needs renewal |
|
|
659
|
+
| `airtable-api-key` | Airtable MCP direct access | Active |
|
|
660
|
+
| `airtable-base-id` | Airtable base reference | Active |
|
|
661
|
+
| `google-client-id` | Google OAuth + Drive MCP | Active |
|
|
662
|
+
| `google-client-secret` | Google OAuth + Drive MCP | Active |
|
|
663
|
+
| `gemini-api-key` | Backup Gemini key | Active |
|
|
664
|
+
|
|
665
|
+
#### 4b. Environment File
|
|
666
|
+
|
|
667
|
+
**File: `infrastructure/gcp/hf-chat-ui/.env.production`**
|
|
668
|
+
|
|
669
|
+
```ini
|
|
670
|
+
# ── Model Provider ──────────────────────────────────────
|
|
671
|
+
OPENAI_BASE_URL=https://api.openai.com/v1
|
|
672
|
+
# OPENAI_API_KEY injected from Secret Manager
|
|
673
|
+
|
|
674
|
+
# ── Database ────────────────────────────────────────────
|
|
675
|
+
# MONGODB_URL injected from Secret Manager
|
|
676
|
+
MONGODB_DB_NAME=conveyor-chat
|
|
677
|
+
|
|
678
|
+
# ── Branding ────────────────────────────────────────────
|
|
679
|
+
PUBLIC_APP_NAME=Conveyor AI
|
|
680
|
+
PUBLIC_APP_DESCRIPTION=Insurance Case Management & Revenue Operations Assistant powered by GPT-5
|
|
681
|
+
PUBLIC_ORIGIN=https://chat.conveyorclaims.ai
|
|
682
|
+
|
|
683
|
+
# ── Authentication (Google OAuth) ───────────────────────
|
|
684
|
+
OPENID_PROVIDER_URL=https://accounts.google.com
|
|
685
|
+
OPENID_CLIENT_ID=245235083640-gkbo4otq57lqeisuigcat0bg037f49oc.apps.googleusercontent.com
|
|
686
|
+
# OPENID_CLIENT_SECRET injected from Secret Manager
|
|
687
|
+
OPENID_SCOPES=openid profile email
|
|
688
|
+
OPENID_NAME_CLAIM=name
|
|
689
|
+
COOKIE_SECURE=true
|
|
690
|
+
COOKIE_SAMESITE=lax
|
|
691
|
+
|
|
692
|
+
# ── MCP Tools (3 servers: Custom Bridge + Airtable + Google Drive) ──
|
|
693
|
+
MCP_SERVERS=`[
|
|
694
|
+
{
|
|
695
|
+
"name": "Conveyor Tools",
|
|
696
|
+
"description": "Workflow search, DB analytics, case management, simulations via ruvector-postgres and Cloud Functions",
|
|
697
|
+
"url": "https://mcp-bridge-hwqrrwrlna-uc.a.run.app/mcp"
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
"name": "Airtable",
|
|
701
|
+
"description": "Direct Airtable base access — browse tables, search records, create/update cases, view schemas",
|
|
702
|
+
"url": "https://mcp.airtable.com/v0/mcp",
|
|
703
|
+
"headers": {
|
|
704
|
+
"Authorization": "Bearer ${AIRTABLE_API_KEY}"
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"name": "Google Drive",
|
|
709
|
+
"description": "Search and read CLG Workflow documents, forms, and templates from Google Drive shared folders",
|
|
710
|
+
"url": "https://mcp.googleapis.com/v1/drive",
|
|
711
|
+
"headers": {
|
|
712
|
+
"Authorization": "Bearer ${GOOGLE_DRIVE_TOKEN}"
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
]`
|
|
716
|
+
MCP_TOOL_TIMEOUT_MS=30000
|
|
717
|
+
|
|
718
|
+
# ── Smart Router ────────────────────────────────────────
|
|
719
|
+
LLM_ROUTER_FALLBACK_MODEL=gpt-5
|
|
720
|
+
LLM_ROUTER_ENABLE_TOOLS=true
|
|
721
|
+
LLM_ROUTER_TOOLS_MODEL=gpt-5.2
|
|
722
|
+
PUBLIC_LLM_ROUTER_DISPLAY_NAME=Auto (Omni)
|
|
723
|
+
PUBLIC_LLM_ROUTER_ALIAS_ID=omni
|
|
724
|
+
|
|
725
|
+
# ── Voice ───────────────────────────────────────────────
|
|
726
|
+
TRANSCRIPTION_MODEL=openai/whisper-large-v3-turbo
|
|
727
|
+
|
|
728
|
+
# ── Web Search ──────────────────────────────────────────
|
|
729
|
+
USE_LOCAL_WEBSEARCH=true
|
|
730
|
+
|
|
731
|
+
# ── Features ────────────────────────────────────────────
|
|
732
|
+
LLM_SUMMARIZATION=true
|
|
733
|
+
ENABLE_DATA_EXPORT=true
|
|
734
|
+
ALLOW_IFRAME=false
|
|
735
|
+
|
|
736
|
+
# ── Rate Limits ─────────────────────────────────────────
|
|
737
|
+
USAGE_LIMITS={"messagesPerMinute": 20, "conversations": 100, "tools": 50}
|
|
738
|
+
|
|
739
|
+
# ── System Prompt (Conveyor Identity) ───────────────────
|
|
740
|
+
TASK_MODEL=gpt-5-mini
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### 4c. Cloud Build Configuration
|
|
744
|
+
|
|
745
|
+
**File: `infrastructure/gcp/hf-chat-ui/cloudbuild.yaml`**
|
|
746
|
+
|
|
747
|
+
```yaml
|
|
748
|
+
steps:
|
|
749
|
+
# Step 1: Pull the pre-built HuggingFace Chat UI image
|
|
750
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
751
|
+
args: ['pull', 'ghcr.io/huggingface/chat-ui:latest']
|
|
752
|
+
|
|
753
|
+
# Step 2: Tag for GCR
|
|
754
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
755
|
+
args: [
|
|
756
|
+
'tag',
|
|
757
|
+
'ghcr.io/huggingface/chat-ui:latest',
|
|
758
|
+
'gcr.io/${PROJECT_ID}/hf-chat-ui:${_VERSION}'
|
|
759
|
+
]
|
|
760
|
+
|
|
761
|
+
# Step 3: Push versioned tag
|
|
762
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
763
|
+
args: ['push', 'gcr.io/${PROJECT_ID}/hf-chat-ui:${_VERSION}']
|
|
764
|
+
|
|
765
|
+
# Step 4: Push latest tag
|
|
766
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
767
|
+
args: [
|
|
768
|
+
'tag',
|
|
769
|
+
'gcr.io/${PROJECT_ID}/hf-chat-ui:${_VERSION}',
|
|
770
|
+
'gcr.io/${PROJECT_ID}/hf-chat-ui:latest'
|
|
771
|
+
]
|
|
772
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
773
|
+
args: ['push', 'gcr.io/${PROJECT_ID}/hf-chat-ui:latest']
|
|
774
|
+
|
|
775
|
+
# Step 5: Deploy to Cloud Run
|
|
776
|
+
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
|
777
|
+
entrypoint: gcloud
|
|
778
|
+
args: [
|
|
779
|
+
'run', 'deploy', 'hf-chat-ui',
|
|
780
|
+
'--image', 'gcr.io/${PROJECT_ID}/hf-chat-ui:${_VERSION}',
|
|
781
|
+
'--platform', 'managed',
|
|
782
|
+
'--region', 'us-central1',
|
|
783
|
+
'--port', '3000',
|
|
784
|
+
'--memory', '2Gi',
|
|
785
|
+
'--cpu', '2',
|
|
786
|
+
'--min-instances', '0',
|
|
787
|
+
'--max-instances', '10',
|
|
788
|
+
'--timeout', '300',
|
|
789
|
+
'--vpc-connector', 'conveyor-connector',
|
|
790
|
+
'--allow-unauthenticated',
|
|
791
|
+
'--set-env-vars', 'OPENAI_BASE_URL=https://api.openai.com/v1,MONGODB_DB_NAME=conveyor-chat,PUBLIC_APP_NAME=Conveyor AI,PUBLIC_ORIGIN=https://chat.conveyorclaims.ai,LLM_SUMMARIZATION=true,ENABLE_DATA_EXPORT=true',
|
|
792
|
+
'--set-secrets', 'OPENAI_API_KEY=openai-api-key:latest,ANTHROPIC_API_KEY=anthropic-api-key:latest,GOOGLE_API_KEY=google-api-key:latest,AIRTABLE_API_KEY=airtable-api-key:latest,GOOGLE_CLIENT_ID=google-client-id:latest,GOOGLE_CLIENT_SECRET=google-client-secret:latest',
|
|
793
|
+
]
|
|
794
|
+
|
|
795
|
+
substitutions:
|
|
796
|
+
_VERSION: 'v1'
|
|
797
|
+
|
|
798
|
+
options:
|
|
799
|
+
logging: CLOUD_LOGGING_ONLY
|
|
800
|
+
timeout: 600s
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
### Phase 5: Custom Domain Mapping
|
|
806
|
+
|
|
807
|
+
#### 5a. Map `chat.conveyorclaims.ai` to Cloud Run
|
|
808
|
+
|
|
809
|
+
```bash
|
|
810
|
+
# Verify domain ownership (one-time)
|
|
811
|
+
gcloud domains verify conveyorclaims.ai --project=new-project-473022
|
|
812
|
+
|
|
813
|
+
# Map custom domain to the Cloud Run service
|
|
814
|
+
gcloud run domain-mappings create \
|
|
815
|
+
--service=hf-chat-ui \
|
|
816
|
+
--domain=chat.conveyorclaims.ai \
|
|
817
|
+
--region=us-central1 \
|
|
818
|
+
--project=new-project-473022
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
#### 5b. DNS Configuration
|
|
822
|
+
|
|
823
|
+
Add these DNS records at your domain registrar for `conveyorclaims.ai`:
|
|
824
|
+
|
|
825
|
+
| Type | Name | Value |
|
|
826
|
+
|------|------|-------|
|
|
827
|
+
| CNAME | `chat` | `ghs.googlehosted.com.` |
|
|
828
|
+
|
|
829
|
+
Google manages the SSL certificate automatically. Provisioning takes 15-30 minutes after DNS propagation.
|
|
830
|
+
|
|
831
|
+
#### 5c. Google OAuth Redirect URI
|
|
832
|
+
|
|
833
|
+
Add `https://chat.conveyorclaims.ai/login/callback` to the authorized redirect URIs in the Google Cloud Console:
|
|
834
|
+
|
|
835
|
+
```
|
|
836
|
+
Console → APIs & Services → Credentials → OAuth 2.0 Client ID
|
|
837
|
+
→ Authorized redirect URIs → Add:
|
|
838
|
+
https://chat.conveyorclaims.ai/login/callback
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
---
|
|
842
|
+
|
|
843
|
+
### Phase 6: System Prompt Configuration
|
|
844
|
+
|
|
845
|
+
Create a custom assistant in the Chat UI that embeds Conveyor's identity and formatting rules (from ADR-027):
|
|
846
|
+
|
|
847
|
+
```json
|
|
848
|
+
{
|
|
849
|
+
"name": "Conveyor AI",
|
|
850
|
+
"preprompt": "You are Conveyor AI, an Insurance Case Management & Revenue Operations Assistant for CLG (Claims Litigation Group).\n\n## Your Capabilities\n- Case management: Look up case status, next steps, due dates, assigned roles\n- Workflow guidance: Step-by-step procedures from CLG workflow documents\n- Revenue forecasting: Analytics and trend analysis\n- Strategy optimization: RL-based settlement strategy simulations\n- Airtable operations: Query and update case records\n\n## Response Style\n- Start conversationally: 'Great question —', 'Yes —', 'Got it —'\n- Use emoji markers: ✅ ❌ ⚠️ 🔑 💰 📌 for scannability\n- Bold field names: **Next Steps**, **Case Status**, **RS Due Date**\n- End with a key takeaway: 🔑 or 🧠 summary\n- Offer proactive follow-up: 'If you want, I can also...'\n- NEVER expose: similarity scores, chunk IDs, function names, JSON, silo numbers\n- ALWAYS attribute sources by document name: 'Referrals Workflow', 'FAQ's'\n\n## Available Tools\nYou have access to Conveyor Tools via MCP. Use them to:\n- search_workflows: Search CLG workflow procedures and FAQs\n- query_database: Run analytics against PostgreSQL\n- manage_case: Look up or update case status via Airtable\n- run_simulation: Run RL strategy simulations\n- airtable_query: Direct Airtable CRUD operations",
|
|
851
|
+
"model": "gpt-5.2"
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
This can be set as the default assistant via MongoDB or via the `ASSISTANTS` environment variable.
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
## Deployment Runbook
|
|
860
|
+
|
|
861
|
+
### Quick Deploy (4 commands)
|
|
862
|
+
|
|
863
|
+
All secrets already exist in Google Secret Manager. No new secrets needed.
|
|
864
|
+
|
|
865
|
+
```bash
|
|
866
|
+
# 1. Deploy Chat UI to Cloud Run (bundled MongoDB sidecar via chat-ui-db image)
|
|
867
|
+
gcloud run deploy hf-chat-ui \
|
|
868
|
+
--image=ghcr.io/huggingface/chat-ui-db:latest \
|
|
869
|
+
--platform=managed \
|
|
870
|
+
--region=us-central1 \
|
|
871
|
+
--port=3000 \
|
|
872
|
+
--memory=2Gi \
|
|
873
|
+
--cpu=2 \
|
|
874
|
+
--min-instances=1 \
|
|
875
|
+
--max-instances=10 \
|
|
876
|
+
--timeout=300 \
|
|
877
|
+
--vpc-connector=conveyor-connector \
|
|
878
|
+
--allow-unauthenticated \
|
|
879
|
+
--set-env-vars="OPENAI_BASE_URL=https://api.openai.com/v1,MONGODB_URL=mongodb://localhost:27017,MONGODB_DB_NAME=conveyor-chat,PUBLIC_APP_NAME=Conveyor AI,PUBLIC_ORIGIN=https://chat.conveyorclaims.ai,LLM_SUMMARIZATION=true,ENABLE_DATA_EXPORT=true,ALLOW_IFRAME=false,USE_LOCAL_WEBSEARCH=true" \
|
|
880
|
+
--set-secrets="OPENAI_API_KEY=openai-api-key:latest,ANTHROPIC_API_KEY=anthropic-api-key:latest,GOOGLE_API_KEY=google-api-key:latest,AIRTABLE_API_KEY=airtable-api-key:latest,GOOGLE_CLIENT_ID=google-client-id:latest,GOOGLE_CLIENT_SECRET=google-client-secret:latest" \
|
|
881
|
+
--project=new-project-473022
|
|
882
|
+
|
|
883
|
+
# 2. Deploy MCP Bridge (connects Chat UI tools to existing Cloud Functions + ruvector-postgres)
|
|
884
|
+
gcloud run deploy mcp-bridge \
|
|
885
|
+
--source=infrastructure/gcp/mcp-bridge \
|
|
886
|
+
--platform=managed \
|
|
887
|
+
--region=us-central1 \
|
|
888
|
+
--port=3001 \
|
|
889
|
+
--memory=512Mi \
|
|
890
|
+
--cpu=1 \
|
|
891
|
+
--vpc-connector=conveyor-connector \
|
|
892
|
+
--allow-unauthenticated \
|
|
893
|
+
--project=new-project-473022
|
|
894
|
+
|
|
895
|
+
# 3. Map custom domain
|
|
896
|
+
gcloud run domain-mappings create \
|
|
897
|
+
--service=hf-chat-ui \
|
|
898
|
+
--domain=chat.conveyorclaims.ai \
|
|
899
|
+
--region=us-central1 \
|
|
900
|
+
--project=new-project-473022
|
|
901
|
+
|
|
902
|
+
# 4. Add DNS CNAME record at registrar
|
|
903
|
+
# chat.conveyorclaims.ai → ghs.googlehosted.com.
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
## Cost Estimate
|
|
909
|
+
|
|
910
|
+
| Component | Monthly Cost |
|
|
911
|
+
|-----------|-------------|
|
|
912
|
+
| **Cloud Run (hf-chat-ui + MongoDB sidecar)** | ~$8-30 (min-instances=1 for MongoDB persistence) |
|
|
913
|
+
| **Cloud Run (mcp-bridge)** | ~$2-10 (lightweight, auto-scales to 0) |
|
|
914
|
+
| **MongoDB** | $0 (bundled sidecar, no external service) |
|
|
915
|
+
| **ruvector-postgres** | $0 (already running for existing services) |
|
|
916
|
+
| **OpenAI API (GPT-5)** | Variable — depends on usage |
|
|
917
|
+
| **Google/Anthropic APIs** | Variable — uses existing Secret Manager keys |
|
|
918
|
+
| **SSL Certificate** | $0 (Google-managed) |
|
|
919
|
+
| **Custom Domain** | $0 (CNAME mapping is free) |
|
|
920
|
+
| **Total Infrastructure** | ~$10-40/month + AI provider usage |
|
|
921
|
+
|
|
922
|
+
---
|
|
923
|
+
|
|
924
|
+
## Consequences
|
|
925
|
+
|
|
926
|
+
### Positive
|
|
927
|
+
- **Immediate GPT-5 access** — no custom UI development needed
|
|
928
|
+
- **Multi-model selection** — users choose GPT-5, GPT-5-mini, GPT-4o, o3, etc.
|
|
929
|
+
- **MCP tool integration** — reuses all existing Cloud Functions without modification
|
|
930
|
+
- **Production-grade** — conversation history, auth, streaming, voice input out of the box
|
|
931
|
+
- **Community maintained** — 10,400+ stars, active development by HuggingFace
|
|
932
|
+
- **Zero disruption** — existing chat system continues operating independently
|
|
933
|
+
- **Cost effective** — MongoDB sidecar eliminates external DB cost, ruvector-postgres already running
|
|
934
|
+
- **Multi-provider resilience** — if one AI provider is down, users switch to another
|
|
935
|
+
|
|
936
|
+
### Negative
|
|
937
|
+
- **SvelteKit, not React** — different tech stack from existing chat system; team needs familiarity
|
|
938
|
+
- **MongoDB sidecar** — Chat UI requires MongoDB internally; sidecar approach means min-instances=1 for data persistence (Cloud Run stateless otherwise)
|
|
939
|
+
- **Less control** — upstream UI changes may require adaptation; customization is via env vars and assistants, not code
|
|
940
|
+
- **MCP bridge overhead** — extra network hop for tool calls (mitigated by Cloud Run co-location)
|
|
941
|
+
|
|
942
|
+
### Risks & Mitigations
|
|
943
|
+
| Risk | Mitigation |
|
|
944
|
+
|------|-----------|
|
|
945
|
+
| MongoDB sidecar data loss on scale-to-zero | Set min-instances=1; conversations are recoverable (AI can regenerate) |
|
|
946
|
+
| OpenAI API costs spike | Set `USAGE_LIMITS` to cap messages per minute; use gpt-5-nano for simple queries |
|
|
947
|
+
| HuggingFace Chat UI breaking changes | Pin to specific image tag, test before upgrading |
|
|
948
|
+
| MCP bridge latency | Co-locate in us-central1, same VPC as Cloud Functions |
|
|
949
|
+
| Custom domain SSL delay | Allow 24h for certificate provisioning |
|
|
950
|
+
| Provider key expiration | All keys in Secret Manager — rotate without redeployment |
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
## Updated Architecture Diagram (Full System)
|
|
955
|
+
|
|
956
|
+
```
|
|
957
|
+
┌──────────────────────────────────────────────────────────────────────────────────┐
|
|
958
|
+
│ GOOGLE CLOUD PLATFORM │
|
|
959
|
+
│ Project: new-project-473022 │
|
|
960
|
+
├──────────────────────────────────────────────────────────────────────────────────┤
|
|
961
|
+
│ │
|
|
962
|
+
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
|
963
|
+
│ │ VPC Network (conveyor-vpc) │ │
|
|
964
|
+
│ │ │ │
|
|
965
|
+
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
966
|
+
│ │ │ Cloud Run Services │ │ │
|
|
967
|
+
│ │ │ │ │ │
|
|
968
|
+
│ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │
|
|
969
|
+
│ │ │ │ hf-chat-ui │ │ chat-system │ │ mcp-bridge │ │ │ │
|
|
970
|
+
│ │ │ │ (NEW) │ │ (existing) │ │ (NEW) │ │ │ │
|
|
971
|
+
│ │ │ │ │ │ │ │ │ │ │ │
|
|
972
|
+
│ │ │ │ SvelteKit │ │ React+Vite │ │ MCP Server │ │ │ │
|
|
973
|
+
│ │ │ │ GPT-5 models │ │ Gemini │ │ Tool bridge │ │ │ │
|
|
974
|
+
│ │ │ │ Port 3000 │ │ Port 8080 │ │ Port 3001 │ │ │ │
|
|
975
|
+
│ │ │ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │ │ │
|
|
976
|
+
│ │ │ │ │ │ │ │
|
|
977
|
+
│ │ │ │chat.conveyorclaims.ai │ │ │ │
|
|
978
|
+
│ │ └─────────┼─────────────────────────────────────┼──────────────┘ │ │
|
|
979
|
+
│ │ │ │ │ │
|
|
980
|
+
│ │ ┌────────┼─────────────────────────────────────┼───────────────────┐ │ │
|
|
981
|
+
│ │ │ │ Cloud Functions │ │ │ │
|
|
982
|
+
│ │ │ │ │ │ │ │
|
|
983
|
+
│ │ │ │ • airtable-agent ◄─────────────────┤ │ │ │
|
|
984
|
+
│ │ │ │ • db-query-agent ◄─────────────────┤ │ │ │
|
|
985
|
+
│ │ │ │ • case-manager ◄─────────────────┤ │ │ │
|
|
986
|
+
│ │ │ │ • simulation-agent◄─────────────────┤ │ │ │
|
|
987
|
+
│ │ │ │ • workflow-search ◄─────────────────┘ │ │ │
|
|
988
|
+
│ │ │ │ │ │ │
|
|
989
|
+
│ │ └────────┼──────────────────────────────────────────────────────────┘ │ │
|
|
990
|
+
│ │ │ │ │
|
|
991
|
+
│ │ ┌────────▼─────────┐ │ │
|
|
992
|
+
│ │ │ ruvector-postgres│ │ │
|
|
993
|
+
│ │ │ 10.128.0.2:5432 │ │ │
|
|
994
|
+
│ │ │ PostgreSQL 17.7 │ │ │
|
|
995
|
+
│ │ │ ruvector 2.0.1 │ │ │
|
|
996
|
+
│ │ └──────────────────┘ │ │
|
|
997
|
+
│ └───────────────────────────────────────────────────────────────────────────────┘ │
|
|
998
|
+
│ │
|
|
999
|
+
│ ┌───────────────────────────┐ ┌───────────────────────────────────┐ │
|
|
1000
|
+
│ │ Secret Manager │ │ AI Providers (Multi-Provider) │ │
|
|
1001
|
+
│ │ • openai-api-key │ │ • OpenAI → GPT-5 family │ │
|
|
1002
|
+
│ │ • anthropic-api-key │ │ • Google → Gemini 2.5 │ │
|
|
1003
|
+
│ │ • google-api-key │ │ • Anthropic → Claude Sonnet 4 │ │
|
|
1004
|
+
│ │ • airtable-api-key │ └───────────────────────────────────┘ │
|
|
1005
|
+
│ │ • ruvector-db-password │ │
|
|
1006
|
+
│ └───────────────────────────┘ │
|
|
1007
|
+
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
---
|
|
1011
|
+
|
|
1012
|
+
## Service Inventory (Post-Implementation)
|
|
1013
|
+
|
|
1014
|
+
| Service | Domain | Purpose | Tools/Models |
|
|
1015
|
+
|---------|--------|---------|--------------|
|
|
1016
|
+
| **hf-chat-ui** (NEW) | `chat.conveyorclaims.ai` | Multi-provider chat with 3 MCP tool servers | GPT-5.2, GPT-5, GPT-5-mini, GPT-4o, o3, Gemini 2.5, Claude Sonnet 4 |
|
|
1017
|
+
| **mcp-bridge** (NEW) | internal | Custom MCP → Cloud Functions + ruvector-postgres | 5 tools (search, query, case, sim, airtable) |
|
|
1018
|
+
| **Airtable MCP** (external) | `mcp.airtable.com` | Official Airtable direct access | Schema browse, CRUD, search |
|
|
1019
|
+
| **Google Drive MCP** (external) | `mcp.googleapis.com` | Official Google Drive access | File search, doc read, sheets |
|
|
1020
|
+
| **chat-system** (existing) | `chat-system-*.run.app` | Gemini-powered workflow chat | gemini-2.5-pro/flash |
|
|
1021
|
+
| **mcp-server** (existing) | `mcp-server-*.run.app` | General MCP server | N/A |
|
|
1022
|
+
|
|
1023
|
+
---
|
|
1024
|
+
|
|
1025
|
+
## Timeline
|
|
1026
|
+
|
|
1027
|
+
| Phase | Duration | Deliverable |
|
|
1028
|
+
|-------|----------|-------------|
|
|
1029
|
+
| Phase 1: MongoDB Atlas | 1 hour | Free cluster + secret in Secret Manager |
|
|
1030
|
+
| Phase 2: MCP Bridge | 2-3 hours | Cloud Run service with 5 tools |
|
|
1031
|
+
| Phase 3: Model Config | 30 min | MODELS env var with 7 GPT-5 variants |
|
|
1032
|
+
| Phase 4: Chat UI Deploy | 1-2 hours | Cloud Run service from pre-built image |
|
|
1033
|
+
| Phase 5: Domain Mapping | 1-24 hours | `chat.conveyorclaims.ai` live (DNS propagation) |
|
|
1034
|
+
| Phase 6: System Prompt | 30 min | Default Conveyor AI assistant |
|
|
1035
|
+
| **Total** | **~1 day** | Full deployment |
|
|
1036
|
+
|
|
1037
|
+
---
|
|
1038
|
+
|
|
1039
|
+
## Next Steps
|
|
1040
|
+
|
|
1041
|
+
1. **Approve this ADR** and proceed to Phase 1 (MongoDB Atlas)
|
|
1042
|
+
2. Build and deploy the MCP Bridge server (Phase 2)
|
|
1043
|
+
3. Deploy Chat UI with GPT-5 models (Phases 3-4)
|
|
1044
|
+
4. Configure DNS and custom domain (Phase 5)
|
|
1045
|
+
5. Test end-to-end: model selection → tool calling → workflow search → response
|
|
1046
|
+
6. Configure Conveyor AI assistant with system prompt (Phase 6)
|
|
1047
|
+
7. Update ADR-028 to reference this parallel deployment
|
|
1048
|
+
|
|
1049
|
+
---
|
|
1050
|
+
|
|
1051
|
+
## Post-Deployment Updates (2026-03-03)
|
|
1052
|
+
|
|
1053
|
+
### Update 1: Google OIDC Authentication
|
|
1054
|
+
|
|
1055
|
+
Added Google OAuth login to restrict access to authenticated users only.
|
|
1056
|
+
|
|
1057
|
+
**Configuration approach:** HF Chat UI reads OIDC settings from the `DOTENV_LOCAL` environment variable, which acts as an in-memory `.env.local` file. Individual `OPENID_*` env vars are NOT read by Chat UI — they must be inside `DOTENV_LOCAL`.
|
|
1058
|
+
|
|
1059
|
+
**OAuth client:** `245235083640-gkbo4otq57lqeisuigcat0bg037f49oc.apps.googleusercontent.com` (Web Application type)
|
|
1060
|
+
|
|
1061
|
+
**Secret:** `google-client-secret` in Secret Manager (version 2) — `GOCSPX-QzuZ-...`
|
|
1062
|
+
|
|
1063
|
+
**Redirect URI:** `https://chat.conveyorclaims.ai/login/callback` (added manually in Google Cloud Console → APIs & Services → Credentials)
|
|
1064
|
+
|
|
1065
|
+
**OIDC env vars added to DOTENV_LOCAL:**
|
|
1066
|
+
```ini
|
|
1067
|
+
OPENID_PROVIDER_URL=https://accounts.google.com
|
|
1068
|
+
OPENID_CLIENT_ID=245235083640-gkbo4otq57lqeisuigcat0bg037f49oc.apps.googleusercontent.com
|
|
1069
|
+
OPENID_SCOPES=openid profile email
|
|
1070
|
+
OPENID_NAME_CLAIM=name
|
|
1071
|
+
COOKIE_SECURE=true
|
|
1072
|
+
COOKIE_SAMESITE=lax
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
**Key lesson:** IAP OAuth clients (`*-9lt8...`) cannot be used for custom web OIDC flows — they are locked to IAP-specific redirect patterns. Only standard Web Application OAuth clients work.
|
|
1076
|
+
|
|
1077
|
+
**Files modified:**
|
|
1078
|
+
- `infrastructure/gcp/hf-chat-ui/update-preprompt.js` — added OIDC vars to DOTENV_LOCAL output
|
|
1079
|
+
- `infrastructure/gcp/hf-chat-ui/cloudbuild.yaml` — added OIDC env vars + `OPENID_CLIENT_SECRET` secret binding
|
|
1080
|
+
- `infrastructure/gcp/hf-chat-ui/deploy.sh` — added OIDC env vars + secret binding
|
|
1081
|
+
|
|
1082
|
+
### Update 2: Branded Welcome Animation
|
|
1083
|
+
|
|
1084
|
+
Replaced the default HuggingFace `omni-welcome.gif` with a branded "Conveyor AI" animated GIF matching the Three.js `AnimatedBackground.tsx` aesthetic from the existing chat system.
|
|
1085
|
+
|
|
1086
|
+
**Design:**
|
|
1087
|
+
- 480x320px, 90 frames (3s @ 30fps), ~1.75 MB
|
|
1088
|
+
- Dark background `#0d0d1a`
|
|
1089
|
+
- Rotating wireframe geometric shapes (icosahedron + octahedron) in cyan/blue/indigo
|
|
1090
|
+
- Scattered glowing dots matching blue-500/sky-500/indigo-500 palette
|
|
1091
|
+
- "Conveyor AI" text centered with subtle glow effect
|
|
1092
|
+
|
|
1093
|
+
**Implementation:**
|
|
1094
|
+
- `infrastructure/gcp/hf-chat-ui/generate-welcome.cjs` — Node.js script using `canvas` + `gif-encoder-2` (`.cjs` extension required because root `package.json` has `"type": "module"`)
|
|
1095
|
+
- `infrastructure/gcp/hf-chat-ui/Dockerfile` — extends `ghcr.io/huggingface/chat-ui-db:latest`, copies branded GIF to `/app/build/client/chatui/omni-welcome.gif` and `/app/static/chatui/omni-welcome.gif`
|
|
1096
|
+
- `infrastructure/gcp/hf-chat-ui/cloudbuild.yaml` — changed from pull+tag to Docker build with custom Dockerfile
|
|
1097
|
+
|
|
1098
|
+
### Update 3: MCP Bridge Tool Mapping Fixes
|
|
1099
|
+
|
|
1100
|
+
Fixed all 5 tool-to-Cloud-Function mappings in the MCP Bridge. Every tool was sending incorrect or missing parameters to its backend Cloud Function.
|
|
1101
|
+
|
|
1102
|
+
| Tool | Issue | Fix |
|
|
1103
|
+
|------|-------|-----|
|
|
1104
|
+
| `search_workflows` | Was working | No change needed |
|
|
1105
|
+
| `query_database` | Missing `action` field entirely | Added `action: "nl_query"` |
|
|
1106
|
+
| `manage_case` | Sent `status` as action, backend expects `get` | Map `status` → `get`, `next_steps` → `get` |
|
|
1107
|
+
| `run_simulation` | Missing `action` field, wrong field names | Added `action: "run_qlearning"`, mapped `scenario` → `caseType`, `episodes` → `iterations` |
|
|
1108
|
+
| `airtable_query` | Wrong field name `table` (backend expects `tableName`), wrong action names | Map `list` → `query`, `get` → `get_case_status`, `create`/`update` → `upsert` |
|
|
1109
|
+
|
|
1110
|
+
**File modified:** `infrastructure/gcp/mcp-bridge/index.js`
|
|
1111
|
+
|
|
1112
|
+
### Update 4: Natural Language to SQL (db-query-agent)
|
|
1113
|
+
|
|
1114
|
+
Added `nl_query` action to the db-query-agent Cloud Function. This enables natural language questions like "How many cases were opened this month?" to be converted to SQL via Gemini.
|
|
1115
|
+
|
|
1116
|
+
**Flow:** Natural language → Gemini generates SQL → validate (no DROP/DELETE) → execute against ruvector-postgres → return results
|
|
1117
|
+
|
|
1118
|
+
**File modified:** `infrastructure/gcp/functions/db-query-agent/index.js`
|
|
1119
|
+
|
|
1120
|
+
### Update 5: Multi-Provider Chat Completions Proxy
|
|
1121
|
+
|
|
1122
|
+
Added an OpenAI-compatible `/chat/completions` proxy to the MCP Bridge that routes requests to the correct AI provider based on model name. This enables HF Chat UI to use `OPENAI_BASE_URL` pointing to the MCP Bridge, which then routes:
|
|
1123
|
+
- `gpt-*`, `o*-*` models → OpenAI API
|
|
1124
|
+
- `gemini-*` models → Google Generative Language API
|
|
1125
|
+
|
|
1126
|
+
Also added `/models` endpoint returning only the curated model list (7 models) instead of the full OpenAI model catalog (114+ models).
|
|
1127
|
+
|
|
1128
|
+
**File modified:** `infrastructure/gcp/mcp-bridge/index.js`
|
|
1129
|
+
|
|
1130
|
+
### Deployment Status (2026-03-03)
|
|
1131
|
+
|
|
1132
|
+
| Component | Deployed? | Notes |
|
|
1133
|
+
|-----------|-----------|-------|
|
|
1134
|
+
| HF Chat UI (with OIDC + branded GIF) | Yes | Custom Docker image with Dockerfile |
|
|
1135
|
+
| MCP Bridge (with tool fixes + proxy) | Yes | All 5 tools validated working |
|
|
1136
|
+
| db-query-agent (with nl_query) | Yes | Entry point: `dbQueryAgent` |
|
|
1137
|
+
|
|
1138
|
+
---
|
|
1139
|
+
|
|
1140
|
+
## Post-Deployment Updates (2026-03-04)
|
|
1141
|
+
|
|
1142
|
+
### Update 6: Server-Side API Key Fix
|
|
1143
|
+
|
|
1144
|
+
Fixed 401 errors where the MCP Bridge was forwarding the user's Google OAuth token to OpenAI instead of using the server-side API key.
|
|
1145
|
+
|
|
1146
|
+
**Root cause:** `getKey: (req) => req.headers.authorization?.replace("Bearer ", "") || process.env.OPENAI_API_KEY` extracted the OIDC session token `ya29.A0A...` and sent it to OpenAI.
|
|
1147
|
+
|
|
1148
|
+
**Fix:** Changed to `getKey: () => process.env.OPENAI_API_KEY` — always use server-side key. Added `OPENAI_API_KEY=openai-api-key:latest` to MCP bridge `cloudbuild.yaml` `--set-secrets`.
|
|
1149
|
+
|
|
1150
|
+
### Update 7: Airtable Table Name Mapping
|
|
1151
|
+
|
|
1152
|
+
Added `TABLE_MAP` to the MCP Bridge to translate friendly table names to actual Airtable table names. The LLM sends `"table": "Cases"` but Airtable expects `"All Cases (dev)"`.
|
|
1153
|
+
|
|
1154
|
+
| Friendly Name | Actual Airtable Name |
|
|
1155
|
+
|---------------|---------------------|
|
|
1156
|
+
| Cases | All Cases (dev) |
|
|
1157
|
+
| Managed Cases | Managed Cases (dev) |
|
|
1158
|
+
| Clients / Contacts | Contacts |
|
|
1159
|
+
| Carriers / Partners | Co-Counsel & Referral Partners |
|
|
1160
|
+
| Users | Conveyor Users |
|
|
1161
|
+
| Invoices | Invoices |
|
|
1162
|
+
| Payments | Payments |
|
|
1163
|
+
| Emails | Emails |
|
|
1164
|
+
|
|
1165
|
+
### Update 8: Case Search by Number and Client Name
|
|
1166
|
+
|
|
1167
|
+
Enhanced `airtable_query` tool to support searching by case number or client name instead of only listing all records.
|
|
1168
|
+
|
|
1169
|
+
- Added `search` action and `search` parameter to tool schema
|
|
1170
|
+
- Case number patterns (e.g., `C-01748`) route to `get_case_status` for precise lookup
|
|
1171
|
+
- Name searches use `query` with `{search: searchTerm}` for fuzzy matching
|
|
1172
|
+
- `manage_case` status/next_steps now route to airtable-agent's `get_case_status` for better results
|
|
1173
|
+
|
|
1174
|
+
### Update 9: Table-Aware Search Formula
|
|
1175
|
+
|
|
1176
|
+
Fixed "Unknown field names" errors when searching non-case tables. The airtable-agent search formula previously hardcoded `{Case Number}` which doesn't exist in tables like `Co-Counsel & Referral Partners`.
|
|
1177
|
+
|
|
1178
|
+
**Fix:** Added `TABLE_SEARCH_FIELDS` map in `airtable-agent/index.js`:
|
|
1179
|
+
|
|
1180
|
+
| Table | Search Fields |
|
|
1181
|
+
|-------|--------------|
|
|
1182
|
+
| All Cases (dev) | Case Number |
|
|
1183
|
+
| Contacts | Full Name, Email |
|
|
1184
|
+
| Co-Counsel & Referral Partners | Partner Name |
|
|
1185
|
+
| Invoices | Invoice Number, Reference Number |
|
|
1186
|
+
| Conveyor Users | Full Name, Email Address |
|
|
1187
|
+
|
|
1188
|
+
### Update 10: Multi-Provider Model Catalog (17 Models)
|
|
1189
|
+
|
|
1190
|
+
Expanded from 7 models to 17 models across 6 providers. Gemini 2.5 Pro set as default (first position).
|
|
1191
|
+
|
|
1192
|
+
| Provider | Route | Models |
|
|
1193
|
+
|----------|-------|--------|
|
|
1194
|
+
| Google (direct) | Gemini API | Gemini 2.5 Pro (Default), Gemini 2.5 Flash |
|
|
1195
|
+
| OpenAI (direct) | OpenAI API | GPT-5.2 Pro, GPT-5, GPT-5 Mini, GPT-4o, o4-mini |
|
|
1196
|
+
| Anthropic | OpenRouter | Claude Sonnet 4.6, Claude Opus 4.6 |
|
|
1197
|
+
| Google next-gen | OpenRouter | Gemini 3 Pro Preview, Gemini 3 Flash Preview |
|
|
1198
|
+
| DeepSeek | OpenRouter | DeepSeek V3.2 |
|
|
1199
|
+
| Mistral | OpenRouter | Mistral Large, Devstral |
|
|
1200
|
+
| xAI | OpenRouter | Grok 4.1 Fast |
|
|
1201
|
+
| OpenAI latest | OpenRouter | GPT-5.3 Chat, GPT-5.3 Codex |
|
|
1202
|
+
|
|
1203
|
+
**MCP Bridge routing logic:** Models with `/` in the name (e.g., `anthropic/claude-sonnet-4.6`) route to OpenRouter. Models starting with `gemini-` route to Google direct. All others route to OpenAI direct.
|
|
1204
|
+
|
|
1205
|
+
### Update 11: Docker-Baked Configuration
|
|
1206
|
+
|
|
1207
|
+
Moved MODELS config from Cloud Run env vars to Docker image `.env.local` file. The full MODELS JSON with 17 model preprompts exceeds the 32KB Cloud Run env var limit.
|
|
1208
|
+
|
|
1209
|
+
**Architecture:** `update-preprompt.js` generates `dotenv-local.txt` → Dockerfile copies to `/app/.env.local` → HF Chat UI reads at startup. Cloud Run env vars provide secrets only (API keys via Secret Manager).
|
|
1210
|
+
|
|
1211
|
+
### Update 12: PWA Icon and Session Cookies
|
|
1212
|
+
|
|
1213
|
+
- Added 144x144 PNG icon to Dockerfile (fixes `/chat/chatui/icon-144x144.png` 404)
|
|
1214
|
+
- Added `COOKIE_MAX_AGE=604800` (7-day sessions) to reduce OAuth redirect frequency
|
|
1215
|
+
|
|
1216
|
+
### Deployment Status (2026-03-04)
|
|
1217
|
+
|
|
1218
|
+
| Component | Version | Status |
|
|
1219
|
+
|-----------|---------|--------|
|
|
1220
|
+
| HF Chat UI | hf-chat-ui-00026 | Live — 17 models, OIDC, branded GIF, PWA icon |
|
|
1221
|
+
| MCP Bridge | v2026030419xx | Live — OpenRouter routing, table mapping, search |
|
|
1222
|
+
| airtable-agent | Gen2 | Live — table-aware search formula |
|
|
1223
|
+
| db-query-agent | Gen2 | Live — nl_query action |
|
|
1224
|
+
|
|
1225
|
+
---
|
|
1226
|
+
|
|
1227
|
+
## Related ADRs
|
|
1228
|
+
|
|
1229
|
+
| ADR | Relationship |
|
|
1230
|
+
|-----|-------------|
|
|
1231
|
+
| ADR-014 | Existing chat system architecture (continues independently) |
|
|
1232
|
+
| ADR-015 | Cloud Functions reused via MCP Bridge |
|
|
1233
|
+
| ADR-022 | Workflow documents in ruvector-postgres searched via tools |
|
|
1234
|
+
| ADR-024 | Workflow context injection pattern adapted for MCP tools |
|
|
1235
|
+
| ADR-027 | Response formatting rules carried into system prompt |
|
|
1236
|
+
| ADR-028 | OpenAI GPT-5 integration in existing chat system (complementary) |
|