ruflo 3.5.2 → 3.5.3

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.
Files changed (521) hide show
  1. package/dist/rvf.manifest.json +295 -0
  2. package/package.json +16 -2
  3. package/src/chat-ui/Dockerfile +25 -0
  4. package/src/chat-ui/patch-mcp-url-safety.sh +28 -0
  5. package/src/chat-ui/static/chatui/icon-144x144.png +0 -0
  6. package/src/chat-ui/static/chatui/omni-welcome.gif +0 -0
  7. package/src/config/config.example.json +76 -0
  8. package/src/mcp-bridge/Dockerfile +45 -0
  9. package/src/mcp-bridge/index.js +1668 -0
  10. package/src/mcp-bridge/mcp-stdio-kernel.js +159 -0
  11. package/src/mcp-bridge/package.json +17 -0
  12. package/src/mcp-bridge/test-harness.js +470 -0
  13. package/src/nginx/Dockerfile +10 -0
  14. package/src/nginx/nginx.conf +67 -0
  15. package/src/nginx/static/favicon-dark.svg +4 -0
  16. package/src/nginx/static/favicon.svg +4 -0
  17. package/src/nginx/static/icon.svg +5 -0
  18. package/src/nginx/static/logo.svg +9 -0
  19. package/src/nginx/static/manifest.json +22 -0
  20. package/src/nginx/static/welcome.js +184 -0
  21. package/src/ruvocal/.claude/skills/add-model-descriptions/SKILL.md +73 -0
  22. package/src/ruvocal/.devcontainer/Dockerfile +9 -0
  23. package/src/ruvocal/.devcontainer/devcontainer.json +36 -0
  24. package/src/ruvocal/.dockerignore +13 -0
  25. package/src/ruvocal/.env +194 -0
  26. package/src/ruvocal/.env.ci +1 -0
  27. package/src/ruvocal/.eslintignore +13 -0
  28. package/src/ruvocal/.eslintrc.cjs +45 -0
  29. package/src/ruvocal/.github/ISSUE_TEMPLATE/bug-report--chat-ui-.md +43 -0
  30. package/src/ruvocal/.github/ISSUE_TEMPLATE/config-support.md +9 -0
  31. package/src/ruvocal/.github/ISSUE_TEMPLATE/feature-request--chat-ui-.md +17 -0
  32. package/src/ruvocal/.github/ISSUE_TEMPLATE/huggingchat.md +11 -0
  33. package/src/ruvocal/.github/release.yml +16 -0
  34. package/src/ruvocal/.github/workflows/build-docs.yml +18 -0
  35. package/src/ruvocal/.github/workflows/build-image.yml +142 -0
  36. package/src/ruvocal/.github/workflows/build-pr-docs.yml +20 -0
  37. package/src/ruvocal/.github/workflows/deploy-dev.yml +63 -0
  38. package/src/ruvocal/.github/workflows/deploy-prod.yml +78 -0
  39. package/src/ruvocal/.github/workflows/lint-and-test.yml +84 -0
  40. package/src/ruvocal/.github/workflows/slugify.yaml +72 -0
  41. package/src/ruvocal/.github/workflows/trufflehog.yml +17 -0
  42. package/src/ruvocal/.github/workflows/upload-pr-documentation.yml +16 -0
  43. package/src/ruvocal/.husky/lint-stage-config.js +4 -0
  44. package/src/ruvocal/.husky/pre-commit +2 -0
  45. package/src/ruvocal/.prettierignore +14 -0
  46. package/src/ruvocal/.prettierrc +7 -0
  47. package/src/ruvocal/.vscode/launch.json +11 -0
  48. package/src/ruvocal/.vscode/settings.json +14 -0
  49. package/src/ruvocal/CLAUDE.md +126 -0
  50. package/src/ruvocal/Dockerfile +93 -0
  51. package/src/ruvocal/LICENSE +203 -0
  52. package/src/ruvocal/PRIVACY.md +41 -0
  53. package/src/ruvocal/README.md +190 -0
  54. package/src/ruvocal/chart/Chart.yaml +5 -0
  55. package/src/ruvocal/chart/env/dev.yaml +260 -0
  56. package/src/ruvocal/chart/env/prod.yaml +273 -0
  57. package/src/ruvocal/chart/templates/_helpers.tpl +22 -0
  58. package/src/ruvocal/chart/templates/config.yaml +10 -0
  59. package/src/ruvocal/chart/templates/deployment.yaml +81 -0
  60. package/src/ruvocal/chart/templates/hpa.yaml +45 -0
  61. package/src/ruvocal/chart/templates/infisical.yaml +24 -0
  62. package/src/ruvocal/chart/templates/ingress-internal.yaml +32 -0
  63. package/src/ruvocal/chart/templates/ingress.yaml +32 -0
  64. package/src/ruvocal/chart/templates/network-policy.yaml +36 -0
  65. package/src/ruvocal/chart/templates/service-account.yaml +13 -0
  66. package/src/ruvocal/chart/templates/service-monitor.yaml +17 -0
  67. package/src/ruvocal/chart/templates/service.yaml +21 -0
  68. package/src/ruvocal/chart/values.yaml +73 -0
  69. package/src/ruvocal/docker-compose.yml +21 -0
  70. package/src/ruvocal/docs/adr/ADR-029-HUGGINGFACE-CHAT-UI-CLOUD-RUN.md +1236 -0
  71. package/src/ruvocal/docs/adr/ADR-033-RUVECTOR-RUFLO-MCP-INTEGRATION.md +111 -0
  72. package/src/ruvocal/docs/adr/ADR-034-OPTIONAL-MCP-BACKENDS.md +117 -0
  73. package/src/ruvocal/docs/adr/ADR-035-MCP-TOOL-GROUPS.md +186 -0
  74. package/src/ruvocal/docs/adr/ADR-037-AUTOPILOT-CHAT-MODE.md +1500 -0
  75. package/src/ruvocal/docs/adr/ADR-038-RUVOCAL-FORK.md +286 -0
  76. package/src/ruvocal/docs/source/_toctree.yml +30 -0
  77. package/src/ruvocal/docs/source/configuration/common-issues.md +38 -0
  78. package/src/ruvocal/docs/source/configuration/llm-router.md +105 -0
  79. package/src/ruvocal/docs/source/configuration/mcp-tools.md +84 -0
  80. package/src/ruvocal/docs/source/configuration/metrics.md +9 -0
  81. package/src/ruvocal/docs/source/configuration/open-id.md +57 -0
  82. package/src/ruvocal/docs/source/configuration/overview.md +89 -0
  83. package/src/ruvocal/docs/source/configuration/theming.md +20 -0
  84. package/src/ruvocal/docs/source/developing/architecture.md +48 -0
  85. package/src/ruvocal/docs/source/index.md +53 -0
  86. package/src/ruvocal/docs/source/installation/docker.md +43 -0
  87. package/src/ruvocal/docs/source/installation/helm.md +43 -0
  88. package/src/ruvocal/docs/source/installation/local.md +62 -0
  89. package/src/ruvocal/entrypoint.sh +19 -0
  90. package/src/ruvocal/mcp-bridge/.claude-flow/agents/store.json +27 -0
  91. package/src/ruvocal/mcp-bridge/.claude-flow/daemon-state.json +130 -0
  92. package/src/ruvocal/mcp-bridge/.claude-flow/daemon.log +0 -0
  93. package/src/ruvocal/mcp-bridge/.claude-flow/daemon.pid +1 -0
  94. package/src/ruvocal/mcp-bridge/.claude-flow/tasks/store.json +21 -0
  95. package/src/ruvocal/mcp-bridge/.swarm/hnsw.index +0 -0
  96. package/src/ruvocal/mcp-bridge/.swarm/hnsw.metadata.json +1 -0
  97. package/src/ruvocal/mcp-bridge/.swarm/memory.db +0 -0
  98. package/src/ruvocal/mcp-bridge/.swarm/model-router-state.json +14 -0
  99. package/src/ruvocal/mcp-bridge/.swarm/schema.sql +305 -0
  100. package/src/ruvocal/mcp-bridge/Dockerfile +45 -0
  101. package/src/ruvocal/mcp-bridge/cloudbuild.yaml +49 -0
  102. package/src/ruvocal/mcp-bridge/index.js +1864 -0
  103. package/src/ruvocal/mcp-bridge/mcp-stdio-kernel.js +159 -0
  104. package/src/ruvocal/mcp-bridge/package-lock.json +762 -0
  105. package/src/ruvocal/mcp-bridge/package.json +17 -0
  106. package/src/ruvocal/mcp-bridge/test-harness.js +470 -0
  107. package/src/ruvocal/models/add-your-models-here.txt +1 -0
  108. package/src/ruvocal/package-lock.json +11741 -0
  109. package/src/ruvocal/package.json +121 -0
  110. package/src/ruvocal/postcss.config.js +6 -0
  111. package/src/ruvocal/rvf.manifest.json +204 -0
  112. package/src/ruvocal/scripts/config.ts +64 -0
  113. package/src/ruvocal/scripts/generate-welcome.mjs +181 -0
  114. package/src/ruvocal/scripts/populate.ts +288 -0
  115. package/src/ruvocal/scripts/samples.txt +194 -0
  116. package/src/ruvocal/scripts/setups/vitest-setup-client.ts +0 -0
  117. package/src/ruvocal/scripts/setups/vitest-setup-server.ts +44 -0
  118. package/src/ruvocal/scripts/updateLocalEnv.ts +48 -0
  119. package/src/ruvocal/src/ambient.d.ts +7 -0
  120. package/src/ruvocal/src/app.d.ts +29 -0
  121. package/src/ruvocal/src/app.html +53 -0
  122. package/src/ruvocal/src/hooks.server.ts +32 -0
  123. package/src/ruvocal/src/hooks.ts +6 -0
  124. package/src/ruvocal/src/lib/APIClient.ts +148 -0
  125. package/src/ruvocal/src/lib/actions/clickOutside.ts +18 -0
  126. package/src/ruvocal/src/lib/actions/snapScrollToBottom.ts +346 -0
  127. package/src/ruvocal/src/lib/buildPrompt.ts +33 -0
  128. package/src/ruvocal/src/lib/components/AnnouncementBanner.svelte +20 -0
  129. package/src/ruvocal/src/lib/components/BackgroundGenerationPoller.svelte +168 -0
  130. package/src/ruvocal/src/lib/components/CodeBlock.svelte +73 -0
  131. package/src/ruvocal/src/lib/components/CopyToClipBoardBtn.svelte +92 -0
  132. package/src/ruvocal/src/lib/components/DeleteConversationModal.svelte +75 -0
  133. package/src/ruvocal/src/lib/components/EditConversationModal.svelte +100 -0
  134. package/src/ruvocal/src/lib/components/ExpandNavigation.svelte +22 -0
  135. package/src/ruvocal/src/lib/components/HoverTooltip.svelte +44 -0
  136. package/src/ruvocal/src/lib/components/HtmlPreviewModal.svelte +143 -0
  137. package/src/ruvocal/src/lib/components/InfiniteScroll.svelte +50 -0
  138. package/src/ruvocal/src/lib/components/MobileNav.svelte +300 -0
  139. package/src/ruvocal/src/lib/components/Modal.svelte +115 -0
  140. package/src/ruvocal/src/lib/components/ModelCardMetadata.svelte +71 -0
  141. package/src/ruvocal/src/lib/components/NavConversationItem.svelte +151 -0
  142. package/src/ruvocal/src/lib/components/NavMenu.svelte +295 -0
  143. package/src/ruvocal/src/lib/components/Pagination.svelte +97 -0
  144. package/src/ruvocal/src/lib/components/PaginationArrow.svelte +27 -0
  145. package/src/ruvocal/src/lib/components/Portal.svelte +24 -0
  146. package/src/ruvocal/src/lib/components/RetryBtn.svelte +18 -0
  147. package/src/ruvocal/src/lib/components/RuFloUniverse.svelte +185 -0
  148. package/src/ruvocal/src/lib/components/ScrollToBottomBtn.svelte +47 -0
  149. package/src/ruvocal/src/lib/components/ScrollToPreviousBtn.svelte +77 -0
  150. package/src/ruvocal/src/lib/components/ShareConversationModal.svelte +182 -0
  151. package/src/ruvocal/src/lib/components/StopGeneratingBtn.svelte +69 -0
  152. package/src/ruvocal/src/lib/components/SubscribeModal.svelte +87 -0
  153. package/src/ruvocal/src/lib/components/Switch.svelte +36 -0
  154. package/src/ruvocal/src/lib/components/SystemPromptModal.svelte +44 -0
  155. package/src/ruvocal/src/lib/components/Toast.svelte +27 -0
  156. package/src/ruvocal/src/lib/components/Tooltip.svelte +30 -0
  157. package/src/ruvocal/src/lib/components/WelcomeModal.svelte +46 -0
  158. package/src/ruvocal/src/lib/components/chat/Alternatives.svelte +77 -0
  159. package/src/ruvocal/src/lib/components/chat/BlockWrapper.svelte +72 -0
  160. package/src/ruvocal/src/lib/components/chat/ChatInput.svelte +490 -0
  161. package/src/ruvocal/src/lib/components/chat/ChatIntroduction.svelte +123 -0
  162. package/src/ruvocal/src/lib/components/chat/ChatMessage.svelte +548 -0
  163. package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +939 -0
  164. package/src/ruvocal/src/lib/components/chat/FileDropzone.svelte +92 -0
  165. package/src/ruvocal/src/lib/components/chat/ImageLightbox.svelte +66 -0
  166. package/src/ruvocal/src/lib/components/chat/MarkdownBlock.svelte +23 -0
  167. package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte +69 -0
  168. package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte.test.ts +58 -0
  169. package/src/ruvocal/src/lib/components/chat/MessageAvatar.svelte +103 -0
  170. package/src/ruvocal/src/lib/components/chat/ModelSwitch.svelte +64 -0
  171. package/src/ruvocal/src/lib/components/chat/OpenReasoningResults.svelte +81 -0
  172. package/src/ruvocal/src/lib/components/chat/TaskGroup.svelte +88 -0
  173. package/src/ruvocal/src/lib/components/chat/ToolUpdate.svelte +273 -0
  174. package/src/ruvocal/src/lib/components/chat/UploadedFile.svelte +253 -0
  175. package/src/ruvocal/src/lib/components/chat/UrlFetchModal.svelte +203 -0
  176. package/src/ruvocal/src/lib/components/chat/VoiceRecorder.svelte +214 -0
  177. package/src/ruvocal/src/lib/components/icons/IconBurger.svelte +20 -0
  178. package/src/ruvocal/src/lib/components/icons/IconCheap.svelte +20 -0
  179. package/src/ruvocal/src/lib/components/icons/IconChevron.svelte +24 -0
  180. package/src/ruvocal/src/lib/components/icons/IconDazzled.svelte +40 -0
  181. package/src/ruvocal/src/lib/components/icons/IconFast.svelte +20 -0
  182. package/src/ruvocal/src/lib/components/icons/IconLoading.svelte +22 -0
  183. package/src/ruvocal/src/lib/components/icons/IconMCP.svelte +28 -0
  184. package/src/ruvocal/src/lib/components/icons/IconMoon.svelte +21 -0
  185. package/src/ruvocal/src/lib/components/icons/IconNew.svelte +20 -0
  186. package/src/ruvocal/src/lib/components/icons/IconOmni.svelte +90 -0
  187. package/src/ruvocal/src/lib/components/icons/IconPaperclip.svelte +24 -0
  188. package/src/ruvocal/src/lib/components/icons/IconPro.svelte +37 -0
  189. package/src/ruvocal/src/lib/components/icons/IconShare.svelte +21 -0
  190. package/src/ruvocal/src/lib/components/icons/IconSun.svelte +93 -0
  191. package/src/ruvocal/src/lib/components/icons/Logo.svelte +68 -0
  192. package/src/ruvocal/src/lib/components/icons/LogoHuggingFaceBorderless.svelte +54 -0
  193. package/src/ruvocal/src/lib/components/mcp/AddServerForm.svelte +250 -0
  194. package/src/ruvocal/src/lib/components/mcp/MCPServerManager.svelte +185 -0
  195. package/src/ruvocal/src/lib/components/mcp/ServerCard.svelte +203 -0
  196. package/src/ruvocal/src/lib/components/players/AudioPlayer.svelte +82 -0
  197. package/src/ruvocal/src/lib/components/voice/AudioWaveform.svelte +96 -0
  198. package/src/ruvocal/src/lib/constants/mcpExamples.ts +135 -0
  199. package/src/ruvocal/src/lib/constants/mime.ts +11 -0
  200. package/src/ruvocal/src/lib/constants/pagination.ts +1 -0
  201. package/src/ruvocal/src/lib/constants/publicSepToken.ts +1 -0
  202. package/src/ruvocal/src/lib/constants/routerExamples.ts +209 -0
  203. package/src/ruvocal/src/lib/createShareLink.ts +27 -0
  204. package/src/ruvocal/src/lib/jobs/refresh-conversation-stats.ts +297 -0
  205. package/src/ruvocal/src/lib/migrations/lock.ts +56 -0
  206. package/src/ruvocal/src/lib/migrations/migrations.spec.ts +74 -0
  207. package/src/ruvocal/src/lib/migrations/migrations.ts +109 -0
  208. package/src/ruvocal/src/lib/migrations/routines/01-update-search-assistants.ts +50 -0
  209. package/src/ruvocal/src/lib/migrations/routines/02-update-assistants-models.ts +48 -0
  210. package/src/ruvocal/src/lib/migrations/routines/04-update-message-updates.ts +151 -0
  211. package/src/ruvocal/src/lib/migrations/routines/05-update-message-files.ts +56 -0
  212. package/src/ruvocal/src/lib/migrations/routines/06-trim-message-updates.ts +56 -0
  213. package/src/ruvocal/src/lib/migrations/routines/08-update-featured-to-review.ts +32 -0
  214. package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.spec.ts +214 -0
  215. package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.ts +88 -0
  216. package/src/ruvocal/src/lib/migrations/routines/10-update-reports-assistantid.ts +29 -0
  217. package/src/ruvocal/src/lib/migrations/routines/index.ts +15 -0
  218. package/src/ruvocal/src/lib/server/__tests__/conversation-stop-generating.spec.ts +103 -0
  219. package/src/ruvocal/src/lib/server/abortRegistry.ts +57 -0
  220. package/src/ruvocal/src/lib/server/abortedGenerations.ts +43 -0
  221. package/src/ruvocal/src/lib/server/adminToken.ts +62 -0
  222. package/src/ruvocal/src/lib/server/api/__tests__/conversations-id.spec.ts +296 -0
  223. package/src/ruvocal/src/lib/server/api/__tests__/conversations-message.spec.ts +216 -0
  224. package/src/ruvocal/src/lib/server/api/__tests__/conversations.spec.ts +235 -0
  225. package/src/ruvocal/src/lib/server/api/__tests__/misc.spec.ts +72 -0
  226. package/src/ruvocal/src/lib/server/api/__tests__/testHelpers.ts +86 -0
  227. package/src/ruvocal/src/lib/server/api/__tests__/user-reports.spec.ts +78 -0
  228. package/src/ruvocal/src/lib/server/api/__tests__/user.spec.ts +239 -0
  229. package/src/ruvocal/src/lib/server/api/types.ts +37 -0
  230. package/src/ruvocal/src/lib/server/api/utils/requireAuth.ts +22 -0
  231. package/src/ruvocal/src/lib/server/api/utils/resolveConversation.ts +69 -0
  232. package/src/ruvocal/src/lib/server/api/utils/resolveModel.ts +27 -0
  233. package/src/ruvocal/src/lib/server/api/utils/superjsonResponse.ts +15 -0
  234. package/src/ruvocal/src/lib/server/apiToken.ts +11 -0
  235. package/src/ruvocal/src/lib/server/auth.ts +554 -0
  236. package/src/ruvocal/src/lib/server/config.ts +187 -0
  237. package/src/ruvocal/src/lib/server/conversation.ts +83 -0
  238. package/src/ruvocal/src/lib/server/database/__tests__/rvf.spec.ts +709 -0
  239. package/src/ruvocal/src/lib/server/database/postgres.ts +700 -0
  240. package/src/ruvocal/src/lib/server/database/rvf.ts +1078 -0
  241. package/src/ruvocal/src/lib/server/database.ts +145 -0
  242. package/src/ruvocal/src/lib/server/endpoints/document.ts +68 -0
  243. package/src/ruvocal/src/lib/server/endpoints/endpoints.ts +43 -0
  244. package/src/ruvocal/src/lib/server/endpoints/images.ts +211 -0
  245. package/src/ruvocal/src/lib/server/endpoints/openai/endpointOai.ts +266 -0
  246. package/src/ruvocal/src/lib/server/endpoints/openai/openAIChatToTextGenerationStream.ts +212 -0
  247. package/src/ruvocal/src/lib/server/endpoints/openai/openAICompletionToTextGenerationStream.ts +32 -0
  248. package/src/ruvocal/src/lib/server/endpoints/preprocessMessages.ts +61 -0
  249. package/src/ruvocal/src/lib/server/exitHandler.ts +59 -0
  250. package/src/ruvocal/src/lib/server/files/downloadFile.ts +34 -0
  251. package/src/ruvocal/src/lib/server/files/uploadFile.ts +29 -0
  252. package/src/ruvocal/src/lib/server/findRepoRoot.ts +13 -0
  253. package/src/ruvocal/src/lib/server/fonts/Inter-Black.ttf +0 -0
  254. package/src/ruvocal/src/lib/server/fonts/Inter-Bold.ttf +0 -0
  255. package/src/ruvocal/src/lib/server/fonts/Inter-ExtraBold.ttf +0 -0
  256. package/src/ruvocal/src/lib/server/fonts/Inter-ExtraLight.ttf +0 -0
  257. package/src/ruvocal/src/lib/server/fonts/Inter-Light.ttf +0 -0
  258. package/src/ruvocal/src/lib/server/fonts/Inter-Medium.ttf +0 -0
  259. package/src/ruvocal/src/lib/server/fonts/Inter-Regular.ttf +0 -0
  260. package/src/ruvocal/src/lib/server/fonts/Inter-SemiBold.ttf +0 -0
  261. package/src/ruvocal/src/lib/server/fonts/Inter-Thin.ttf +0 -0
  262. package/src/ruvocal/src/lib/server/generateFromDefaultEndpoint.ts +46 -0
  263. package/src/ruvocal/src/lib/server/hooks/error.ts +37 -0
  264. package/src/ruvocal/src/lib/server/hooks/fetch.ts +22 -0
  265. package/src/ruvocal/src/lib/server/hooks/handle.ts +250 -0
  266. package/src/ruvocal/src/lib/server/hooks/init.ts +51 -0
  267. package/src/ruvocal/src/lib/server/isURLLocal.spec.ts +31 -0
  268. package/src/ruvocal/src/lib/server/isURLLocal.ts +74 -0
  269. package/src/ruvocal/src/lib/server/logger.ts +42 -0
  270. package/src/ruvocal/src/lib/server/mcp/clientPool.ts +70 -0
  271. package/src/ruvocal/src/lib/server/mcp/hf.ts +32 -0
  272. package/src/ruvocal/src/lib/server/mcp/httpClient.ts +122 -0
  273. package/src/ruvocal/src/lib/server/mcp/registry.ts +76 -0
  274. package/src/ruvocal/src/lib/server/mcp/tools.ts +196 -0
  275. package/src/ruvocal/src/lib/server/metrics.ts +255 -0
  276. package/src/ruvocal/src/lib/server/models.ts +518 -0
  277. package/src/ruvocal/src/lib/server/requestContext.ts +55 -0
  278. package/src/ruvocal/src/lib/server/router/arch.ts +230 -0
  279. package/src/ruvocal/src/lib/server/router/endpoint.ts +316 -0
  280. package/src/ruvocal/src/lib/server/router/multimodal.ts +28 -0
  281. package/src/ruvocal/src/lib/server/router/policy.ts +49 -0
  282. package/src/ruvocal/src/lib/server/router/toolsRoute.ts +51 -0
  283. package/src/ruvocal/src/lib/server/router/types.ts +21 -0
  284. package/src/ruvocal/src/lib/server/sendSlack.ts +23 -0
  285. package/src/ruvocal/src/lib/server/textGeneration/generate.ts +258 -0
  286. package/src/ruvocal/src/lib/server/textGeneration/index.ts +95 -0
  287. package/src/ruvocal/src/lib/server/textGeneration/mcp/fileRefs.ts +155 -0
  288. package/src/ruvocal/src/lib/server/textGeneration/mcp/routerResolution.ts +108 -0
  289. package/src/ruvocal/src/lib/server/textGeneration/mcp/runMcpFlow.ts +822 -0
  290. package/src/ruvocal/src/lib/server/textGeneration/mcp/toolInvocation.ts +349 -0
  291. package/src/ruvocal/src/lib/server/textGeneration/reasoning.ts +23 -0
  292. package/src/ruvocal/src/lib/server/textGeneration/title.ts +83 -0
  293. package/src/ruvocal/src/lib/server/textGeneration/types.ts +26 -0
  294. package/src/ruvocal/src/lib/server/textGeneration/utils/prepareFiles.ts +88 -0
  295. package/src/ruvocal/src/lib/server/textGeneration/utils/routing.ts +21 -0
  296. package/src/ruvocal/src/lib/server/textGeneration/utils/toolPrompt.ts +49 -0
  297. package/src/ruvocal/src/lib/server/urlSafety.ts +72 -0
  298. package/src/ruvocal/src/lib/server/usageLimits.ts +30 -0
  299. package/src/ruvocal/src/lib/stores/autopilotStore.svelte.ts +175 -0
  300. package/src/ruvocal/src/lib/stores/backgroundGenerations.svelte.ts +32 -0
  301. package/src/ruvocal/src/lib/stores/backgroundGenerations.ts +1 -0
  302. package/src/ruvocal/src/lib/stores/errors.ts +9 -0
  303. package/src/ruvocal/src/lib/stores/isAborted.ts +3 -0
  304. package/src/ruvocal/src/lib/stores/isPro.ts +4 -0
  305. package/src/ruvocal/src/lib/stores/loading.ts +3 -0
  306. package/src/ruvocal/src/lib/stores/mcpServers.ts +345 -0
  307. package/src/ruvocal/src/lib/stores/pendingChatInput.ts +3 -0
  308. package/src/ruvocal/src/lib/stores/pendingMessage.ts +9 -0
  309. package/src/ruvocal/src/lib/stores/settings.ts +182 -0
  310. package/src/ruvocal/src/lib/stores/shareModal.ts +13 -0
  311. package/src/ruvocal/src/lib/stores/titleUpdate.ts +8 -0
  312. package/src/ruvocal/src/lib/switchTheme.ts +124 -0
  313. package/src/ruvocal/src/lib/types/AbortedGeneration.ts +8 -0
  314. package/src/ruvocal/src/lib/types/Assistant.ts +31 -0
  315. package/src/ruvocal/src/lib/types/AssistantStats.ts +11 -0
  316. package/src/ruvocal/src/lib/types/ConfigKey.ts +4 -0
  317. package/src/ruvocal/src/lib/types/ConvSidebar.ts +9 -0
  318. package/src/ruvocal/src/lib/types/Conversation.ts +27 -0
  319. package/src/ruvocal/src/lib/types/ConversationStats.ts +13 -0
  320. package/src/ruvocal/src/lib/types/Message.ts +41 -0
  321. package/src/ruvocal/src/lib/types/MessageEvent.ts +10 -0
  322. package/src/ruvocal/src/lib/types/MessageUpdate.ts +139 -0
  323. package/src/ruvocal/src/lib/types/MigrationResult.ts +7 -0
  324. package/src/ruvocal/src/lib/types/Model.ts +23 -0
  325. package/src/ruvocal/src/lib/types/Report.ts +12 -0
  326. package/src/ruvocal/src/lib/types/Review.ts +6 -0
  327. package/src/ruvocal/src/lib/types/Semaphore.ts +19 -0
  328. package/src/ruvocal/src/lib/types/Session.ts +22 -0
  329. package/src/ruvocal/src/lib/types/Settings.ts +86 -0
  330. package/src/ruvocal/src/lib/types/SharedConversation.ts +9 -0
  331. package/src/ruvocal/src/lib/types/Template.ts +6 -0
  332. package/src/ruvocal/src/lib/types/Timestamps.ts +4 -0
  333. package/src/ruvocal/src/lib/types/TokenCache.ts +6 -0
  334. package/src/ruvocal/src/lib/types/Tool.ts +74 -0
  335. package/src/ruvocal/src/lib/types/UrlDependency.ts +5 -0
  336. package/src/ruvocal/src/lib/types/User.ts +14 -0
  337. package/src/ruvocal/src/lib/utils/PublicConfig.svelte.ts +75 -0
  338. package/src/ruvocal/src/lib/utils/auth.ts +17 -0
  339. package/src/ruvocal/src/lib/utils/chunk.ts +33 -0
  340. package/src/ruvocal/src/lib/utils/cookiesAreEnabled.ts +13 -0
  341. package/src/ruvocal/src/lib/utils/debounce.ts +17 -0
  342. package/src/ruvocal/src/lib/utils/deepestChild.ts +6 -0
  343. package/src/ruvocal/src/lib/utils/favicon.ts +21 -0
  344. package/src/ruvocal/src/lib/utils/fetchJSON.ts +23 -0
  345. package/src/ruvocal/src/lib/utils/file2base64.ts +14 -0
  346. package/src/ruvocal/src/lib/utils/formatUserCount.ts +37 -0
  347. package/src/ruvocal/src/lib/utils/generationState.spec.ts +75 -0
  348. package/src/ruvocal/src/lib/utils/generationState.ts +26 -0
  349. package/src/ruvocal/src/lib/utils/getHref.ts +41 -0
  350. package/src/ruvocal/src/lib/utils/getReturnFromGenerator.ts +7 -0
  351. package/src/ruvocal/src/lib/utils/haptics.ts +64 -0
  352. package/src/ruvocal/src/lib/utils/hashConv.ts +12 -0
  353. package/src/ruvocal/src/lib/utils/hf.ts +17 -0
  354. package/src/ruvocal/src/lib/utils/isDesktop.ts +7 -0
  355. package/src/ruvocal/src/lib/utils/isUrl.ts +8 -0
  356. package/src/ruvocal/src/lib/utils/isVirtualKeyboard.ts +16 -0
  357. package/src/ruvocal/src/lib/utils/loadAttachmentsFromUrls.ts +115 -0
  358. package/src/ruvocal/src/lib/utils/marked.spec.ts +96 -0
  359. package/src/ruvocal/src/lib/utils/marked.ts +531 -0
  360. package/src/ruvocal/src/lib/utils/mcpValidation.ts +147 -0
  361. package/src/ruvocal/src/lib/utils/mergeAsyncGenerators.ts +38 -0
  362. package/src/ruvocal/src/lib/utils/messageUpdates.spec.ts +262 -0
  363. package/src/ruvocal/src/lib/utils/messageUpdates.ts +324 -0
  364. package/src/ruvocal/src/lib/utils/mime.ts +56 -0
  365. package/src/ruvocal/src/lib/utils/models.ts +14 -0
  366. package/src/ruvocal/src/lib/utils/parseBlocks.ts +120 -0
  367. package/src/ruvocal/src/lib/utils/parseIncompleteMarkdown.ts +644 -0
  368. package/src/ruvocal/src/lib/utils/parseStringToList.ts +10 -0
  369. package/src/ruvocal/src/lib/utils/randomUuid.ts +14 -0
  370. package/src/ruvocal/src/lib/utils/searchTokens.ts +33 -0
  371. package/src/ruvocal/src/lib/utils/sha256.ts +7 -0
  372. package/src/ruvocal/src/lib/utils/stringifyError.ts +12 -0
  373. package/src/ruvocal/src/lib/utils/sum.ts +3 -0
  374. package/src/ruvocal/src/lib/utils/template.spec.ts +59 -0
  375. package/src/ruvocal/src/lib/utils/template.ts +53 -0
  376. package/src/ruvocal/src/lib/utils/timeout.ts +9 -0
  377. package/src/ruvocal/src/lib/utils/toolProgress.spec.ts +46 -0
  378. package/src/ruvocal/src/lib/utils/toolProgress.ts +11 -0
  379. package/src/ruvocal/src/lib/utils/tree/addChildren.spec.ts +102 -0
  380. package/src/ruvocal/src/lib/utils/tree/addChildren.ts +48 -0
  381. package/src/ruvocal/src/lib/utils/tree/addSibling.spec.ts +81 -0
  382. package/src/ruvocal/src/lib/utils/tree/addSibling.ts +41 -0
  383. package/src/ruvocal/src/lib/utils/tree/buildSubtree.spec.ts +110 -0
  384. package/src/ruvocal/src/lib/utils/tree/buildSubtree.ts +24 -0
  385. package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.spec.ts +31 -0
  386. package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.ts +36 -0
  387. package/src/ruvocal/src/lib/utils/tree/isMessageId.spec.ts +15 -0
  388. package/src/ruvocal/src/lib/utils/tree/isMessageId.ts +5 -0
  389. package/src/ruvocal/src/lib/utils/tree/tree.d.ts +14 -0
  390. package/src/ruvocal/src/lib/utils/tree/treeHelpers.spec.ts +167 -0
  391. package/src/ruvocal/src/lib/utils/updates.ts +39 -0
  392. package/src/ruvocal/src/lib/utils/urlParams.ts +13 -0
  393. package/src/ruvocal/src/lib/workers/autopilotWorker.ts +221 -0
  394. package/src/ruvocal/src/lib/workers/detailFetchWorker.ts +100 -0
  395. package/src/ruvocal/src/lib/workers/markdownWorker.ts +61 -0
  396. package/src/ruvocal/src/routes/+error.svelte +20 -0
  397. package/src/ruvocal/src/routes/+layout.svelte +324 -0
  398. package/src/ruvocal/src/routes/+layout.ts +91 -0
  399. package/src/ruvocal/src/routes/+page.svelte +168 -0
  400. package/src/ruvocal/src/routes/.well-known/oauth-cimd/+server.ts +37 -0
  401. package/src/ruvocal/src/routes/__debug/openai/+server.ts +21 -0
  402. package/src/ruvocal/src/routes/admin/export/+server.ts +159 -0
  403. package/src/ruvocal/src/routes/admin/stats/compute/+server.ts +16 -0
  404. package/src/ruvocal/src/routes/api/conversation/[id]/+server.ts +40 -0
  405. package/src/ruvocal/src/routes/api/conversation/[id]/message/[messageId]/+server.ts +42 -0
  406. package/src/ruvocal/src/routes/api/conversations/+server.ts +48 -0
  407. package/src/ruvocal/src/routes/api/fetch-url/+server.ts +147 -0
  408. package/src/ruvocal/src/routes/api/mcp/health/+server.ts +292 -0
  409. package/src/ruvocal/src/routes/api/mcp/servers/+server.ts +32 -0
  410. package/src/ruvocal/src/routes/api/models/+server.ts +25 -0
  411. package/src/ruvocal/src/routes/api/transcribe/+server.ts +104 -0
  412. package/src/ruvocal/src/routes/api/user/+server.ts +15 -0
  413. package/src/ruvocal/src/routes/api/user/validate-token/+server.ts +20 -0
  414. package/src/ruvocal/src/routes/api/v2/conversations/+server.ts +48 -0
  415. package/src/ruvocal/src/routes/api/v2/conversations/[id]/+server.ts +94 -0
  416. package/src/ruvocal/src/routes/api/v2/conversations/[id]/message/[messageId]/+server.ts +43 -0
  417. package/src/ruvocal/src/routes/api/v2/conversations/import-share/+server.ts +23 -0
  418. package/src/ruvocal/src/routes/api/v2/debug/config/+server.ts +16 -0
  419. package/src/ruvocal/src/routes/api/v2/debug/refresh/+server.ts +30 -0
  420. package/src/ruvocal/src/routes/api/v2/export/+server.ts +196 -0
  421. package/src/ruvocal/src/routes/api/v2/feature-flags/+server.ts +14 -0
  422. package/src/ruvocal/src/routes/api/v2/models/+server.ts +38 -0
  423. package/src/ruvocal/src/routes/api/v2/models/[namespace]/+server.ts +8 -0
  424. package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/+server.ts +8 -0
  425. package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/subscribe/+server.ts +28 -0
  426. package/src/ruvocal/src/routes/api/v2/models/[namespace]/subscribe/+server.ts +28 -0
  427. package/src/ruvocal/src/routes/api/v2/models/old/+server.ts +7 -0
  428. package/src/ruvocal/src/routes/api/v2/models/refresh/+server.ts +33 -0
  429. package/src/ruvocal/src/routes/api/v2/public-config/+server.ts +7 -0
  430. package/src/ruvocal/src/routes/api/v2/user/+server.ts +17 -0
  431. package/src/ruvocal/src/routes/api/v2/user/billing-orgs/+server.ts +73 -0
  432. package/src/ruvocal/src/routes/api/v2/user/reports/+server.ts +17 -0
  433. package/src/ruvocal/src/routes/api/v2/user/settings/+server.ts +103 -0
  434. package/src/ruvocal/src/routes/conversation/+server.ts +115 -0
  435. package/src/ruvocal/src/routes/conversation/[id]/+page.svelte +582 -0
  436. package/src/ruvocal/src/routes/conversation/[id]/+page.ts +60 -0
  437. package/src/ruvocal/src/routes/conversation/[id]/+server.ts +736 -0
  438. package/src/ruvocal/src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +66 -0
  439. package/src/ruvocal/src/routes/conversation/[id]/output/[sha256]/+server.ts +58 -0
  440. package/src/ruvocal/src/routes/conversation/[id]/share/+server.ts +69 -0
  441. package/src/ruvocal/src/routes/conversation/[id]/stop-generating/+server.ts +35 -0
  442. package/src/ruvocal/src/routes/healthcheck/+server.ts +3 -0
  443. package/src/ruvocal/src/routes/login/+server.ts +5 -0
  444. package/src/ruvocal/src/routes/login/callback/+server.ts +103 -0
  445. package/src/ruvocal/src/routes/login/callback/updateUser.spec.ts +157 -0
  446. package/src/ruvocal/src/routes/login/callback/updateUser.ts +215 -0
  447. package/src/ruvocal/src/routes/logout/+server.ts +18 -0
  448. package/src/ruvocal/src/routes/metrics/+server.ts +18 -0
  449. package/src/ruvocal/src/routes/models/+page.svelte +233 -0
  450. package/src/ruvocal/src/routes/models/[...model]/+page.svelte +161 -0
  451. package/src/ruvocal/src/routes/models/[...model]/+page.ts +14 -0
  452. package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/+server.ts +64 -0
  453. package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/ModelThumbnail.svelte +28 -0
  454. package/src/ruvocal/src/routes/privacy/+page.svelte +11 -0
  455. package/src/ruvocal/src/routes/r/[id]/+page.ts +34 -0
  456. package/src/ruvocal/src/routes/settings/(nav)/+layout.svelte +282 -0
  457. package/src/ruvocal/src/routes/settings/(nav)/+layout.ts +1 -0
  458. package/src/ruvocal/src/routes/settings/(nav)/+page.svelte +0 -0
  459. package/src/ruvocal/src/routes/settings/(nav)/+server.ts +53 -0
  460. package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.svelte +464 -0
  461. package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.ts +14 -0
  462. package/src/ruvocal/src/routes/settings/(nav)/application/+page.svelte +362 -0
  463. package/src/ruvocal/src/routes/settings/+layout.svelte +40 -0
  464. package/src/ruvocal/src/styles/highlight-js.css +195 -0
  465. package/src/ruvocal/src/styles/main.css +144 -0
  466. package/src/ruvocal/static/chatui/apple-touch-icon.png +0 -0
  467. package/src/ruvocal/static/chatui/favicon-dark.svg +3 -0
  468. package/src/ruvocal/static/chatui/favicon-dev.svg +3 -0
  469. package/src/ruvocal/static/chatui/favicon.ico +0 -0
  470. package/src/ruvocal/static/chatui/favicon.svg +3 -0
  471. package/src/ruvocal/static/chatui/icon-128x128.png +0 -0
  472. package/src/ruvocal/static/chatui/icon-144x144.png +0 -0
  473. package/src/ruvocal/static/chatui/icon-192x192.png +0 -0
  474. package/src/ruvocal/static/chatui/icon-256x256.png +0 -0
  475. package/src/ruvocal/static/chatui/icon-36x36.png +0 -0
  476. package/src/ruvocal/static/chatui/icon-48x48.png +0 -0
  477. package/src/ruvocal/static/chatui/icon-512x512.png +0 -0
  478. package/src/ruvocal/static/chatui/icon-72x72.png +0 -0
  479. package/src/ruvocal/static/chatui/icon-96x96.png +0 -0
  480. package/src/ruvocal/static/chatui/icon.svg +3 -0
  481. package/src/ruvocal/static/chatui/logo.svg +7 -0
  482. package/src/ruvocal/static/chatui/manifest.json +54 -0
  483. package/src/ruvocal/static/chatui/omni-welcome.gif +0 -0
  484. package/src/ruvocal/static/chatui/omni-welcome.png +0 -0
  485. package/src/ruvocal/static/chatui/welcome.js +184 -0
  486. package/src/ruvocal/static/chatui/welcome.svg +1 -0
  487. package/src/ruvocal/static/huggingchat/apple-touch-icon.png +0 -0
  488. package/src/ruvocal/static/huggingchat/assistants-thumbnail.png +0 -0
  489. package/src/ruvocal/static/huggingchat/castle-example.jpg +0 -0
  490. package/src/ruvocal/static/huggingchat/favicon-dark.svg +4 -0
  491. package/src/ruvocal/static/huggingchat/favicon-dev.svg +4 -0
  492. package/src/ruvocal/static/huggingchat/favicon.ico +0 -0
  493. package/src/ruvocal/static/huggingchat/favicon.svg +4 -0
  494. package/src/ruvocal/static/huggingchat/fulltext-logo.svg +2 -0
  495. package/src/ruvocal/static/huggingchat/icon-128x128.png +0 -0
  496. package/src/ruvocal/static/huggingchat/icon-144x144.png +0 -0
  497. package/src/ruvocal/static/huggingchat/icon-192x192.png +0 -0
  498. package/src/ruvocal/static/huggingchat/icon-256x256.png +0 -0
  499. package/src/ruvocal/static/huggingchat/icon-36x36.png +0 -0
  500. package/src/ruvocal/static/huggingchat/icon-48x48.png +0 -0
  501. package/src/ruvocal/static/huggingchat/icon-512x512.png +0 -0
  502. package/src/ruvocal/static/huggingchat/icon-72x72.png +0 -0
  503. package/src/ruvocal/static/huggingchat/icon-96x96.png +0 -0
  504. package/src/ruvocal/static/huggingchat/icon.svg +4 -0
  505. package/src/ruvocal/static/huggingchat/logo.svg +4 -0
  506. package/src/ruvocal/static/huggingchat/manifest.json +54 -0
  507. package/src/ruvocal/static/huggingchat/omni-welcome.gif +0 -0
  508. package/src/ruvocal/static/huggingchat/routes.chat.json +226 -0
  509. package/src/ruvocal/static/huggingchat/thumbnail.png +0 -0
  510. package/src/ruvocal/static/huggingchat/tools-thumbnail.png +0 -0
  511. package/src/ruvocal/static/robots.txt +10 -0
  512. package/src/ruvocal/stub/@reflink/reflink/index.js +0 -0
  513. package/src/ruvocal/stub/@reflink/reflink/package.json +5 -0
  514. package/src/ruvocal/svelte.config.js +53 -0
  515. package/src/ruvocal/tailwind.config.cjs +30 -0
  516. package/src/ruvocal/tsconfig.json +19 -0
  517. package/src/ruvocal/vite.config.ts +87 -0
  518. package/src/scripts/deploy.sh +116 -0
  519. package/src/scripts/generate-config.js +245 -0
  520. package/src/scripts/generate-welcome.js +187 -0
  521. package/src/scripts/package-rvf.sh +116 -0
@@ -0,0 +1,292 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
4
+ import type { KeyValuePair } from "$lib/types/Tool";
5
+ import { config } from "$lib/server/config";
6
+ import { logger } from "$lib/server/logger";
7
+ import type { RequestHandler } from "./$types";
8
+ import { isValidUrl } from "$lib/server/urlSafety";
9
+ import { isStrictHfMcpLogin, hasNonEmptyToken, isExaMcpServer } from "$lib/server/mcp/hf";
10
+
11
+ interface HealthCheckRequest {
12
+ url: string;
13
+ headers?: KeyValuePair[];
14
+ }
15
+
16
+ interface HealthCheckResponse {
17
+ ready: boolean;
18
+ tools?: Array<{
19
+ name: string;
20
+ description?: string;
21
+ inputSchema?: unknown;
22
+ }>;
23
+ error?: string;
24
+ authRequired?: boolean;
25
+ }
26
+
27
+ export const POST: RequestHandler = async ({ request, locals }) => {
28
+ let client: Client | undefined;
29
+
30
+ try {
31
+ const body: HealthCheckRequest = await request.json();
32
+ const { url, headers } = body;
33
+
34
+ if (!url) {
35
+ return new Response(JSON.stringify({ ready: false, error: "URL is required" }), {
36
+ status: 400,
37
+ headers: { "Content-Type": "application/json" },
38
+ });
39
+ }
40
+
41
+ // URL validation handled above
42
+
43
+ if (!isValidUrl(url)) {
44
+ return new Response(
45
+ JSON.stringify({
46
+ ready: false,
47
+ error: "Invalid or unsafe URL (only HTTPS is supported)",
48
+ } as HealthCheckResponse),
49
+ { status: 400, headers: { "Content-Type": "application/json" } }
50
+ );
51
+ }
52
+
53
+ // Inject Exa API key for mcp.exa.ai servers via URL param
54
+ let finalUrl = url;
55
+ try {
56
+ const exaApiKey = config.EXA_API_KEY;
57
+ if (isExaMcpServer(url) && hasNonEmptyToken(exaApiKey)) {
58
+ const urlObj = new URL(url);
59
+ if (!urlObj.searchParams.has("exaApiKey")) {
60
+ urlObj.searchParams.set("exaApiKey", exaApiKey);
61
+ finalUrl = urlObj.toString();
62
+ logger.debug({}, "[MCP Health] injected Exa API key");
63
+ }
64
+ }
65
+ } catch {
66
+ // best-effort injection
67
+ }
68
+
69
+ const baseUrl = new URL(finalUrl);
70
+
71
+ // Minimal header handling
72
+ const headersRecord: Record<string, string> = headers?.length
73
+ ? Object.fromEntries(headers.map((h) => [h.key, h.value]))
74
+ : {};
75
+ if (!headersRecord["Accept"]) {
76
+ headersRecord["Accept"] = "application/json, text/event-stream";
77
+ }
78
+
79
+ // If enabled, attach the logged-in user's HF token only for the official HF MCP endpoint
80
+ try {
81
+ const shouldForward = config.MCP_FORWARD_HF_USER_TOKEN === "true";
82
+ const userToken =
83
+ (locals as unknown as { hfAccessToken?: string } | undefined)?.hfAccessToken ??
84
+ (locals as unknown as { token?: string } | undefined)?.token;
85
+ const hasAuth = typeof headersRecord["Authorization"] === "string";
86
+ const isHfMcpTarget = isStrictHfMcpLogin(url);
87
+ if (shouldForward && !hasAuth && isHfMcpTarget && hasNonEmptyToken(userToken)) {
88
+ headersRecord["Authorization"] = `Bearer ${userToken}`;
89
+ }
90
+ } catch {
91
+ // best-effort overlay
92
+ }
93
+
94
+ // Add an abort timeout to outbound requests (align with fetch-url: 30s)
95
+ const controller = new AbortController();
96
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
97
+ const signal = controller.signal;
98
+ const requestInit: RequestInit = {
99
+ headers: headersRecord,
100
+ signal,
101
+ };
102
+
103
+ let httpError: Error | undefined;
104
+ let lastError: Error | undefined;
105
+
106
+ // Try Streamable HTTP transport first
107
+ try {
108
+ logger.info({}, `[MCP Health] Trying HTTP transport for ${url}`);
109
+ client = new Client({
110
+ name: "chat-ui-health-check",
111
+ version: "1.0.0",
112
+ });
113
+
114
+ const transport = new StreamableHTTPClientTransport(baseUrl, { requestInit });
115
+ logger.info({}, `[MCP Health] Connecting to ${url}...`);
116
+ await client.connect(transport);
117
+ logger.info({}, `[MCP Health] Connected successfully via HTTP`);
118
+
119
+ // Connection successful, get tools
120
+ const toolsResponse = await client.listTools();
121
+
122
+ // Disconnect after getting tools
123
+ await client.close();
124
+
125
+ if (toolsResponse && toolsResponse.tools) {
126
+ const response: HealthCheckResponse = {
127
+ ready: true,
128
+ tools: toolsResponse.tools.map((tool) => ({
129
+ name: tool.name,
130
+ description: tool.description,
131
+ inputSchema: tool.inputSchema,
132
+ })),
133
+ authRequired: false,
134
+ };
135
+
136
+ const res = new Response(JSON.stringify(response), {
137
+ status: 200,
138
+ headers: { "Content-Type": "application/json" },
139
+ });
140
+ clearTimeout(timeoutId);
141
+ return res;
142
+ } else {
143
+ const res = new Response(
144
+ JSON.stringify({
145
+ ready: false,
146
+ error: "Connected but no tools available",
147
+ authRequired: false,
148
+ } as HealthCheckResponse),
149
+ {
150
+ status: 503,
151
+ headers: { "Content-Type": "application/json" },
152
+ }
153
+ );
154
+ clearTimeout(timeoutId);
155
+ return res;
156
+ }
157
+ } catch (error) {
158
+ httpError = error instanceof Error ? error : new Error(String(error));
159
+ lastError = httpError;
160
+ logger.warn(lastError.message, "Streamable HTTP failed, trying SSE transport...");
161
+
162
+ // Close failed client
163
+ try {
164
+ await client?.close();
165
+ } catch {
166
+ // Ignore
167
+ }
168
+
169
+ // Try SSE transport
170
+ try {
171
+ logger.info({}, `[MCP Health] Trying SSE transport for ${url}`);
172
+ client = new Client({
173
+ name: "chat-ui-health-check",
174
+ version: "1.0.0",
175
+ });
176
+
177
+ const sseTransport = new SSEClientTransport(baseUrl, { requestInit });
178
+ logger.info({}, `[MCP Health] Connecting via SSE...`);
179
+ await client.connect(sseTransport);
180
+ logger.info({}, `[MCP Health] Connected successfully via SSE`);
181
+
182
+ // Connection successful, get tools
183
+ const toolsResponse = await client.listTools();
184
+
185
+ // Disconnect after getting tools
186
+ await client.close();
187
+
188
+ if (toolsResponse && toolsResponse.tools) {
189
+ const response: HealthCheckResponse = {
190
+ ready: true,
191
+ tools: toolsResponse.tools.map((tool) => ({
192
+ name: tool.name,
193
+ description: tool.description,
194
+ inputSchema: tool.inputSchema,
195
+ })),
196
+ authRequired: false,
197
+ };
198
+
199
+ const res = new Response(JSON.stringify(response), {
200
+ status: 200,
201
+ headers: { "Content-Type": "application/json" },
202
+ });
203
+ clearTimeout(timeoutId);
204
+ return res;
205
+ } else {
206
+ const res = new Response(
207
+ JSON.stringify({
208
+ ready: false,
209
+ error: "Connected but no tools available",
210
+ authRequired: false,
211
+ } as HealthCheckResponse),
212
+ {
213
+ status: 503,
214
+ headers: { "Content-Type": "application/json" },
215
+ }
216
+ );
217
+ clearTimeout(timeoutId);
218
+ return res;
219
+ }
220
+ } catch (sseError) {
221
+ lastError = sseError instanceof Error ? sseError : new Error(String(sseError));
222
+ // Prefer the HTTP error when both failed so UI shows the primary failure (e.g., HTTP 500) instead
223
+ // of the fallback SSE message.
224
+ if (httpError) {
225
+ lastError = new Error(
226
+ `HTTP transport failed: ${httpError.message}; SSE fallback failed: ${lastError.message}`,
227
+ { cause: sseError instanceof Error ? sseError : undefined }
228
+ );
229
+ }
230
+ logger.error(lastError, "Both transports failed.");
231
+ }
232
+ }
233
+
234
+ // Both transports failed
235
+ let errorMessage = lastError?.message || "Failed to connect to MCP server";
236
+
237
+ // Detect unauthorized to signal auth requirement
238
+ const lower = (errorMessage || "").toLowerCase();
239
+ const authRequired =
240
+ lower.includes("unauthorized") ||
241
+ lower.includes("forbidden") ||
242
+ lower.includes("401") ||
243
+ lower.includes("403");
244
+
245
+ // Provide more helpful error messages
246
+ if (authRequired) {
247
+ errorMessage =
248
+ "Authentication required. Provide appropriate Authorization headers in the server configuration.";
249
+ } else if (errorMessage.includes("not valid JSON")) {
250
+ errorMessage =
251
+ "Server returned invalid response. This might not be a valid MCP endpoint. MCP servers should respond to POST requests at /mcp with JSON-RPC messages.";
252
+ } else if (errorMessage.includes("fetch failed") || errorMessage.includes("ECONNREFUSED")) {
253
+ errorMessage = `Cannot connect to ${url}. Please verify the server is running and accessible.`;
254
+ } else if (errorMessage.includes("CORS")) {
255
+ errorMessage = `CORS error. The MCP server needs to allow requests from this origin.`;
256
+ }
257
+
258
+ const res = new Response(
259
+ JSON.stringify({
260
+ ready: false,
261
+ error: errorMessage,
262
+ authRequired,
263
+ } as HealthCheckResponse),
264
+ {
265
+ status: 503,
266
+ headers: { "Content-Type": "application/json" },
267
+ }
268
+ );
269
+ clearTimeout(timeoutId);
270
+ return res;
271
+ } catch (error) {
272
+ logger.error(error, "MCP health check failed");
273
+
274
+ // Clean up client if it exists
275
+ try {
276
+ await client?.close();
277
+ } catch {
278
+ // Ignore
279
+ }
280
+
281
+ const response: HealthCheckResponse = {
282
+ ready: false,
283
+ error: error instanceof Error ? error.message : "Unknown error",
284
+ };
285
+
286
+ const res = new Response(JSON.stringify(response), {
287
+ status: 503,
288
+ headers: { "Content-Type": "application/json" },
289
+ });
290
+ return res;
291
+ }
292
+ };
@@ -0,0 +1,32 @@
1
+ import type { MCPServer } from "$lib/types/Tool";
2
+ import { config } from "$lib/server/config";
3
+
4
+ export async function GET() {
5
+ // Parse MCP_SERVERS environment variable
6
+ const mcpServersEnv = config.MCP_SERVERS || "[]";
7
+
8
+ let servers: Array<{ name: string; url: string; headers?: Record<string, string> }> = [];
9
+
10
+ try {
11
+ servers = JSON.parse(mcpServersEnv);
12
+ if (!Array.isArray(servers)) {
13
+ servers = [];
14
+ }
15
+ } catch (error) {
16
+ console.error("Failed to parse MCP_SERVERS env variable:", error);
17
+ servers = [];
18
+ }
19
+
20
+ // Convert internal server config to client MCPServer format
21
+ const mcpServers: MCPServer[] = servers.map((server) => ({
22
+ id: `base-${server.name}`, // Stable ID based on name
23
+ name: server.name,
24
+ url: server.url,
25
+ type: "base" as const,
26
+ // headers intentionally omitted
27
+ isLocked: false, // Base servers can be toggled by users
28
+ status: undefined, // Status determined client-side via health check
29
+ }));
30
+
31
+ return Response.json(mcpServers);
32
+ }
@@ -0,0 +1,25 @@
1
+ import { models } from "$lib/server/models";
2
+
3
+ export async function GET() {
4
+ const res = models
5
+ .filter((m) => m.unlisted == false)
6
+ .map((model) => ({
7
+ id: model.id,
8
+ name: model.name,
9
+ websiteUrl: model.websiteUrl ?? "https://huggingface.co",
10
+ modelUrl: model.modelUrl ?? "https://huggingface.co",
11
+ // tokenizer removed in this build
12
+ datasetName: model.datasetName,
13
+ datasetUrl: model.datasetUrl,
14
+ displayName: model.displayName,
15
+ description: model.description ?? "",
16
+ logoUrl: model.logoUrl,
17
+ promptExamples: model.promptExamples ?? [],
18
+ preprompt: model.preprompt ?? "",
19
+ multimodal: model.multimodal ?? false,
20
+ supportsTools: (model as unknown as { supportsTools?: boolean }).supportsTools ?? false,
21
+ unlisted: model.unlisted ?? false,
22
+ hasInferenceAPI: model.hasInferenceAPI ?? false,
23
+ }));
24
+ return Response.json(res);
25
+ }
@@ -0,0 +1,104 @@
1
+ import { error, json } from "@sveltejs/kit";
2
+ import { config } from "$lib/server/config";
3
+ import { getApiToken } from "$lib/server/apiToken";
4
+ import { logger } from "$lib/server/logger";
5
+
6
+ const MAX_AUDIO_SIZE = 25 * 1024 * 1024; // 25MB
7
+ const TRANSCRIPTION_TIMEOUT = 60000; // 60 seconds
8
+
9
+ const ALLOWED_CONTENT_TYPES = [
10
+ "audio/webm",
11
+ "audio/ogg",
12
+ "audio/wav",
13
+ "audio/flac",
14
+ "audio/mpeg",
15
+ "audio/mp4",
16
+ "audio/x-wav",
17
+ ];
18
+
19
+ export async function POST({ request, locals }) {
20
+ const transcriptionModel = config.get("TRANSCRIPTION_MODEL");
21
+
22
+ if (!transcriptionModel) {
23
+ throw error(503, "Transcription is not configured");
24
+ }
25
+
26
+ const token = getApiToken(locals);
27
+
28
+ if (!token) {
29
+ throw error(401, "Authentication required");
30
+ }
31
+
32
+ const rawContentType = request.headers.get("content-type") || "";
33
+ // Normalize content-type: Safari sends "audio/webm; codecs=opus" (with space)
34
+ // but HF API expects "audio/webm;codecs=opus" (no space)
35
+ const contentType = rawContentType.replace(/;\s+/g, ";");
36
+ const isAllowed = ALLOWED_CONTENT_TYPES.some((type) => contentType.includes(type));
37
+
38
+ if (!isAllowed) {
39
+ logger.warn({ contentType }, "Unsupported audio format for transcription");
40
+ throw error(400, `Unsupported audio format: ${contentType}`);
41
+ }
42
+
43
+ const contentLength = parseInt(request.headers.get("content-length") || "0");
44
+ if (contentLength > MAX_AUDIO_SIZE) {
45
+ throw error(413, "Audio file too large (max 25MB)");
46
+ }
47
+
48
+ try {
49
+ const audioBuffer = await request.arrayBuffer();
50
+
51
+ if (audioBuffer.byteLength > MAX_AUDIO_SIZE) {
52
+ throw error(413, "Audio file too large (max 25MB)");
53
+ }
54
+
55
+ const baseUrl =
56
+ config.get("TRANSCRIPTION_BASE_URL") || "https://router.huggingface.co/hf-inference/models";
57
+ const apiUrl = `${baseUrl}/${transcriptionModel}`;
58
+
59
+ const controller = new AbortController();
60
+ const timeoutId = setTimeout(() => controller.abort(), TRANSCRIPTION_TIMEOUT);
61
+
62
+ const response = await fetch(apiUrl, {
63
+ method: "POST",
64
+ headers: {
65
+ Authorization: `Bearer ${token}`,
66
+ "Content-Type": contentType,
67
+ // Bill to organization if configured
68
+ ...(locals?.billingOrganization ? { "X-HF-Bill-To": locals.billingOrganization } : {}),
69
+ },
70
+ body: audioBuffer,
71
+ signal: controller.signal,
72
+ }).finally(() => clearTimeout(timeoutId));
73
+
74
+ if (!response.ok) {
75
+ const errorText = await response.text();
76
+ logger.error(
77
+ { status: response.status, error: errorText, model: transcriptionModel },
78
+ "Whisper API error"
79
+ );
80
+ throw error(response.status, `Transcription failed: ${errorText}`);
81
+ }
82
+
83
+ const result = await response.json();
84
+
85
+ // Whisper API returns { text: "transcribed text" }
86
+ // Filter out responses that only contain dots (e.g. "..." returned for silence/unclear audio)
87
+ const text = (result.text || "").trim();
88
+ const isOnlyDots = /^\.+$/.test(text);
89
+ return json({ text: isOnlyDots ? "" : text });
90
+ } catch (err) {
91
+ if (err instanceof Error && err.name === "AbortError") {
92
+ logger.error({ model: transcriptionModel }, "Transcription timeout");
93
+ throw error(504, "Transcription took too long. Please try a shorter recording.");
94
+ }
95
+
96
+ // Re-throw SvelteKit errors
97
+ if (err && typeof err === "object" && "status" in err) {
98
+ throw err;
99
+ }
100
+
101
+ logger.error(err, "Transcription error");
102
+ throw error(500, "Failed to transcribe audio");
103
+ }
104
+ }
@@ -0,0 +1,15 @@
1
+ export async function GET({ locals }) {
2
+ if (locals.user) {
3
+ const res = {
4
+ id: locals.user._id,
5
+ username: locals.user.username,
6
+ name: locals.user.name,
7
+ email: locals.user.email,
8
+ avatarUrl: locals.user.avatarUrl,
9
+ hfUserId: locals.user.hfUserId,
10
+ };
11
+
12
+ return Response.json(res);
13
+ }
14
+ return Response.json({ message: "Must be signed in" }, { status: 401 });
15
+ }
@@ -0,0 +1,20 @@
1
+ import { adminTokenManager } from "$lib/server/adminToken";
2
+ import { z } from "zod";
3
+
4
+ const validateTokenSchema = z.object({
5
+ token: z.string(),
6
+ });
7
+
8
+ export const POST = async ({ request, locals }) => {
9
+ const { success, data } = validateTokenSchema.safeParse(await request.json());
10
+
11
+ if (!success) {
12
+ return new Response(JSON.stringify({ error: "Invalid token" }), { status: 400 });
13
+ }
14
+
15
+ if (adminTokenManager.checkToken(data.token, locals.sessionId)) {
16
+ return new Response(JSON.stringify({ valid: true }));
17
+ }
18
+
19
+ return new Response(JSON.stringify({ valid: false }));
20
+ };
@@ -0,0 +1,48 @@
1
+ import type { RequestHandler } from "@sveltejs/kit";
2
+ import { superjsonResponse } from "$lib/server/api/utils/superjsonResponse";
3
+ import { requireAuth } from "$lib/server/api/utils/requireAuth";
4
+ import { collections } from "$lib/server/database";
5
+ import { authCondition } from "$lib/server/auth";
6
+ import type { Conversation } from "$lib/types/Conversation";
7
+ import { CONV_NUM_PER_PAGE } from "$lib/constants/pagination";
8
+
9
+ export const GET: RequestHandler = async ({ locals, url }) => {
10
+ requireAuth(locals);
11
+
12
+ const pageSize = CONV_NUM_PER_PAGE;
13
+ const p = parseInt(url.searchParams.get("p") ?? "0") || 0;
14
+
15
+ const convs = await collections.conversations
16
+ .find(authCondition(locals))
17
+ .project<Pick<Conversation, "_id" | "title" | "updatedAt" | "model">>({
18
+ title: 1,
19
+ updatedAt: 1,
20
+ model: 1,
21
+ })
22
+ .sort({ updatedAt: -1 })
23
+ .skip(p * pageSize)
24
+ .limit(pageSize + 1)
25
+ .toArray();
26
+
27
+ const hasMore = convs.length > pageSize;
28
+ const res = (hasMore ? convs.slice(0, pageSize) : convs).map((conv) => ({
29
+ _id: conv._id,
30
+ id: conv._id, // legacy param iOS
31
+ title: conv.title,
32
+ updatedAt: conv.updatedAt,
33
+ model: conv.model,
34
+ modelId: conv.model, // legacy param iOS
35
+ }));
36
+
37
+ return superjsonResponse({ conversations: res, hasMore });
38
+ };
39
+
40
+ export const DELETE: RequestHandler = async ({ locals }) => {
41
+ requireAuth(locals);
42
+
43
+ const res = await collections.conversations.deleteMany({
44
+ ...authCondition(locals),
45
+ });
46
+
47
+ return superjsonResponse(res.deletedCount);
48
+ };
@@ -0,0 +1,94 @@
1
+ import { error, type RequestHandler } from "@sveltejs/kit";
2
+ import { superjsonResponse } from "$lib/server/api/utils/superjsonResponse";
3
+ import { requireAuth } from "$lib/server/api/utils/requireAuth";
4
+ import { resolveConversation } from "$lib/server/api/utils/resolveConversation";
5
+ import { collections } from "$lib/server/database";
6
+ import { authCondition } from "$lib/server/auth";
7
+ import { ObjectId } from "mongodb";
8
+ import { validModelIdSchema } from "$lib/server/models";
9
+
10
+ export const GET: RequestHandler = async ({ locals, params, url }) => {
11
+ requireAuth(locals);
12
+
13
+ const conversation = await resolveConversation(
14
+ params.id ?? "",
15
+ locals,
16
+ url.searchParams.get("fromShare")
17
+ );
18
+
19
+ return superjsonResponse({
20
+ messages: conversation.messages,
21
+ title: conversation.title,
22
+ model: conversation.model,
23
+ preprompt: conversation.preprompt,
24
+ rootMessageId: conversation.rootMessageId,
25
+ id: conversation._id.toString(),
26
+ updatedAt: conversation.updatedAt,
27
+ modelId: conversation.model,
28
+ shared: conversation.shared,
29
+ });
30
+ };
31
+
32
+ export const DELETE: RequestHandler = async ({ locals, params }) => {
33
+ requireAuth(locals);
34
+
35
+ const id = params.id ?? "";
36
+ if (!ObjectId.isValid(id)) {
37
+ error(400, "Invalid conversation ID");
38
+ }
39
+ const res = await collections.conversations.deleteOne({
40
+ _id: new ObjectId(id),
41
+ ...authCondition(locals),
42
+ });
43
+
44
+ if (res.deletedCount === 0) {
45
+ error(404, "Conversation not found");
46
+ }
47
+
48
+ return superjsonResponse({ success: true });
49
+ };
50
+
51
+ export const PATCH: RequestHandler = async ({ locals, params, request }) => {
52
+ requireAuth(locals);
53
+
54
+ const body = await request.json();
55
+ const title = body?.title as string | undefined;
56
+ const model = body?.model as string | undefined;
57
+
58
+ if (title !== undefined) {
59
+ if (typeof title !== "string" || title.length === 0 || title.length > 100) {
60
+ error(400, "Title must be a string between 1 and 100 characters");
61
+ }
62
+ }
63
+
64
+ if (model !== undefined) {
65
+ if (!validModelIdSchema.safeParse(model).success) {
66
+ error(400, "Invalid model ID");
67
+ }
68
+ }
69
+
70
+ const updateValues = {
71
+ ...(title !== undefined && {
72
+ title: title.replace(/<\/?think>/gi, "").trim(),
73
+ }),
74
+ ...(model !== undefined && { model }),
75
+ };
76
+
77
+ const id = params.id ?? "";
78
+ if (!ObjectId.isValid(id)) {
79
+ error(400, "Invalid conversation ID");
80
+ }
81
+ const res = await collections.conversations.updateOne(
82
+ {
83
+ _id: new ObjectId(id),
84
+ ...authCondition(locals),
85
+ },
86
+ { $set: updateValues }
87
+ );
88
+
89
+ if (typeof res.matchedCount === "number" ? res.matchedCount === 0 : res.modifiedCount === 0) {
90
+ error(404, "Conversation not found");
91
+ }
92
+
93
+ return superjsonResponse({ success: true });
94
+ };
@@ -0,0 +1,43 @@
1
+ import { error, type RequestHandler } from "@sveltejs/kit";
2
+ import { superjsonResponse } from "$lib/server/api/utils/superjsonResponse";
3
+ import { requireAuth } from "$lib/server/api/utils/requireAuth";
4
+ import { resolveConversation } from "$lib/server/api/utils/resolveConversation";
5
+ import { collections } from "$lib/server/database";
6
+ import { authCondition } from "$lib/server/auth";
7
+ import { ObjectId } from "mongodb";
8
+
9
+ export const DELETE: RequestHandler = async ({ locals, params }) => {
10
+ requireAuth(locals);
11
+
12
+ const id = params.id ?? "";
13
+ const messageId = params.messageId ?? "";
14
+
15
+ const conversation = await resolveConversation(id, locals);
16
+
17
+ if (!conversation.messages.map((m) => m.id).includes(messageId)) {
18
+ error(404, "Message not found");
19
+ }
20
+
21
+ const filteredMessages = conversation.messages
22
+ .filter(
23
+ (message) =>
24
+ !(message.id === messageId) && message.ancestors && !message.ancestors.includes(messageId)
25
+ )
26
+ .map((message) => {
27
+ if (message.children && message.children.includes(messageId)) {
28
+ message.children = message.children.filter((child) => child !== messageId);
29
+ }
30
+ return message;
31
+ });
32
+
33
+ const res = await collections.conversations.updateOne(
34
+ { _id: new ObjectId(conversation._id), ...authCondition(locals) },
35
+ { $set: { messages: filteredMessages } }
36
+ );
37
+
38
+ if (res.modifiedCount === 0) {
39
+ error(500, "Deleting message failed");
40
+ }
41
+
42
+ return superjsonResponse({ success: true });
43
+ };