ruflo 3.5.2 → 3.5.4

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,36 @@
1
+ import type { Conversation } from "$lib/types/Conversation";
2
+ import type { Message } from "$lib/types/Message";
3
+ import { v4 } from "uuid";
4
+
5
+ export function convertLegacyConversation(
6
+ conv: Pick<Conversation, "messages" | "rootMessageId" | "preprompt">
7
+ ): Pick<Conversation, "messages" | "rootMessageId" | "preprompt"> {
8
+ if (conv.rootMessageId) return conv; // not a legacy conversation
9
+ if (conv.messages.length === 0) return conv; // empty conversation
10
+ const messages = [
11
+ {
12
+ from: "system",
13
+ content: conv.preprompt ?? "",
14
+ createdAt: new Date(),
15
+ updatedAt: new Date(),
16
+ id: v4(),
17
+ } satisfies Message,
18
+ ...conv.messages,
19
+ ];
20
+
21
+ const rootMessageId = messages[0].id;
22
+
23
+ const newMessages = messages.map((message, index) => {
24
+ return {
25
+ ...message,
26
+ ancestors: messages.slice(0, index).map((m) => m.id),
27
+ children: index < messages.length - 1 ? [messages[index + 1].id] : [],
28
+ };
29
+ });
30
+
31
+ return {
32
+ ...conv,
33
+ rootMessageId,
34
+ messages: newMessages,
35
+ };
36
+ }
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isMessageId } from "./isMessageId";
3
+ import { v4 } from "uuid";
4
+
5
+ describe("isMessageId", () => {
6
+ it("should return true for a valid message id", () => {
7
+ expect(isMessageId(v4())).toBe(true);
8
+ });
9
+ it("should return false for an invalid message id", () => {
10
+ expect(isMessageId("1-2-3-4")).toBe(false);
11
+ });
12
+ it("should return false for an empty string", () => {
13
+ expect(isMessageId("")).toBe(false);
14
+ });
15
+ });
@@ -0,0 +1,5 @@
1
+ import type { Message } from "$lib/types/Message";
2
+
3
+ export function isMessageId(id: string): id is Message["id"] {
4
+ return id.split("-").length === 5;
5
+ }
@@ -0,0 +1,14 @@
1
+ export type TreeId = string;
2
+
3
+ export type Tree<T> = {
4
+ rootMessageId?: TreeId;
5
+ messages: TreeNode<T>[];
6
+ };
7
+
8
+ export type TreeNode<T> = T & {
9
+ id: TreeId;
10
+ ancestors?: TreeId[];
11
+ children?: TreeId[];
12
+ };
13
+
14
+ export type NewNode<T> = Omit<TreeNode<T>, "id">;
@@ -0,0 +1,167 @@
1
+ import { getCollectionsEarly } from "$lib/server/database";
2
+ import { ObjectId } from "mongodb";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ // function used to insert conversations used for testing
6
+ const getConversations = async () => (await getCollectionsEarly()).conversations;
7
+
8
+ export const insertLegacyConversation = async () => {
9
+ const conversations = await getConversations();
10
+ const res = await conversations.insertOne({
11
+ _id: new ObjectId(),
12
+ createdAt: new Date(),
13
+ updatedAt: new Date(),
14
+ title: "legacy conversation",
15
+ model: "",
16
+
17
+ messages: [
18
+ {
19
+ id: "1-1-1-1-1",
20
+ from: "user",
21
+ content: "Hello, world! I am a user",
22
+ },
23
+ {
24
+ id: "1-1-1-1-2",
25
+ from: "assistant",
26
+ content: "Hello, world! I am an assistant.",
27
+ },
28
+ {
29
+ id: "1-1-1-1-3",
30
+ from: "user",
31
+ content: "Hello, world! I am a user.",
32
+ },
33
+ {
34
+ id: "1-1-1-1-4",
35
+ from: "assistant",
36
+ content: "Hello, world! I am an assistant.",
37
+ },
38
+ ],
39
+ });
40
+ return res.insertedId;
41
+ };
42
+
43
+ export const insertLinearBranchConversation = async () => {
44
+ const conversations = await getConversations();
45
+ const res = await conversations.insertOne({
46
+ _id: new ObjectId(),
47
+ createdAt: new Date(),
48
+ updatedAt: new Date(),
49
+ title: "linear branch conversation",
50
+ model: "",
51
+
52
+ rootMessageId: "1-1-1-1-1",
53
+ messages: [
54
+ {
55
+ id: "1-1-1-1-1",
56
+ from: "user",
57
+ content: "Hello, world! I am a user",
58
+ ancestors: [],
59
+ children: ["1-1-1-1-2"],
60
+ },
61
+ {
62
+ id: "1-1-1-1-2",
63
+ from: "assistant",
64
+ content: "Hello, world! I am an assistant.",
65
+ ancestors: ["1-1-1-1-1"],
66
+ children: ["1-1-1-1-3"],
67
+ },
68
+ {
69
+ id: "1-1-1-1-3",
70
+ from: "user",
71
+ content: "Hello, world! I am a user.",
72
+ ancestors: ["1-1-1-1-1", "1-1-1-1-2"],
73
+ children: ["1-1-1-1-4"],
74
+ },
75
+ {
76
+ id: "1-1-1-1-4",
77
+ from: "assistant",
78
+ content: "Hello, world! I am an assistant.",
79
+ ancestors: ["1-1-1-1-1", "1-1-1-1-2", "1-1-1-1-3"],
80
+ children: [],
81
+ },
82
+ ],
83
+ });
84
+ return res.insertedId;
85
+ };
86
+
87
+ export const insertSideBranchesConversation = async () => {
88
+ const conversations = await getConversations();
89
+ const res = await conversations.insertOne({
90
+ _id: new ObjectId(),
91
+ createdAt: new Date(),
92
+ updatedAt: new Date(),
93
+ title: "side branches conversation",
94
+ model: "",
95
+
96
+ rootMessageId: "1-1-1-1-1",
97
+ messages: [
98
+ {
99
+ id: "1-1-1-1-1",
100
+ from: "user",
101
+ content: "Hello, world, root message!",
102
+ ancestors: [],
103
+ children: ["1-1-1-1-2", "1-1-1-1-5"],
104
+ },
105
+ {
106
+ id: "1-1-1-1-2",
107
+ from: "assistant",
108
+ content: "Hello, response to root message!",
109
+ ancestors: ["1-1-1-1-1"],
110
+ children: ["1-1-1-1-3"],
111
+ },
112
+ {
113
+ id: "1-1-1-1-3",
114
+ from: "user",
115
+ content: "Hello, follow up question!",
116
+ ancestors: ["1-1-1-1-1", "1-1-1-1-2"],
117
+ children: ["1-1-1-1-4"],
118
+ },
119
+ {
120
+ id: "1-1-1-1-4",
121
+ from: "assistant",
122
+ content: "Hello, response from follow up question!",
123
+ ancestors: ["1-1-1-1-1", "1-1-1-1-2", "1-1-1-1-3"],
124
+ children: [],
125
+ },
126
+ {
127
+ id: "1-1-1-1-5",
128
+ from: "assistant",
129
+ content: "Hello, alternative assistant answer!",
130
+ ancestors: ["1-1-1-1-1"],
131
+ children: ["1-1-1-1-6", "1-1-1-1-7"],
132
+ },
133
+ {
134
+ id: "1-1-1-1-6",
135
+ from: "user",
136
+ content: "Hello, follow up question to alternative answer!",
137
+ ancestors: ["1-1-1-1-1", "1-1-1-1-5"],
138
+ children: [],
139
+ },
140
+ {
141
+ id: "1-1-1-1-7",
142
+ from: "user",
143
+ content: "Hello, alternative follow up question to alternative answer!",
144
+ ancestors: ["1-1-1-1-1", "1-1-1-1-5"],
145
+ children: [],
146
+ },
147
+ ],
148
+ });
149
+ return res.insertedId;
150
+ };
151
+
152
+ describe("inserting conversations", () => {
153
+ it("should insert a legacy conversation", async () => {
154
+ const id = await insertLegacyConversation();
155
+ expect(id).toBeDefined();
156
+ }, 30000);
157
+
158
+ it("should insert a linear branch conversation", async () => {
159
+ const id = await insertLinearBranchConversation();
160
+ expect(id).toBeDefined();
161
+ }, 30000);
162
+
163
+ it("should insert a side branches conversation", async () => {
164
+ const id = await insertSideBranchesConversation();
165
+ expect(id).toBeDefined();
166
+ }, 30000);
167
+ });
@@ -0,0 +1,39 @@
1
+ // This is a debouncer for the updates from the server to the client
2
+ // It is used to prevent the client from being overloaded with too many updates
3
+ // It works by keeping track of the time it takes to render the updates
4
+ // and adding a safety margin to it, to find the debounce time.
5
+
6
+ class UpdateDebouncer {
7
+ private renderStartedAt: Date | null = null;
8
+ private lastRenderTimes: number[] = [];
9
+
10
+ get maxUpdateTime() {
11
+ if (this.lastRenderTimes.length === 0) {
12
+ return 50;
13
+ }
14
+
15
+ const averageTime =
16
+ this.lastRenderTimes.reduce((acc, time) => acc + time, 0) / this.lastRenderTimes.length;
17
+
18
+ return Math.min(averageTime * 3, 500);
19
+ }
20
+
21
+ public startRender() {
22
+ this.renderStartedAt = new Date();
23
+ }
24
+
25
+ public endRender() {
26
+ if (!this.renderStartedAt) {
27
+ return;
28
+ }
29
+
30
+ const timeSinceRenderStarted = new Date().getTime() - this.renderStartedAt.getTime();
31
+ this.lastRenderTimes.push(timeSinceRenderStarted);
32
+ if (this.lastRenderTimes.length > 10) {
33
+ this.lastRenderTimes.shift();
34
+ }
35
+ this.renderStartedAt = null;
36
+ }
37
+ }
38
+
39
+ export const updateDebouncer = new UpdateDebouncer();
@@ -0,0 +1,13 @@
1
+ const MAX_PARAM_LENGTH = 10_000;
2
+
3
+ export function sanitizeUrlParam(value: string | null): string | null {
4
+ if (value == null) return null;
5
+
6
+ const trimmed = value.trim();
7
+ if (!trimmed.length) return null;
8
+ if (trimmed.length > MAX_PARAM_LENGTH) return null;
9
+
10
+ return trimmed;
11
+ }
12
+
13
+ export { MAX_PARAM_LENGTH };
@@ -0,0 +1,221 @@
1
+ /**
2
+ * AutopilotWorker — Web Worker for non-blocking SSE parsing of autopilot events.
3
+ *
4
+ * Handles the SSE stream from the MCP bridge, parses structured events,
5
+ * and batches UI updates at ~60fps to prevent main thread jank.
6
+ *
7
+ * ADR-037 Part 3: Web Workers for Non-Blocking Execution
8
+ */
9
+
10
+ export interface TaskState {
11
+ taskId: string;
12
+ tool: string;
13
+ status: "queued" | "running" | "completed" | "failed" | "blocked" | "cancelled";
14
+ summary?: string;
15
+ duration?: number;
16
+ detailToken?: string;
17
+ args?: Record<string, unknown>;
18
+ }
19
+
20
+ export interface GroupState {
21
+ groupId: string;
22
+ step: number;
23
+ tasks: TaskState[];
24
+ duration?: number;
25
+ }
26
+
27
+ // Messages FROM main thread TO worker
28
+ export type AutopilotWorkerIncoming =
29
+ | { type: "start"; url: string; headers: Record<string, string>; body: unknown }
30
+ | { type: "stop" };
31
+
32
+ // Messages FROM worker TO main thread
33
+ export type AutopilotWorkerOutgoing =
34
+ | { type: "batch_update"; updates: AutopilotUIUpdate[]; groups: GroupState[] }
35
+ | { type: "text"; content: string }
36
+ | { type: "done"; groups: GroupState[] }
37
+ | { type: "error"; error: string }
38
+ | { type: "stopped"; groups: GroupState[] };
39
+
40
+ export type AutopilotUIUpdate =
41
+ | { type: "start"; maxSteps: number }
42
+ | { type: "group_start"; group: GroupState }
43
+ | { type: "task_update"; taskId: string; status: string; summary?: string; duration?: number; detailToken?: string }
44
+ | { type: "group_end"; groupId: string; duration: number }
45
+ | { type: "text"; content: string }
46
+ | { type: "end"; totalSteps: number; totalTasks: number; duration: number }
47
+ | { type: "paused"; reason: string; tools?: string[] }
48
+ | { type: "error_event"; error: string };
49
+
50
+ const groups: Map<string, GroupState> = new Map();
51
+ let abortController: AbortController | null = null;
52
+ let batchTimeout: ReturnType<typeof setTimeout> | null = null;
53
+ let pendingUpdates: AutopilotUIUpdate[] = [];
54
+
55
+ /** Batch UI updates at ~60fps to prevent main thread jank */
56
+ function flushUpdates() {
57
+ if (pendingUpdates.length === 0) return;
58
+ const msg: AutopilotWorkerOutgoing = {
59
+ type: "batch_update",
60
+ updates: pendingUpdates,
61
+ groups: [...groups.values()],
62
+ };
63
+ self.postMessage(msg);
64
+ pendingUpdates = [];
65
+ batchTimeout = null;
66
+ }
67
+
68
+ function queueUpdate(update: AutopilotUIUpdate) {
69
+ pendingUpdates.push(update);
70
+ if (!batchTimeout) {
71
+ batchTimeout = setTimeout(flushUpdates, 16); // ~60fps
72
+ }
73
+ }
74
+
75
+ function handleEvent(event: Record<string, unknown>) {
76
+ switch (event.type) {
77
+ case "autopilot_start":
78
+ queueUpdate({ type: "start", maxSteps: (event.maxSteps as number) ?? 20 });
79
+ break;
80
+
81
+ case "task_group_start": {
82
+ const group: GroupState = {
83
+ groupId: event.groupId as string,
84
+ step: event.step as number,
85
+ tasks: (event.tasks as TaskState[]) ?? [],
86
+ };
87
+ groups.set(group.groupId, group);
88
+ queueUpdate({ type: "group_start", group });
89
+ break;
90
+ }
91
+
92
+ case "task_update":
93
+ for (const [, group] of groups) {
94
+ const task = group.tasks.find((t) => t.taskId === event.taskId);
95
+ if (task) {
96
+ if (event.status) task.status = event.status as TaskState["status"];
97
+ if (event.summary) task.summary = event.summary as string;
98
+ if (event.duration != null) task.duration = event.duration as number;
99
+ if (event.detailToken) task.detailToken = event.detailToken as string;
100
+ queueUpdate({
101
+ type: "task_update",
102
+ taskId: event.taskId as string,
103
+ status: event.status as string,
104
+ summary: event.summary as string | undefined,
105
+ duration: event.duration as number | undefined,
106
+ detailToken: event.detailToken as string | undefined,
107
+ });
108
+ break;
109
+ }
110
+ }
111
+ break;
112
+
113
+ case "task_group_end": {
114
+ const g = groups.get(event.groupId as string);
115
+ if (g) g.duration = event.duration as number;
116
+ queueUpdate({
117
+ type: "group_end",
118
+ groupId: event.groupId as string,
119
+ duration: (event.duration as number) ?? 0,
120
+ });
121
+ break;
122
+ }
123
+
124
+ case "autopilot_text":
125
+ queueUpdate({ type: "text", content: (event.content as string) ?? "" });
126
+ // Also send as a separate top-level message for immediate streaming
127
+ self.postMessage({ type: "text", content: (event.content as string) ?? "" });
128
+ break;
129
+
130
+ case "autopilot_paused":
131
+ queueUpdate({
132
+ type: "paused",
133
+ reason: (event.reason as string) ?? "unknown",
134
+ tools: event.tools as string[] | undefined,
135
+ });
136
+ break;
137
+
138
+ case "autopilot_error":
139
+ queueUpdate({ type: "error_event", error: (event.error as string) ?? "Unknown error" });
140
+ break;
141
+
142
+ case "autopilot_end":
143
+ queueUpdate({
144
+ type: "end",
145
+ totalSteps: (event.totalSteps as number) ?? 0,
146
+ totalTasks: (event.totalTasks as number) ?? 0,
147
+ duration: (event.duration as number) ?? 0,
148
+ });
149
+ break;
150
+ }
151
+ }
152
+
153
+ self.onmessage = async (e: MessageEvent<AutopilotWorkerIncoming>) => {
154
+ const msg = e.data;
155
+
156
+ if (msg.type === "start") {
157
+ abortController = new AbortController();
158
+ groups.clear();
159
+ pendingUpdates = [];
160
+
161
+ try {
162
+ const response = await fetch(msg.url, {
163
+ method: "POST",
164
+ headers: { ...msg.headers, "Content-Type": "application/json" },
165
+ body: JSON.stringify(msg.body),
166
+ signal: abortController.signal,
167
+ });
168
+
169
+ if (!response.ok) {
170
+ const errText = await response.text().catch(() => "Unknown error");
171
+ self.postMessage({ type: "error", error: `HTTP ${response.status}: ${errText}` });
172
+ return;
173
+ }
174
+
175
+ const reader = response.body!.getReader();
176
+ const decoder = new TextDecoder();
177
+ let buffer = "";
178
+
179
+ while (true) {
180
+ const { done, value } = await reader.read();
181
+ if (done) break;
182
+
183
+ buffer += decoder.decode(value, { stream: true });
184
+ const lines = buffer.split("\n");
185
+ buffer = lines.pop() || "";
186
+
187
+ for (const line of lines) {
188
+ if (!line.startsWith("data: ")) continue;
189
+ const data = line.slice(6).trim();
190
+ if (data === "[DONE]") {
191
+ flushUpdates();
192
+ self.postMessage({ type: "done", groups: [...groups.values()] });
193
+ return;
194
+ }
195
+
196
+ try {
197
+ const event = JSON.parse(data);
198
+ handleEvent(event);
199
+ } catch {
200
+ // Skip malformed JSON lines
201
+ }
202
+ }
203
+ }
204
+
205
+ // Stream ended without [DONE]
206
+ flushUpdates();
207
+ self.postMessage({ type: "done", groups: [...groups.values()] });
208
+ } catch (err: unknown) {
209
+ const error = err as Error;
210
+ if (error.name !== "AbortError") {
211
+ self.postMessage({ type: "error", error: error.message ?? "Unknown error" });
212
+ }
213
+ }
214
+ }
215
+
216
+ if (msg.type === "stop") {
217
+ abortController?.abort();
218
+ flushUpdates();
219
+ self.postMessage({ type: "stopped", groups: [...groups.values()] });
220
+ }
221
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * DetailFetchWorker — Web Worker for lazy-loading task details with LRU caching.
3
+ *
4
+ * Full tool results are NOT streamed inline — they are stored server-side
5
+ * and fetched on-demand when the user expands a task card.
6
+ *
7
+ * ADR-037 Part 3: Detail Token Lazy Loading
8
+ */
9
+
10
+ // Messages FROM main thread TO worker
11
+ export type DetailWorkerIncoming =
12
+ | { type: "fetch"; detailToken: string; bridgeUrl: string }
13
+ | { type: "prefetch"; detailToken: string; bridgeUrl: string }
14
+ | { type: "evict"; detailToken: string };
15
+
16
+ // Messages FROM worker TO main thread
17
+ export type DetailWorkerOutgoing =
18
+ | { type: "detail"; detailToken: string; content: string }
19
+ | { type: "detail_error"; detailToken: string; error: string };
20
+
21
+ const cache = new Map<string, string>();
22
+ const MAX_CACHE = 20;
23
+ const accessOrder: string[] = [];
24
+
25
+ function evictLRU() {
26
+ while (cache.size > MAX_CACHE) {
27
+ const oldest = accessOrder.shift();
28
+ if (oldest) cache.delete(oldest);
29
+ }
30
+ }
31
+
32
+ function touchAccess(token: string) {
33
+ const idx = accessOrder.indexOf(token);
34
+ if (idx > -1) accessOrder.splice(idx, 1);
35
+ accessOrder.push(token);
36
+ }
37
+
38
+ self.onmessage = async (e: MessageEvent<DetailWorkerIncoming>) => {
39
+ const msg = e.data;
40
+
41
+ if (msg.type === "fetch" || msg.type === "prefetch") {
42
+ // Check cache first
43
+ if (cache.has(msg.detailToken)) {
44
+ touchAccess(msg.detailToken);
45
+ if (msg.type === "fetch") {
46
+ const out: DetailWorkerOutgoing = {
47
+ type: "detail",
48
+ detailToken: msg.detailToken,
49
+ content: cache.get(msg.detailToken)!,
50
+ };
51
+ self.postMessage(out);
52
+ }
53
+ return;
54
+ }
55
+
56
+ try {
57
+ const res = await fetch(`${msg.bridgeUrl}/autopilot/detail/${msg.detailToken}`);
58
+ if (!res.ok) {
59
+ if (msg.type === "fetch") {
60
+ const out: DetailWorkerOutgoing = {
61
+ type: "detail_error",
62
+ detailToken: msg.detailToken,
63
+ error: `HTTP ${res.status}`,
64
+ };
65
+ self.postMessage(out);
66
+ }
67
+ return;
68
+ }
69
+
70
+ const data = (await res.json()) as { content: string };
71
+ cache.set(msg.detailToken, data.content);
72
+ touchAccess(msg.detailToken);
73
+ evictLRU();
74
+
75
+ if (msg.type === "fetch") {
76
+ const out: DetailWorkerOutgoing = {
77
+ type: "detail",
78
+ detailToken: msg.detailToken,
79
+ content: data.content,
80
+ };
81
+ self.postMessage(out);
82
+ }
83
+ } catch (err: unknown) {
84
+ if (msg.type === "fetch") {
85
+ const out: DetailWorkerOutgoing = {
86
+ type: "detail_error",
87
+ detailToken: msg.detailToken,
88
+ error: (err as Error).message ?? "Unknown error",
89
+ };
90
+ self.postMessage(out);
91
+ }
92
+ }
93
+ }
94
+
95
+ if (msg.type === "evict") {
96
+ cache.delete(msg.detailToken);
97
+ const idx = accessOrder.indexOf(msg.detailToken);
98
+ if (idx > -1) accessOrder.splice(idx, 1);
99
+ }
100
+ };
@@ -0,0 +1,61 @@
1
+ // Simple type to replace removed WebSearchSource
2
+ type SimpleSource = {
3
+ title?: string;
4
+ link: string;
5
+ };
6
+ import { processBlocks, type BlockToken } from "$lib/utils/marked";
7
+
8
+ export type IncomingMessage = {
9
+ type: "process";
10
+ content: string;
11
+ sources: SimpleSource[];
12
+ requestId: number;
13
+ };
14
+
15
+ export type OutgoingMessage = {
16
+ type: "processed";
17
+ blocks: BlockToken[];
18
+ requestId: number;
19
+ };
20
+
21
+ // Flag to track if the worker is currently processing a message
22
+ let isProcessing = false;
23
+
24
+ // Buffer to store the latest incoming message
25
+ let latestMessage: IncomingMessage | null = null;
26
+
27
+ // Helper function to safely handle the latest message
28
+ async function processMessage() {
29
+ if (latestMessage) {
30
+ const nextMessage = latestMessage;
31
+
32
+ latestMessage = null;
33
+ isProcessing = true;
34
+
35
+ try {
36
+ const { content, sources, requestId } = nextMessage;
37
+ const processedBlocks = await processBlocks(content, sources);
38
+ postMessage(
39
+ JSON.parse(JSON.stringify({ type: "processed", blocks: processedBlocks, requestId }))
40
+ );
41
+ } finally {
42
+ isProcessing = false;
43
+
44
+ // After processing, check if a new message was buffered
45
+ await new Promise((resolve) => setTimeout(resolve, 100));
46
+ processMessage();
47
+ }
48
+ }
49
+ }
50
+
51
+ onmessage = (event) => {
52
+ if (event.data.type !== "process") {
53
+ return;
54
+ }
55
+
56
+ latestMessage = event.data as IncomingMessage;
57
+
58
+ if (!isProcessing && latestMessage) {
59
+ processMessage();
60
+ }
61
+ };
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { page } from "$app/state";
3
+ </script>
4
+
5
+ <div
6
+ class="flex items-center justify-center bg-gradient-to-t from-gray-200 text-gray-800 dark:from-gray-700 dark:text-gray-300"
7
+ >
8
+ <div
9
+ class="align-center -mt-24 flex flex-col justify-center rounded-xl border bg-white px-8 pb-2 pt-4 text-center dark:border-gray-700 dark:bg-gray-800"
10
+ >
11
+ <h1 class="mb-2 text-5xl font-semibold">{page.status}</h1>
12
+ <div class="-mx-8 my-2 h-px bg-gray-200 dark:bg-gray-700"></div>
13
+ <h2 class="max-w-sm text-lg">{page.error?.message}</h2>
14
+ {#if page.error?.errorId}
15
+ <div class="-mx-8 my-2 h-px bg-gray-200 dark:bg-gray-700"></div>
16
+ <pre class="max-w-sm whitespace-pre-wrap text-left font-mono text-xs">{page.error
17
+ .errorId}</pre>
18
+ {/if}
19
+ </div>
20
+ </div>