Spaces:
				
			
			
	
			
			
		Paused
		
	
	
	
			
			
	
	
	
	
		
		
		Paused
		
	Major bump to sveltekit & node-adapter versions (#1395)
Browse files* version bump
* sveltekit2 bump
* formatting
* fix imports
* fix deps
* minor bump on chat-ui itself
* better error logging
* bump svelte-check version
- package-lock.json +0 -0
 - package.json +11 -9
 - src/hooks.server.ts +3 -1
 - src/lib/components/ExpandNavigation.svelte +1 -1
 - src/lib/components/MobileNav.svelte +1 -1
 - src/lib/components/NavConversationItem.svelte +1 -1
 - src/lib/components/NavMenu.svelte +3 -3
 - src/lib/components/Pagination.svelte +1 -1
 - src/lib/components/chat/AssistantIntroduction.svelte +3 -3
 - src/lib/components/chat/ChatIntroduction.svelte +1 -1
 - src/lib/components/chat/ChatMessage.svelte +10 -10
 - src/lib/components/chat/ChatWindow.svelte +4 -4
 - src/lib/server/auth.ts +7 -1
 - src/lib/server/endpoints/anthropic/utils.ts +1 -1
 - src/lib/server/endpoints/cohere/endpointCohere.ts +2 -2
 - src/lib/server/exitHandler.ts +1 -1
 - src/lib/server/files/downloadFile.ts +2 -2
 - src/routes/+layout.svelte +3 -3
 - src/routes/admin/export/+server.ts +1 -1
 - src/routes/assistant/[assistantId]/+page.server.ts +2 -2
 - src/routes/assistant/[assistantId]/thumbnail.png/+server.ts +1 -1
 - src/routes/assistants/+page.server.ts +2 -2
 - src/routes/assistants/+page.svelte +4 -4
 - src/routes/conversation/+server.ts +6 -9
 - src/routes/conversation/[id]/+page.server.ts +5 -5
 - src/routes/conversation/[id]/+server.ts +16 -16
 - src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +3 -3
 - src/routes/conversation/[id]/message/[messageId]/vote/+server.ts +1 -1
 - src/routes/conversation/[id]/output/[sha256]/+server.ts +3 -3
 - src/routes/conversation/[id]/share/+server.ts +1 -1
 - src/routes/conversation/[id]/stop-generating/+server.ts +1 -1
 - src/routes/conversations/+page.server.ts +1 -1
 - src/routes/login/+page.server.ts +1 -1
 - src/routes/login/callback/+page.server.ts +6 -6
 - src/routes/login/callback/updateUser.ts +1 -1
 - src/routes/logout/+page.server.ts +1 -1
 - src/routes/models/[...model]/+page.server.ts +1 -1
 - src/routes/models/[...model]/thumbnail.png/+server.ts +1 -1
 - src/routes/r/[id]/+page.ts +1 -1
 - src/routes/settings/(nav)/+page.svelte +1 -1
 - src/routes/settings/(nav)/[...model]/+page.ts +1 -1
 - src/routes/settings/(nav)/assistants/[assistantId]/+page.server.ts +2 -2
 - src/routes/settings/(nav)/assistants/[assistantId]/+page.ts +1 -1
 - src/routes/settings/(nav)/assistants/[assistantId]/avatar.jpg/+server.ts +3 -3
 - src/routes/settings/(nav)/assistants/[assistantId]/edit/+page.server.ts +1 -1
 - src/routes/settings/(nav)/assistants/new/+page.server.ts +1 -1
 - svelte.config.js +1 -1
 
    	
        package-lock.json
    CHANGED
    
    | 
         The diff for this file is too large to render. 
		See raw diff 
     | 
| 
         | 
    	
        package.json
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 1 | 
         
             
            {
         
     | 
| 2 | 
         
             
            	"name": "chat-ui",
         
     | 
| 3 | 
         
            -
            	"version": "0.9. 
     | 
| 4 | 
         
             
            	"private": true,
         
     | 
| 5 | 
         
             
            	"packageManager": "npm@9.5.0",
         
     | 
| 6 | 
         
             
            	"scripts": {
         
     | 
| 
         @@ -20,14 +20,15 @@ 
     | 
|
| 20 | 
         
             
            		"@faker-js/faker": "^8.4.1",
         
     | 
| 21 | 
         
             
            		"@iconify-json/carbon": "^1.1.16",
         
     | 
| 22 | 
         
             
            		"@iconify-json/eos-icons": "^1.1.6",
         
     | 
| 23 | 
         
            -
            		"@sveltejs/adapter-node": "^ 
     | 
| 24 | 
         
            -
            		"@sveltejs/kit": "^ 
     | 
| 25 | 
         
             
            		"@tailwindcss/typography": "^0.5.9",
         
     | 
| 26 | 
         
             
            		"@types/dompurify": "^3.0.5",
         
     | 
| 27 | 
         
             
            		"@types/express": "^4.17.21",
         
     | 
| 28 | 
         
             
            		"@types/js-yaml": "^4.0.9",
         
     | 
| 29 | 
         
             
            		"@types/jsdom": "^21.1.1",
         
     | 
| 30 | 
         
             
            		"@types/minimist": "^1.2.5",
         
     | 
| 
         | 
|
| 31 | 
         
             
            		"@types/parquetjs": "^0.10.3",
         
     | 
| 32 | 
         
             
            		"@types/sbd": "^1.0.5",
         
     | 
| 33 | 
         
             
            		"@types/uuid": "^9.0.8",
         
     | 
| 
         @@ -44,13 +45,13 @@ 
     | 
|
| 44 | 
         
             
            		"prettier-plugin-svelte": "^2.10.1",
         
     | 
| 45 | 
         
             
            		"prettier-plugin-tailwindcss": "^0.2.7",
         
     | 
| 46 | 
         
             
            		"prom-client": "^15.1.2",
         
     | 
| 47 | 
         
            -
            		"svelte": "^4.2. 
     | 
| 48 | 
         
            -
            		"svelte-check": "^3. 
     | 
| 49 | 
         
             
            		"ts-node": "^10.9.1",
         
     | 
| 50 | 
         
             
            		"tslib": "^2.4.1",
         
     | 
| 51 | 
         
             
            		"typescript": "^5.0.0",
         
     | 
| 52 | 
         
             
            		"unplugin-icons": "^0.16.1",
         
     | 
| 53 | 
         
            -
            		"vite": "^ 
     | 
| 54 | 
         
             
            		"vite-node": "^1.3.1",
         
     | 
| 55 | 
         
             
            		"vitest": "^0.31.0"
         
     | 
| 56 | 
         
             
            	},
         
     | 
| 
         @@ -72,6 +73,7 @@ 
     | 
|
| 72 | 
         
             
            		"dotenv": "^16.0.3",
         
     | 
| 73 | 
         
             
            		"express": "^4.19.2",
         
     | 
| 74 | 
         
             
            		"file-type": "^19.0.0",
         
     | 
| 
         | 
|
| 75 | 
         
             
            		"handlebars": "^4.7.8",
         
     | 
| 76 | 
         
             
            		"highlight.js": "^11.7.0",
         
     | 
| 77 | 
         
             
            		"husky": "^9.0.11",
         
     | 
| 
         @@ -99,12 +101,12 @@ 
     | 
|
| 99 | 
         
             
            		"sharp": "^0.33.4",
         
     | 
| 100 | 
         
             
            		"tailwind-scrollbar": "^3.0.0",
         
     | 
| 101 | 
         
             
            		"tailwindcss": "^3.4.0",
         
     | 
| 102 | 
         
            -
            		"uuid": "^ 
     | 
| 103 | 
         
             
            		"zod": "^3.22.3"
         
     | 
| 104 | 
         
             
            	},
         
     | 
| 105 | 
         
             
            	"optionalDependencies": {
         
     | 
| 106 | 
         
            -
            		"@anthropic-ai/sdk": "^0. 
     | 
| 107 | 
         
            -
            		"@anthropic-ai/vertex-sdk": "^0. 
     | 
| 108 | 
         
             
            		"@google-cloud/vertexai": "^1.1.0",
         
     | 
| 109 | 
         
             
            		"@google/generative-ai": "^0.14.1",
         
     | 
| 110 | 
         
             
            		"aws4fetch": "^1.0.17",
         
     | 
| 
         | 
|
| 1 | 
         
             
            {
         
     | 
| 2 | 
         
             
            	"name": "chat-ui",
         
     | 
| 3 | 
         
            +
            	"version": "0.9.2",
         
     | 
| 4 | 
         
             
            	"private": true,
         
     | 
| 5 | 
         
             
            	"packageManager": "npm@9.5.0",
         
     | 
| 6 | 
         
             
            	"scripts": {
         
     | 
| 
         | 
|
| 20 | 
         
             
            		"@faker-js/faker": "^8.4.1",
         
     | 
| 21 | 
         
             
            		"@iconify-json/carbon": "^1.1.16",
         
     | 
| 22 | 
         
             
            		"@iconify-json/eos-icons": "^1.1.6",
         
     | 
| 23 | 
         
            +
            		"@sveltejs/adapter-node": "^5.2.0",
         
     | 
| 24 | 
         
            +
            		"@sveltejs/kit": "^2.5.20",
         
     | 
| 25 | 
         
             
            		"@tailwindcss/typography": "^0.5.9",
         
     | 
| 26 | 
         
             
            		"@types/dompurify": "^3.0.5",
         
     | 
| 27 | 
         
             
            		"@types/express": "^4.17.21",
         
     | 
| 28 | 
         
             
            		"@types/js-yaml": "^4.0.9",
         
     | 
| 29 | 
         
             
            		"@types/jsdom": "^21.1.1",
         
     | 
| 30 | 
         
             
            		"@types/minimist": "^1.2.5",
         
     | 
| 31 | 
         
            +
            		"@types/node": "^22.1.0",
         
     | 
| 32 | 
         
             
            		"@types/parquetjs": "^0.10.3",
         
     | 
| 33 | 
         
             
            		"@types/sbd": "^1.0.5",
         
     | 
| 34 | 
         
             
            		"@types/uuid": "^9.0.8",
         
     | 
| 
         | 
|
| 45 | 
         
             
            		"prettier-plugin-svelte": "^2.10.1",
         
     | 
| 46 | 
         
             
            		"prettier-plugin-tailwindcss": "^0.2.7",
         
     | 
| 47 | 
         
             
            		"prom-client": "^15.1.2",
         
     | 
| 48 | 
         
            +
            		"svelte": "^4.2.18",
         
     | 
| 49 | 
         
            +
            		"svelte-check": "^3.8.5",
         
     | 
| 50 | 
         
             
            		"ts-node": "^10.9.1",
         
     | 
| 51 | 
         
             
            		"tslib": "^2.4.1",
         
     | 
| 52 | 
         
             
            		"typescript": "^5.0.0",
         
     | 
| 53 | 
         
             
            		"unplugin-icons": "^0.16.1",
         
     | 
| 54 | 
         
            +
            		"vite": "^5.3.5",
         
     | 
| 55 | 
         
             
            		"vite-node": "^1.3.1",
         
     | 
| 56 | 
         
             
            		"vitest": "^0.31.0"
         
     | 
| 57 | 
         
             
            	},
         
     | 
| 
         | 
|
| 73 | 
         
             
            		"dotenv": "^16.0.3",
         
     | 
| 74 | 
         
             
            		"express": "^4.19.2",
         
     | 
| 75 | 
         
             
            		"file-type": "^19.0.0",
         
     | 
| 76 | 
         
            +
            		"google-auth-library": "^9.13.0",
         
     | 
| 77 | 
         
             
            		"handlebars": "^4.7.8",
         
     | 
| 78 | 
         
             
            		"highlight.js": "^11.7.0",
         
     | 
| 79 | 
         
             
            		"husky": "^9.0.11",
         
     | 
| 
         | 
|
| 101 | 
         
             
            		"sharp": "^0.33.4",
         
     | 
| 102 | 
         
             
            		"tailwind-scrollbar": "^3.0.0",
         
     | 
| 103 | 
         
             
            		"tailwindcss": "^3.4.0",
         
     | 
| 104 | 
         
            +
            		"uuid": "^10.0.0",
         
     | 
| 105 | 
         
             
            		"zod": "^3.22.3"
         
     | 
| 106 | 
         
             
            	},
         
     | 
| 107 | 
         
             
            	"optionalDependencies": {
         
     | 
| 108 | 
         
            +
            		"@anthropic-ai/sdk": "^0.25.0",
         
     | 
| 109 | 
         
            +
            		"@anthropic-ai/vertex-sdk": "^0.4.1",
         
     | 
| 110 | 
         
             
            		"@google-cloud/vertexai": "^1.1.0",
         
     | 
| 111 | 
         
             
            		"@google/generative-ai": "^0.14.1",
         
     | 
| 112 | 
         
             
            		"aws4fetch": "^1.0.17",
         
     | 
    	
        src/hooks.server.ts
    CHANGED
    
    | 
         @@ -35,7 +35,7 @@ if (!building) { 
     | 
|
| 35 | 
         
             
            	AbortedGenerations.getInstance();
         
     | 
| 36 | 
         
             
            }
         
     | 
| 37 | 
         | 
| 38 | 
         
            -
            export const handleError: HandleServerError = async ({ error, event }) => {
         
     | 
| 39 | 
         
             
            	// handle 404
         
     | 
| 40 | 
         | 
| 41 | 
         
             
            	if (building) {
         
     | 
| 
         @@ -55,8 +55,10 @@ export const handleError: HandleServerError = async ({ error, event }) => { 
     | 
|
| 55 | 
         
             
            		url: event.request.url,
         
     | 
| 56 | 
         
             
            		params: event.params,
         
     | 
| 57 | 
         
             
            		request: event.request,
         
     | 
| 
         | 
|
| 58 | 
         
             
            		error,
         
     | 
| 59 | 
         
             
            		errorId,
         
     | 
| 
         | 
|
| 60 | 
         
             
            	});
         
     | 
| 61 | 
         | 
| 62 | 
         
             
            	return {
         
     | 
| 
         | 
|
| 35 | 
         
             
            	AbortedGenerations.getInstance();
         
     | 
| 36 | 
         
             
            }
         
     | 
| 37 | 
         | 
| 38 | 
         
            +
            export const handleError: HandleServerError = async ({ error, event, status, message }) => {
         
     | 
| 39 | 
         
             
            	// handle 404
         
     | 
| 40 | 
         | 
| 41 | 
         
             
            	if (building) {
         
     | 
| 
         | 
|
| 55 | 
         
             
            		url: event.request.url,
         
     | 
| 56 | 
         
             
            		params: event.params,
         
     | 
| 57 | 
         
             
            		request: event.request,
         
     | 
| 58 | 
         
            +
            		message,
         
     | 
| 59 | 
         
             
            		error,
         
     | 
| 60 | 
         
             
            		errorId,
         
     | 
| 61 | 
         
            +
            		status,
         
     | 
| 62 | 
         
             
            	});
         
     | 
| 63 | 
         | 
| 64 | 
         
             
            	return {
         
     | 
    	
        src/lib/components/ExpandNavigation.svelte
    CHANGED
    
    | 
         @@ -5,7 +5,7 @@ 
     | 
|
| 5 | 
         | 
| 6 | 
         
             
            <button
         
     | 
| 7 | 
         
             
            	on:click
         
     | 
| 8 | 
         
            -
            	class="{classNames} group flex h-16 w-6 flex-col items-center justify-center -space-y-1 outline-none *:h-3 *:w-1 *:rounded-full *:hover:bg-gray-300  
     | 
| 9 | 
         
             
            		? '*:bg-gray-200/70 dark:*:bg-gray-800'
         
     | 
| 10 | 
         
             
            		: '*:bg-gray-200 dark:*:bg-gray-700'}"
         
     | 
| 11 | 
         
             
            >
         
     | 
| 
         | 
|
| 5 | 
         | 
| 6 | 
         
             
            <button
         
     | 
| 7 | 
         
             
            	on:click
         
     | 
| 8 | 
         
            +
            	class="{classNames} group flex h-16 w-6 flex-col items-center justify-center -space-y-1 outline-none *:h-3 *:w-1 *:rounded-full *:hover:bg-gray-300 dark:*:hover:bg-gray-600 max-md:hidden {!isCollapsed
         
     | 
| 9 | 
         
             
            		? '*:bg-gray-200/70 dark:*:bg-gray-800'
         
     | 
| 10 | 
         
             
            		: '*:bg-gray-200 dark:*:bg-gray-700'}"
         
     | 
| 11 | 
         
             
            >
         
     | 
    	
        src/lib/components/MobileNav.svelte
    CHANGED
    
    | 
         @@ -31,7 +31,7 @@ 
     | 
|
| 31 | 
         
             
            </script>
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            <nav
         
     | 
| 34 | 
         
            -
            	class="flex h-12 items-center justify-between border-b bg-gray-50 px-3  
     | 
| 35 | 
         
             
            >
         
     | 
| 36 | 
         
             
            	<button
         
     | 
| 37 | 
         
             
            		type="button"
         
     | 
| 
         | 
|
| 31 | 
         
             
            </script>
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            <nav
         
     | 
| 34 | 
         
            +
            	class="flex h-12 items-center justify-between border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/70 md:hidden"
         
     | 
| 35 | 
         
             
            >
         
     | 
| 36 | 
         
             
            	<button
         
     | 
| 37 | 
         
             
            		type="button"
         
     | 
    	
        src/lib/components/NavConversationItem.svelte
    CHANGED
    
    | 
         @@ -25,7 +25,7 @@ 
     | 
|
| 25 | 
         
             
            		confirmDelete = false;
         
     | 
| 26 | 
         
             
            	}}
         
     | 
| 27 | 
         
             
            	href="{base}/conversation/{conv.id}"
         
     | 
| 28 | 
         
            -
            	class="group flex h-10 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-600 hover:bg-gray-100  
     | 
| 29 | 
         
             
            	$page.params.id
         
     | 
| 30 | 
         
             
            		? 'bg-gray-100 dark:bg-gray-700'
         
     | 
| 31 | 
         
             
            		: ''}"
         
     | 
| 
         | 
|
| 25 | 
         
             
            		confirmDelete = false;
         
     | 
| 26 | 
         
             
            	}}
         
     | 
| 27 | 
         
             
            	href="{base}/conversation/{conv.id}"
         
     | 
| 28 | 
         
            +
            	class="group flex h-10 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:h-[2.35rem] {conv.id ===
         
     | 
| 29 | 
         
             
            	$page.params.id
         
     | 
| 30 | 
         
             
            		? 'bg-gray-100 dark:bg-gray-700'
         
     | 
| 31 | 
         
             
            		: ''}"
         
     | 
    	
        src/lib/components/NavMenu.svelte
    CHANGED
    
    | 
         @@ -57,13 +57,13 @@ 
     | 
|
| 57 | 
         
             
            	<a
         
     | 
| 58 | 
         
             
            		href={`${base}/`}
         
     | 
| 59 | 
         
             
            		on:click={handleNewChatClick}
         
     | 
| 60 | 
         
            -
            		class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none  
     | 
| 61 | 
         
             
            	>
         
     | 
| 62 | 
         
             
            		New Chat
         
     | 
| 63 | 
         
             
            	</a>
         
     | 
| 64 | 
         
             
            </div>
         
     | 
| 65 | 
         
             
            <div
         
     | 
| 66 | 
         
            -
            	class="scrollbar-custom flex flex-col gap-1 overflow-y-auto rounded-r-xl from-gray-50 px-3 pb-3 pt-2 text-[.9rem] max-sm:bg-gradient-to-t md:bg-gradient-to-l 
     | 
| 67 | 
         
             
            >
         
     | 
| 68 | 
         
             
            	{#each Object.entries(groupedConversations) as [group, convs]}
         
     | 
| 69 | 
         
             
            		{#if convs.length}
         
     | 
| 
         @@ -92,7 +92,7 @@ 
     | 
|
| 92 | 
         
             
            			{#if !user.logoutDisabled}
         
     | 
| 93 | 
         
             
            				<button
         
     | 
| 94 | 
         
             
            					type="submit"
         
     | 
| 95 | 
         
            -
            					class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none  
     | 
| 96 | 
         
             
            				>
         
     | 
| 97 | 
         
             
            					Sign Out
         
     | 
| 98 | 
         
             
            				</button>
         
     | 
| 
         | 
|
| 57 | 
         
             
            	<a
         
     | 
| 58 | 
         
             
            		href={`${base}/`}
         
     | 
| 59 | 
         
             
            		on:click={handleNewChatClick}
         
     | 
| 60 | 
         
            +
            		class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none dark:border-gray-600 dark:bg-gray-700 sm:text-smd"
         
     | 
| 61 | 
         
             
            	>
         
     | 
| 62 | 
         
             
            		New Chat
         
     | 
| 63 | 
         
             
            	</a>
         
     | 
| 64 | 
         
             
            </div>
         
     | 
| 65 | 
         
             
            <div
         
     | 
| 66 | 
         
            +
            	class="scrollbar-custom flex flex-col gap-1 overflow-y-auto rounded-r-xl from-gray-50 px-3 pb-3 pt-2 text-[.9rem] dark:from-gray-800/30 max-sm:bg-gradient-to-t md:bg-gradient-to-l"
         
     | 
| 67 | 
         
             
            >
         
     | 
| 68 | 
         
             
            	{#each Object.entries(groupedConversations) as [group, convs]}
         
     | 
| 69 | 
         
             
            		{#if convs.length}
         
     | 
| 
         | 
|
| 92 | 
         
             
            			{#if !user.logoutDisabled}
         
     | 
| 93 | 
         
             
            				<button
         
     | 
| 94 | 
         
             
            					type="submit"
         
     | 
| 95 | 
         
            +
            					class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none dark:border-gray-600 dark:bg-gray-600 dark:text-gray-400 dark:hover:text-gray-300 md:hidden"
         
     | 
| 96 | 
         
             
            				>
         
     | 
| 97 | 
         
             
            					Sign Out
         
     | 
| 98 | 
         
             
            				</button>
         
     | 
    	
        src/lib/components/Pagination.svelte
    CHANGED
    
    | 
         @@ -57,7 +57,7 @@ 
     | 
|
| 57 | 
         
             
            {#if numTotalPages > 1}
         
     | 
| 58 | 
         
             
            	<nav>
         
     | 
| 59 | 
         
             
            		<ul
         
     | 
| 60 | 
         
            -
            			class="flex select-none items-center justify-between space-x-2 text-gray-700  
     | 
| 61 | 
         
             
            		>
         
     | 
| 62 | 
         
             
            			<li>
         
     | 
| 63 | 
         
             
            				<PaginationArrow
         
     | 
| 
         | 
|
| 57 | 
         
             
            {#if numTotalPages > 1}
         
     | 
| 58 | 
         
             
            	<nav>
         
     | 
| 59 | 
         
             
            		<ul
         
     | 
| 60 | 
         
            +
            			class="flex select-none items-center justify-between space-x-2 text-gray-700 dark:text-gray-300 sm:justify-center {classNames}"
         
     | 
| 61 | 
         
             
            		>
         
     | 
| 62 | 
         
             
            			<li>
         
     | 
| 63 | 
         
             
            				<PaginationArrow
         
     | 
    	
        src/lib/components/chat/AssistantIntroduction.svelte
    CHANGED
    
    | 
         @@ -67,7 +67,7 @@ 
     | 
|
| 67 | 
         
             
            				/>
         
     | 
| 68 | 
         
             
            			{:else}
         
     | 
| 69 | 
         
             
            				<div
         
     | 
| 70 | 
         
            -
            					class="flex size-12 flex-none items-center justify-center rounded-full bg-gray-300 object-cover text-xl font-bold uppercase text-gray-500 max-sm:self-start sm:text-4xl md:size-32 
     | 
| 71 | 
         
             
            				>
         
     | 
| 72 | 
         
             
            					{assistant?.name[0]}
         
     | 
| 73 | 
         
             
            				</div>
         
     | 
| 
         @@ -116,7 +116,7 @@ 
     | 
|
| 116 | 
         
             
            		<div class="absolute right-3 top-3 md:right-4 md:top-4">
         
     | 
| 117 | 
         
             
            			<div class="flex flex-row items-center gap-1">
         
     | 
| 118 | 
         
             
            				<button
         
     | 
| 119 | 
         
            -
            					class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner  
     | 
| 120 | 
         
             
            					on:click={() => {
         
     | 
| 121 | 
         
             
            						if (!isCopied) {
         
     | 
| 122 | 
         
             
            							share(shareUrl, assistant.name);
         
     | 
| 
         @@ -137,7 +137,7 @@ 
     | 
|
| 137 | 
         
             
            				</button>
         
     | 
| 138 | 
         
             
            				<a
         
     | 
| 139 | 
         
             
            					href="{base}/settings/assistants/{assistant._id.toString()}"
         
     | 
| 140 | 
         
            -
            					class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner  
     | 
| 141 | 
         
             
            					><IconGear class="text-xxs" />Settings</a
         
     | 
| 142 | 
         
             
            				>
         
     | 
| 143 | 
         
             
            			</div>
         
     | 
| 
         | 
|
| 67 | 
         
             
            				/>
         
     | 
| 68 | 
         
             
            			{:else}
         
     | 
| 69 | 
         
             
            				<div
         
     | 
| 70 | 
         
            +
            					class="flex size-12 flex-none items-center justify-center rounded-full bg-gray-300 object-cover text-xl font-bold uppercase text-gray-500 dark:bg-gray-600 max-sm:self-start sm:text-4xl md:size-32"
         
     | 
| 71 | 
         
             
            				>
         
     | 
| 72 | 
         
             
            					{assistant?.name[0]}
         
     | 
| 73 | 
         
             
            				</div>
         
     | 
| 
         | 
|
| 116 | 
         
             
            		<div class="absolute right-3 top-3 md:right-4 md:top-4">
         
     | 
| 117 | 
         
             
            			<div class="flex flex-row items-center gap-1">
         
     | 
| 118 | 
         
             
            				<button
         
     | 
| 119 | 
         
            +
            					class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner dark:border-gray-700 dark:bg-gray-700 dark:text-gray-300/90 dark:hover:bg-gray-800 max-sm:px-1.5 md:text-sm"
         
     | 
| 120 | 
         
             
            					on:click={() => {
         
     | 
| 121 | 
         
             
            						if (!isCopied) {
         
     | 
| 122 | 
         
             
            							share(shareUrl, assistant.name);
         
     | 
| 
         | 
|
| 137 | 
         
             
            				</button>
         
     | 
| 138 | 
         
             
            				<a
         
     | 
| 139 | 
         
             
            					href="{base}/settings/assistants/{assistant._id.toString()}"
         
     | 
| 140 | 
         
            +
            					class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner dark:border-gray-700 dark:bg-gray-700 dark:text-gray-300/90 dark:hover:bg-gray-800 md:text-sm"
         
     | 
| 141 | 
         
             
            					><IconGear class="text-xxs" />Settings</a
         
     | 
| 142 | 
         
             
            				>
         
     | 
| 143 | 
         
             
            			</div>
         
     | 
    	
        src/lib/components/chat/ChatIntroduction.svelte
    CHANGED
    
    | 
         @@ -86,7 +86,7 @@ 
     | 
|
| 86 | 
         
             
            				{#each currentModelMetadata.promptExamples as example}
         
     | 
| 87 | 
         
             
            					<button
         
     | 
| 88 | 
         
             
            						type="button"
         
     | 
| 89 | 
         
            -
            						class="rounded-xl border bg-gray-50 p-3 text-gray-600 hover:bg-gray-100  
     | 
| 90 | 
         
             
            						on:click={() => dispatch("message", example.prompt)}
         
     | 
| 91 | 
         
             
            					>
         
     | 
| 92 | 
         
             
            						{example.title}
         
     | 
| 
         | 
|
| 86 | 
         
             
            				{#each currentModelMetadata.promptExamples as example}
         
     | 
| 87 | 
         
             
            					<button
         
     | 
| 88 | 
         
             
            						type="button"
         
     | 
| 89 | 
         
            +
            						class="rounded-xl border bg-gray-50 p-3 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 max-xl:text-sm xl:p-3.5"
         
     | 
| 90 | 
         
             
            						on:click={() => dispatch("message", example.prompt)}
         
     | 
| 91 | 
         
             
            					>
         
     | 
| 92 | 
         
             
            						{example.title}
         
     | 
    	
        src/lib/components/chat/ChatMessage.svelte
    CHANGED
    
    | 
         @@ -295,7 +295,7 @@ 
     | 
|
| 295 | 
         
             
            			{/if}
         
     | 
| 296 | 
         | 
| 297 | 
         
             
            			<div
         
     | 
| 298 | 
         
            -
            				class="prose max-w-none max-sm:prose-sm  
     | 
| 299 | 
         
             
            				bind:this={contentEl}
         
     | 
| 300 | 
         
             
            			>
         
     | 
| 301 | 
         
             
            				{#if isLast && loading && $settings.disableStream}
         
     | 
| 
         @@ -343,7 +343,7 @@ 
     | 
|
| 343 | 
         
             
            			>
         
     | 
| 344 | 
         
             
            				{#if isAuthor}
         
     | 
| 345 | 
         
             
            					<button
         
     | 
| 346 | 
         
            -
            						class="btn rounded-sm p-1 text-sm text-gray-400  
     | 
| 347 | 
         
             
            					{message.score && message.score > 0
         
     | 
| 348 | 
         
             
            							? 'text-green-500 hover:text-green-500 dark:text-green-400 hover:dark:text-green-400'
         
     | 
| 349 | 
         
             
            							: ''}"
         
     | 
| 
         @@ -355,7 +355,7 @@ 
     | 
|
| 355 | 
         
             
            						<CarbonThumbsUp class="h-[1.14em] w-[1.14em]" />
         
     | 
| 356 | 
         
             
            					</button>
         
     | 
| 357 | 
         
             
            					<button
         
     | 
| 358 | 
         
            -
            						class="btn rounded-sm p-1 text-sm text-gray-400  
     | 
| 359 | 
         
             
            					{message.score && message.score < 0
         
     | 
| 360 | 
         
             
            							? 'text-red-500 hover:text-red-500 dark:text-red-400 hover:dark:text-red-400'
         
     | 
| 361 | 
         
             
            							: ''}"
         
     | 
| 
         @@ -368,7 +368,7 @@ 
     | 
|
| 368 | 
         
             
            					</button>
         
     | 
| 369 | 
         
             
            				{/if}
         
     | 
| 370 | 
         
             
            				<button
         
     | 
| 371 | 
         
            -
            					class="btn rounded-sm p-1 text-sm text-gray-400  
     | 
| 372 | 
         
             
            					title="Retry"
         
     | 
| 373 | 
         
             
            					type="button"
         
     | 
| 374 | 
         
             
            					on:click={() => dispatch("retry", { id: message.id })}
         
     | 
| 
         @@ -439,7 +439,7 @@ 
     | 
|
| 439 | 
         
             
            								class="btn rounded-lg px-3 py-1.5 text-sm
         
     | 
| 440 | 
         
             
            								{loading
         
     | 
| 441 | 
         
             
            									? 'bg-gray-300 text-gray-400 dark:bg-gray-700 dark:text-gray-600'
         
     | 
| 442 | 
         
            -
            									: 'bg-gray-200 text-gray-600  
     | 
| 443 | 
         
             
            								"
         
     | 
| 444 | 
         
             
            								disabled={loading}
         
     | 
| 445 | 
         
             
            							>
         
     | 
| 
         @@ -447,7 +447,7 @@ 
     | 
|
| 447 | 
         
             
            							</button>
         
     | 
| 448 | 
         
             
            							<button
         
     | 
| 449 | 
         
             
            								type="button"
         
     | 
| 450 | 
         
            -
            								class="btn rounded-sm p-2 text-sm text-gray-400  
     | 
| 451 | 
         
             
            								on:click={() => {
         
     | 
| 452 | 
         
             
            									$convTreeStore.editing = null;
         
     | 
| 453 | 
         
             
            								}}
         
     | 
| 
         @@ -469,7 +469,7 @@ 
     | 
|
| 469 | 
         
             
            						<div class="mx-auto flex flex-row flex-nowrap gap-2">
         
     | 
| 470 | 
         
             
            							{#if downloadLink}
         
     | 
| 471 | 
         
             
            								<a
         
     | 
| 472 | 
         
            -
            									class="rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500  
     | 
| 473 | 
         
             
            									title="Download prompt and parameters"
         
     | 
| 474 | 
         
             
            									type="button"
         
     | 
| 475 | 
         
             
            									target="_blank"
         
     | 
| 
         @@ -480,7 +480,7 @@ 
     | 
|
| 480 | 
         
             
            							{/if}
         
     | 
| 481 | 
         
             
            							{#if !readOnly}
         
     | 
| 482 | 
         
             
            								<button
         
     | 
| 483 | 
         
            -
            									class="cursor-pointer rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500  
     | 
| 484 | 
         
             
            									title="Branch"
         
     | 
| 485 | 
         
             
            									type="button"
         
     | 
| 486 | 
         
             
            									on:click={() => ($convTreeStore.editing = message.id)}
         
     | 
| 
         @@ -515,7 +515,7 @@ 
     | 
|
| 515 | 
         
             
            					class="font-white group/navbranch z-10 -mt-1 ml-3.5 mr-auto flex h-6 w-fit select-none flex-row items-center justify-center gap-1 text-sm"
         
     | 
| 516 | 
         
             
            				>
         
     | 
| 517 | 
         
             
            					<button
         
     | 
| 518 | 
         
            -
            						class="inline text-lg font-thin text-gray-400 disabled:pointer-events-none disabled:opacity-25  
     | 
| 519 | 
         
             
            						on:click={() => (childrenToRender = Math.max(0, childrenToRender - 1))}
         
     | 
| 520 | 
         
             
            						disabled={childrenToRender === 0 || loading}
         
     | 
| 521 | 
         
             
            					>
         
     | 
| 
         @@ -525,7 +525,7 @@ 
     | 
|
| 525 | 
         
             
            						{childrenToRender + 1} / {nChildren}
         
     | 
| 526 | 
         
             
            					</span>
         
     | 
| 527 | 
         
             
            					<button
         
     | 
| 528 | 
         
            -
            						class="inline text-lg font-thin text-gray-400 disabled:pointer-events-none disabled:opacity-25  
     | 
| 529 | 
         
             
            						on:click={() =>
         
     | 
| 530 | 
         
             
            							(childrenToRender = Math.min(
         
     | 
| 531 | 
         
             
            								message?.children?.length ?? 1 - 1,
         
     | 
| 
         | 
|
| 295 | 
         
             
            			{/if}
         
     | 
| 296 | 
         | 
| 297 | 
         
             
            			<div
         
     | 
| 298 | 
         
            +
            				class="prose max-w-none dark:prose-invert max-sm:prose-sm prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
         
     | 
| 299 | 
         
             
            				bind:this={contentEl}
         
     | 
| 300 | 
         
             
            			>
         
     | 
| 301 | 
         
             
            				{#if isLast && loading && $settings.disableStream}
         
     | 
| 
         | 
|
| 343 | 
         
             
            			>
         
     | 
| 344 | 
         
             
            				{#if isAuthor}
         
     | 
| 345 | 
         
             
            					<button
         
     | 
| 346 | 
         
            +
            						class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300
         
     | 
| 347 | 
         
             
            					{message.score && message.score > 0
         
     | 
| 348 | 
         
             
            							? 'text-green-500 hover:text-green-500 dark:text-green-400 hover:dark:text-green-400'
         
     | 
| 349 | 
         
             
            							: ''}"
         
     | 
| 
         | 
|
| 355 | 
         
             
            						<CarbonThumbsUp class="h-[1.14em] w-[1.14em]" />
         
     | 
| 356 | 
         
             
            					</button>
         
     | 
| 357 | 
         
             
            					<button
         
     | 
| 358 | 
         
            +
            						class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300
         
     | 
| 359 | 
         
             
            					{message.score && message.score < 0
         
     | 
| 360 | 
         
             
            							? 'text-red-500 hover:text-red-500 dark:text-red-400 hover:dark:text-red-400'
         
     | 
| 361 | 
         
             
            							: ''}"
         
     | 
| 
         | 
|
| 368 | 
         
             
            					</button>
         
     | 
| 369 | 
         
             
            				{/if}
         
     | 
| 370 | 
         
             
            				<button
         
     | 
| 371 | 
         
            +
            					class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300"
         
     | 
| 372 | 
         
             
            					title="Retry"
         
     | 
| 373 | 
         
             
            					type="button"
         
     | 
| 374 | 
         
             
            					on:click={() => dispatch("retry", { id: message.id })}
         
     | 
| 
         | 
|
| 439 | 
         
             
            								class="btn rounded-lg px-3 py-1.5 text-sm
         
     | 
| 440 | 
         
             
            								{loading
         
     | 
| 441 | 
         
             
            									? 'bg-gray-300 text-gray-400 dark:bg-gray-700 dark:text-gray-600'
         
     | 
| 442 | 
         
            +
            									: 'bg-gray-200 text-gray-600 hover:text-gray-800   focus:ring-0 dark:bg-gray-800 dark:text-gray-300 dark:hover:text-gray-200'}
         
     | 
| 443 | 
         
             
            								"
         
     | 
| 444 | 
         
             
            								disabled={loading}
         
     | 
| 445 | 
         
             
            							>
         
     | 
| 
         | 
|
| 447 | 
         
             
            							</button>
         
     | 
| 448 | 
         
             
            							<button
         
     | 
| 449 | 
         
             
            								type="button"
         
     | 
| 450 | 
         
            +
            								class="btn rounded-sm p-2 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300"
         
     | 
| 451 | 
         
             
            								on:click={() => {
         
     | 
| 452 | 
         
             
            									$convTreeStore.editing = null;
         
     | 
| 453 | 
         
             
            								}}
         
     | 
| 
         | 
|
| 469 | 
         
             
            						<div class="mx-auto flex flex-row flex-nowrap gap-2">
         
     | 
| 470 | 
         
             
            							{#if downloadLink}
         
     | 
| 471 | 
         
             
            								<a
         
     | 
| 472 | 
         
            +
            									class="rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-300 max-sm:!hidden md:hidden"
         
     | 
| 473 | 
         
             
            									title="Download prompt and parameters"
         
     | 
| 474 | 
         
             
            									type="button"
         
     | 
| 475 | 
         
             
            									target="_blank"
         
     | 
| 
         | 
|
| 480 | 
         
             
            							{/if}
         
     | 
| 481 | 
         
             
            							{#if !readOnly}
         
     | 
| 482 | 
         
             
            								<button
         
     | 
| 483 | 
         
            +
            									class="cursor-pointer rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-300 md:hidden lg:-right-2"
         
     | 
| 484 | 
         
             
            									title="Branch"
         
     | 
| 485 | 
         
             
            									type="button"
         
     | 
| 486 | 
         
             
            									on:click={() => ($convTreeStore.editing = message.id)}
         
     | 
| 
         | 
|
| 515 | 
         
             
            					class="font-white group/navbranch z-10 -mt-1 ml-3.5 mr-auto flex h-6 w-fit select-none flex-row items-center justify-center gap-1 text-sm"
         
     | 
| 516 | 
         
             
            				>
         
     | 
| 517 | 
         
             
            					<button
         
     | 
| 518 | 
         
            +
            						class="inline text-lg font-thin text-gray-400 hover:text-gray-800 disabled:pointer-events-none disabled:opacity-25 dark:text-gray-500 dark:hover:text-gray-200"
         
     | 
| 519 | 
         
             
            						on:click={() => (childrenToRender = Math.max(0, childrenToRender - 1))}
         
     | 
| 520 | 
         
             
            						disabled={childrenToRender === 0 || loading}
         
     | 
| 521 | 
         
             
            					>
         
     | 
| 
         | 
|
| 525 | 
         
             
            						{childrenToRender + 1} / {nChildren}
         
     | 
| 526 | 
         
             
            					</span>
         
     | 
| 527 | 
         
             
            					<button
         
     | 
| 528 | 
         
            +
            						class="inline text-lg font-thin text-gray-400 hover:text-gray-800 disabled:pointer-events-none disabled:opacity-25 dark:text-gray-500 dark:hover:text-gray-200"
         
     | 
| 529 | 
         
             
            						on:click={() =>
         
     | 
| 530 | 
         
             
            							(childrenToRender = Math.min(
         
     | 
| 531 | 
         
             
            								message?.children?.length ?? 1 - 1,
         
     | 
    	
        src/lib/components/chat/ChatWindow.svelte
    CHANGED
    
    | 
         @@ -281,7 +281,7 @@ 
     | 
|
| 281 | 
         
             
            		/>
         
     | 
| 282 | 
         
             
            	</div>
         
     | 
| 283 | 
         
             
            	<div
         
     | 
| 284 | 
         
            -
            		class="dark:via-gray-80 pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/80 to-white/0 px-3.5 py-4  
     | 
| 285 | 
         
             
            	>
         
     | 
| 286 | 
         
             
            		{#if sources?.length}
         
     | 
| 287 | 
         
             
            			<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
         
     | 
| 
         @@ -373,19 +373,19 @@ 
     | 
|
| 373 | 
         | 
| 374 | 
         
             
            						{#if loading}
         
     | 
| 375 | 
         
             
            							<button
         
     | 
| 376 | 
         
            -
            								class="btn mx-1 my-1 inline-block h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400  
     | 
| 377 | 
         
             
            								on:click={() => dispatch("stop")}
         
     | 
| 378 | 
         
             
            							>
         
     | 
| 379 | 
         
             
            								<CarbonStopFilledAlt />
         
     | 
| 380 | 
         
             
            							</button>
         
     | 
| 381 | 
         
             
            							<div
         
     | 
| 382 | 
         
            -
            								class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400  
     | 
| 383 | 
         
             
            							>
         
     | 
| 384 | 
         
             
            								<EosIconsLoading />
         
     | 
| 385 | 
         
             
            							</div>
         
     | 
| 386 | 
         
             
            						{:else}
         
     | 
| 387 | 
         
             
            							<button
         
     | 
| 388 | 
         
            -
            								class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400  
     | 
| 389 | 
         
             
            								disabled={!message || isReadOnly}
         
     | 
| 390 | 
         
             
            								type="submit"
         
     | 
| 391 | 
         
             
            							>
         
     | 
| 
         | 
|
| 281 | 
         
             
            		/>
         
     | 
| 282 | 
         
             
            	</div>
         
     | 
| 283 | 
         
             
            	<div
         
     | 
| 284 | 
         
            +
            		class="dark:via-gray-80 pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/80 to-white/0 px-3.5 py-4 dark:border-gray-800 dark:from-gray-900 dark:to-gray-900/0 max-md:border-t max-md:bg-white max-md:dark:bg-gray-900 sm:px-5 md:py-8 xl:max-w-4xl [&>*]:pointer-events-auto"
         
     | 
| 285 | 
         
             
            	>
         
     | 
| 286 | 
         
             
            		{#if sources?.length}
         
     | 
| 287 | 
         
             
            			<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
         
     | 
| 
         | 
|
| 373 | 
         | 
| 374 | 
         
             
            						{#if loading}
         
     | 
| 375 | 
         
             
            							<button
         
     | 
| 376 | 
         
            +
            								class="btn mx-1 my-1 inline-block h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40 md:hidden"
         
     | 
| 377 | 
         
             
            								on:click={() => dispatch("stop")}
         
     | 
| 378 | 
         
             
            							>
         
     | 
| 379 | 
         
             
            								<CarbonStopFilledAlt />
         
     | 
| 380 | 
         
             
            							</button>
         
     | 
| 381 | 
         
             
            							<div
         
     | 
| 382 | 
         
            +
            								class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40 md:flex"
         
     | 
| 383 | 
         
             
            							>
         
     | 
| 384 | 
         
             
            								<EosIconsLoading />
         
     | 
| 385 | 
         
             
            							</div>
         
     | 
| 386 | 
         
             
            						{:else}
         
     | 
| 387 | 
         
             
            							<button
         
     | 
| 388 | 
         
            +
            								class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40"
         
     | 
| 389 | 
         
             
            								disabled={!message || isReadOnly}
         
     | 
| 390 | 
         
             
            								type="submit"
         
     | 
| 391 | 
         
             
            							>
         
     | 
    	
        src/lib/server/auth.ts
    CHANGED
    
    | 
         @@ -1,4 +1,10 @@ 
     | 
|
| 1 | 
         
            -
            import { 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 2 | 
         
             
            import { addHours, addWeeks } from "date-fns";
         
     | 
| 3 | 
         
             
            import { env } from "$env/dynamic/private";
         
     | 
| 4 | 
         
             
            import { sha256 } from "$lib/utils/sha256";
         
     | 
| 
         | 
|
| 1 | 
         
            +
            import {
         
     | 
| 2 | 
         
            +
            	Issuer,
         
     | 
| 3 | 
         
            +
            	type BaseClient,
         
     | 
| 4 | 
         
            +
            	type UserinfoResponse,
         
     | 
| 5 | 
         
            +
            	type TokenSet,
         
     | 
| 6 | 
         
            +
            	custom,
         
     | 
| 7 | 
         
            +
            } from "openid-client";
         
     | 
| 8 | 
         
             
            import { addHours, addWeeks } from "date-fns";
         
     | 
| 9 | 
         
             
            import { env } from "$env/dynamic/private";
         
     | 
| 10 | 
         
             
            import { sha256 } from "$lib/utils/sha256";
         
     | 
    	
        src/lib/server/endpoints/anthropic/utils.ts
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 1 | 
         
            -
            import type { ImageBlockParam, MessageParam } from "@anthropic-ai/sdk/resources";
         
     | 
| 2 | 
         
             
            import { makeImageProcessor, type ImageProcessorOptions } from "../images";
         
     | 
| 3 | 
         
             
            import type { EndpointMessage } from "../endpoints";
         
     | 
| 4 | 
         
             
            import type { MessageFile } from "$lib/types/Message";
         
     | 
| 
         | 
|
| 5 | 
         | 
| 6 | 
         
             
            export async function fileToImageBlock(
         
     | 
| 7 | 
         
             
            	file: MessageFile,
         
     | 
| 
         | 
|
| 
         | 
|
| 1 | 
         
             
            import { makeImageProcessor, type ImageProcessorOptions } from "../images";
         
     | 
| 2 | 
         
             
            import type { EndpointMessage } from "../endpoints";
         
     | 
| 3 | 
         
             
            import type { MessageFile } from "$lib/types/Message";
         
     | 
| 4 | 
         
            +
            import type { ImageBlockParam, MessageParam } from "@anthropic-ai/sdk/resources/messages.mjs";
         
     | 
| 5 | 
         | 
| 6 | 
         
             
            export async function fileToImageBlock(
         
     | 
| 7 | 
         
             
            	file: MessageFile,
         
     | 
    	
        src/lib/server/endpoints/cohere/endpointCohere.ts
    CHANGED
    
    | 
         @@ -5,7 +5,7 @@ import type { TextGenerationStreamOutput } from "@huggingface/inference"; 
     | 
|
| 5 | 
         
             
            import type { Cohere, CohereClient } from "cohere-ai";
         
     | 
| 6 | 
         
             
            import { buildPrompt } from "$lib/buildPrompt";
         
     | 
| 7 | 
         
             
            import { ToolResultStatus, type ToolCall } from "$lib/types/Tool";
         
     | 
| 8 | 
         
            -
            import { pipeline, Writable, Readable } from "node:stream";
         
     | 
| 9 | 
         
             
            import { toolHasName } from "$lib/utils/tools";
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            export const endpointCohereParametersSchema = z.object({
         
     | 
| 
         @@ -78,7 +78,7 @@ export async function endpointCohere( 
     | 
|
| 78 | 
         
             
            					.map((message) => ({
         
     | 
| 79 | 
         
             
            						role: message.from === "user" ? "USER" : "CHATBOT",
         
     | 
| 80 | 
         
             
            						message: message.content,
         
     | 
| 81 | 
         
            -
            					})) satisfies Cohere. 
     | 
| 82 | 
         | 
| 83 | 
         
             
            				stream = await cohere
         
     | 
| 84 | 
         
             
            					.chatStream({
         
     | 
| 
         | 
|
| 5 | 
         
             
            import type { Cohere, CohereClient } from "cohere-ai";
         
     | 
| 6 | 
         
             
            import { buildPrompt } from "$lib/buildPrompt";
         
     | 
| 7 | 
         
             
            import { ToolResultStatus, type ToolCall } from "$lib/types/Tool";
         
     | 
| 8 | 
         
            +
            import { pipeline, Writable, type Readable } from "node:stream";
         
     | 
| 9 | 
         
             
            import { toolHasName } from "$lib/utils/tools";
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            export const endpointCohereParametersSchema = z.object({
         
     | 
| 
         | 
|
| 78 | 
         
             
            					.map((message) => ({
         
     | 
| 79 | 
         
             
            						role: message.from === "user" ? "USER" : "CHATBOT",
         
     | 
| 80 | 
         
             
            						message: message.content,
         
     | 
| 81 | 
         
            +
            					})) satisfies Cohere.Message[];
         
     | 
| 82 | 
         | 
| 83 | 
         
             
            				stream = await cohere
         
     | 
| 84 | 
         
             
            					.chatStream({
         
     | 
    	
        src/lib/server/exitHandler.ts
    CHANGED
    
    | 
         @@ -17,7 +17,7 @@ export function onExit(cb: ExitHandler): ExitHandlerUnsubscribe { 
     | 
|
| 17 | 
         | 
| 18 | 
         
             
            async function runExitHandler(handler: ExitHandler): Promise<void> {
         
     | 
| 19 | 
         
             
            	return timeout(Promise.resolve().then(handler), 30_000).catch((err) => {
         
     | 
| 20 | 
         
            -
            		logger.error("Exit handler failed to run" 
     | 
| 21 | 
         
             
            	});
         
     | 
| 22 | 
         
             
            }
         
     | 
| 23 | 
         | 
| 
         | 
|
| 17 | 
         | 
| 18 | 
         
             
            async function runExitHandler(handler: ExitHandler): Promise<void> {
         
     | 
| 19 | 
         
             
            	return timeout(Promise.resolve().then(handler), 30_000).catch((err) => {
         
     | 
| 20 | 
         
            +
            		logger.error(err, "Exit handler failed to run");
         
     | 
| 21 | 
         
             
            	});
         
     | 
| 22 | 
         
             
            }
         
     | 
| 23 | 
         | 
    	
        src/lib/server/files/downloadFile.ts
    CHANGED
    
    | 
         @@ -12,10 +12,10 @@ export async function downloadFile( 
     | 
|
| 12 | 
         | 
| 13 | 
         
             
            	const file = await fileId.next();
         
     | 
| 14 | 
         
             
            	if (!file) {
         
     | 
| 15 | 
         
            -
            		 
     | 
| 16 | 
         
             
            	}
         
     | 
| 17 | 
         
             
            	if (file.metadata?.conversation !== convId.toString()) {
         
     | 
| 18 | 
         
            -
            		 
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	const mime = file.metadata?.mime;
         
     | 
| 
         | 
|
| 12 | 
         | 
| 13 | 
         
             
            	const file = await fileId.next();
         
     | 
| 14 | 
         
             
            	if (!file) {
         
     | 
| 15 | 
         
            +
            		error(404, "File not found");
         
     | 
| 16 | 
         
             
            	}
         
     | 
| 17 | 
         
             
            	if (file.metadata?.conversation !== convId.toString()) {
         
     | 
| 18 | 
         
            +
            		error(403, "You don't have access to this file.");
         
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	const mime = file.metadata?.mime;
         
     | 
    	
        src/routes/+layout.svelte
    CHANGED
    
    | 
         @@ -207,7 +207,7 @@ 
     | 
|
| 207 | 
         
             
            <div
         
     | 
| 208 | 
         
             
            	class="grid h-full w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd {!isNavCollapsed
         
     | 
| 209 | 
         
             
            		? 'md:grid-cols-[280px,1fr]'
         
     | 
| 210 | 
         
            -
            		: 'md:grid-cols-[0px,1fr]'} transition-[300ms] [transition-property:grid-template-columns] md:grid-rows-[1fr] 
     | 
| 211 | 
         
             
            >
         
     | 
| 212 | 
         
             
            	<MobileNav isOpen={isNavOpen} on:toggle={(ev) => (isNavOpen = ev.detail)} title={mobileNavTitle}>
         
     | 
| 213 | 
         
             
            		<NavMenu
         
     | 
| 
         @@ -242,8 +242,8 @@ 
     | 
|
| 242 | 
         
             
            		href="https://play.google.com/store/apps/details?id=co.huggingface.chat_ui_android"
         
     | 
| 243 | 
         
             
            		class="fixed left-0 right-0 top-0 mx-auto flex h-fit min-h-12 w-screen flex-nowrap items-center justify-evenly gap-4 bg-gray-200 px-4 py-4 text-gray-900 shadow-lg backdrop-blur-md
         
     | 
| 244 | 
         
             
            		hover:bg-gray-100
         
     | 
| 245 | 
         
            -
            		 
     | 
| 246 | 
         
            -
            		 
     | 
| 247 | 
         
             
            	>
         
     | 
| 248 | 
         
             
            		<button
         
     | 
| 249 | 
         
             
            			class="border-r-2 border-black/20 pr-4 text-2xl"
         
     | 
| 
         | 
|
| 207 | 
         
             
            <div
         
     | 
| 208 | 
         
             
            	class="grid h-full w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd {!isNavCollapsed
         
     | 
| 209 | 
         
             
            		? 'md:grid-cols-[280px,1fr]'
         
     | 
| 210 | 
         
            +
            		: 'md:grid-cols-[0px,1fr]'} transition-[300ms] [transition-property:grid-template-columns] dark:text-gray-300 md:grid-rows-[1fr]"
         
     | 
| 211 | 
         
             
            >
         
     | 
| 212 | 
         
             
            	<MobileNav isOpen={isNavOpen} on:toggle={(ev) => (isNavOpen = ev.detail)} title={mobileNavTitle}>
         
     | 
| 213 | 
         
             
            		<NavMenu
         
     | 
| 
         | 
|
| 242 | 
         
             
            		href="https://play.google.com/store/apps/details?id=co.huggingface.chat_ui_android"
         
     | 
| 243 | 
         
             
            		class="fixed left-0 right-0 top-0 mx-auto flex h-fit min-h-12 w-screen flex-nowrap items-center justify-evenly gap-4 bg-gray-200 px-4 py-4 text-gray-900 shadow-lg backdrop-blur-md
         
     | 
| 244 | 
         
             
            		hover:bg-gray-100
         
     | 
| 245 | 
         
            +
            		dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 sm:top-5
         
     | 
| 246 | 
         
            +
            		sm:max-w-fit sm:gap-4 sm:rounded-lg"
         
     | 
| 247 | 
         
             
            	>
         
     | 
| 248 | 
         
             
            		<button
         
     | 
| 249 | 
         
             
            			class="border-r-2 border-black/20 pr-4 text-2xl"
         
     | 
    	
        src/routes/admin/export/+server.ts
    CHANGED
    
    | 
         @@ -14,7 +14,7 @@ import { logger } from "$lib/server/logger.js"; 
     | 
|
| 14 | 
         | 
| 15 | 
         
             
            export async function POST({ request }) {
         
     | 
| 16 | 
         
             
            	if (!env.PARQUET_EXPORT_DATASET || !env.PARQUET_EXPORT_HF_TOKEN) {
         
     | 
| 17 | 
         
            -
            		 
     | 
| 18 | 
         
             
            	}
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const { model } = z
         
     | 
| 
         | 
|
| 14 | 
         | 
| 15 | 
         
             
            export async function POST({ request }) {
         
     | 
| 16 | 
         
             
            	if (!env.PARQUET_EXPORT_DATASET || !env.PARQUET_EXPORT_HF_TOKEN) {
         
     | 
| 17 | 
         
            +
            		error(500, "Parquet export is not configured.");
         
     | 
| 18 | 
         
             
            	}
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const { model } = z
         
     | 
    	
        src/routes/assistant/[assistantId]/+page.server.ts
    CHANGED
    
    | 
         @@ -10,11 +10,11 @@ export const load = async ({ params }) => { 
     | 
|
| 10 | 
         
             
            		});
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            		if (!assistant) {
         
     | 
| 13 | 
         
            -
            			 
     | 
| 14 | 
         
             
            		}
         
     | 
| 15 | 
         | 
| 16 | 
         
             
            		return { assistant: JSON.parse(JSON.stringify(assistant)) };
         
     | 
| 17 | 
         
             
            	} catch {
         
     | 
| 18 | 
         
            -
            		 
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         
             
            };
         
     | 
| 
         | 
|
| 10 | 
         
             
            		});
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            		if (!assistant) {
         
     | 
| 13 | 
         
            +
            			redirect(302, `${base}`);
         
     | 
| 14 | 
         
             
            		}
         
     | 
| 15 | 
         | 
| 16 | 
         
             
            		return { assistant: JSON.parse(JSON.stringify(assistant)) };
         
     | 
| 17 | 
         
             
            	} catch {
         
     | 
| 18 | 
         
            +
            		redirect(302, `${base}`);
         
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         
             
            };
         
     | 
    	
        src/routes/assistant/[assistantId]/thumbnail.png/+server.ts
    CHANGED
    
    | 
         @@ -18,7 +18,7 @@ export const GET: RequestHandler = (async ({ params }) => { 
     | 
|
| 18 | 
         
             
            	});
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	if (!assistant) {
         
     | 
| 21 | 
         
            -
            		 
     | 
| 22 | 
         
             
            	}
         
     | 
| 23 | 
         | 
| 24 | 
         
             
            	let avatar = "";
         
     | 
| 
         | 
|
| 18 | 
         
             
            	});
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	if (!assistant) {
         
     | 
| 21 | 
         
            +
            		error(404, "Assistant not found.");
         
     | 
| 22 | 
         
             
            	}
         
     | 
| 23 | 
         | 
| 24 | 
         
             
            	let avatar = "";
         
     | 
    	
        src/routes/assistants/+page.server.ts
    CHANGED
    
    | 
         @@ -11,7 +11,7 @@ const NUM_PER_PAGE = 24; 
     | 
|
| 11 | 
         | 
| 12 | 
         
             
            export const load = async ({ url, locals }) => {
         
     | 
| 13 | 
         
             
            	if (!env.ENABLE_ASSISTANTS) {
         
     | 
| 14 | 
         
            -
            		 
     | 
| 15 | 
         
             
            	}
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	const modelId = url.searchParams.get("modelId");
         
     | 
| 
         @@ -28,7 +28,7 @@ export const load = async ({ url, locals }) => { 
     | 
|
| 28 | 
         
             
            			{ projection: { _id: 1 } }
         
     | 
| 29 | 
         
             
            		);
         
     | 
| 30 | 
         
             
            		if (!user) {
         
     | 
| 31 | 
         
            -
            			 
     | 
| 32 | 
         
             
            		}
         
     | 
| 33 | 
         
             
            	}
         
     | 
| 34 | 
         | 
| 
         | 
|
| 11 | 
         | 
| 12 | 
         
             
            export const load = async ({ url, locals }) => {
         
     | 
| 13 | 
         
             
            	if (!env.ENABLE_ASSISTANTS) {
         
     | 
| 14 | 
         
            +
            		redirect(302, `${base}/`);
         
     | 
| 15 | 
         
             
            	}
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	const modelId = url.searchParams.get("modelId");
         
     | 
| 
         | 
|
| 28 | 
         
             
            			{ projection: { _id: 1 } }
         
     | 
| 29 | 
         
             
            		);
         
     | 
| 30 | 
         
             
            		if (!user) {
         
     | 
| 31 | 
         
            +
            			error(404, `User "${username}" doesn't exist`);
         
     | 
| 32 | 
         
             
            		}
         
     | 
| 33 | 
         
             
            	}
         
     | 
| 34 | 
         | 
    	
        src/routes/assistants/+page.svelte
    CHANGED
    
    | 
         @@ -195,7 +195,7 @@ 
     | 
|
| 195 | 
         
             
            				{/if}
         
     | 
| 196 | 
         
             
            			{/if}
         
     | 
| 197 | 
         
             
            			<div
         
     | 
| 198 | 
         
            -
            				class="relative ml-auto flex h-[30px] w-40 items-center rounded-full border px-2 has-[:focus]:border-gray-400  
     | 
| 199 | 
         
             
            			>
         
     | 
| 200 | 
         
             
            				<CarbonSearch class="pointer-events-none absolute left-2 text-xs text-gray-400" />
         
     | 
| 201 | 
         
             
            				<input
         
     | 
| 
         @@ -227,7 +227,7 @@ 
     | 
|
| 227 | 
         
             
            					!!assistant?.dynamicPrompt}
         
     | 
| 228 | 
         | 
| 229 | 
         
             
            				<button
         
     | 
| 230 | 
         
            -
            					class="relative flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner  
     | 
| 231 | 
         
             
            					on:click={() => {
         
     | 
| 232 | 
         
             
            						if (data.settings.assistants.includes(assistant._id.toString())) {
         
     | 
| 233 | 
         
             
            							settings.instantSet({ activeModel: assistant._id.toString() });
         
     | 
| 
         @@ -263,7 +263,7 @@ 
     | 
|
| 263 | 
         
             
            						/>
         
     | 
| 264 | 
         
             
            					{:else}
         
     | 
| 265 | 
         
             
            						<div
         
     | 
| 266 | 
         
            -
            							class="mb-2 flex aspect-square size-12 flex-none items-center justify-center rounded-full bg-gray-300 text-2xl font-bold uppercase text-gray-500 sm:mb-6 sm:size-20 
     | 
| 267 | 
         
             
            						>
         
     | 
| 268 | 
         
             
            							{assistant.name[0]}
         
     | 
| 269 | 
         
             
            						</div>
         
     | 
| 
         @@ -273,7 +273,7 @@ 
     | 
|
| 273 | 
         
             
            					>
         
     | 
| 274 | 
         
             
            						{assistant.name}
         
     | 
| 275 | 
         
             
            					</h3>
         
     | 
| 276 | 
         
            -
            					<p class="line-clamp-4 text-xs text-gray-700 sm:line-clamp-2 
     | 
| 277 | 
         
             
            						{assistant.description}
         
     | 
| 278 | 
         
             
            					</p>
         
     | 
| 279 | 
         
             
            					{#if assistant.createdByName}
         
     | 
| 
         | 
|
| 195 | 
         
             
            				{/if}
         
     | 
| 196 | 
         
             
            			{/if}
         
     | 
| 197 | 
         
             
            			<div
         
     | 
| 198 | 
         
            +
            				class="relative ml-auto flex h-[30px] w-40 items-center rounded-full border px-2 has-[:focus]:border-gray-400 dark:border-gray-600 sm:w-64"
         
     | 
| 199 | 
         
             
            			>
         
     | 
| 200 | 
         
             
            				<CarbonSearch class="pointer-events-none absolute left-2 text-xs text-gray-400" />
         
     | 
| 201 | 
         
             
            				<input
         
     | 
| 
         | 
|
| 227 | 
         
             
            					!!assistant?.dynamicPrompt}
         
     | 
| 228 | 
         | 
| 229 | 
         
             
            				<button
         
     | 
| 230 | 
         
            +
            					class="relative flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner dark:border-gray-800/70 dark:bg-gray-950/20 dark:hover:bg-gray-950/40 max-sm:px-4 sm:h-64 sm:pb-4 xl:pt-8"
         
     | 
| 231 | 
         
             
            					on:click={() => {
         
     | 
| 232 | 
         
             
            						if (data.settings.assistants.includes(assistant._id.toString())) {
         
     | 
| 233 | 
         
             
            							settings.instantSet({ activeModel: assistant._id.toString() });
         
     | 
| 
         | 
|
| 263 | 
         
             
            						/>
         
     | 
| 264 | 
         
             
            					{:else}
         
     | 
| 265 | 
         
             
            						<div
         
     | 
| 266 | 
         
            +
            							class="mb-2 flex aspect-square size-12 flex-none items-center justify-center rounded-full bg-gray-300 text-2xl font-bold uppercase text-gray-500 dark:bg-gray-800 sm:mb-6 sm:size-20"
         
     | 
| 267 | 
         
             
            						>
         
     | 
| 268 | 
         
             
            							{assistant.name[0]}
         
     | 
| 269 | 
         
             
            						</div>
         
     | 
| 
         | 
|
| 273 | 
         
             
            					>
         
     | 
| 274 | 
         
             
            						{assistant.name}
         
     | 
| 275 | 
         
             
            					</h3>
         
     | 
| 276 | 
         
            +
            					<p class="line-clamp-4 text-xs text-gray-700 dark:text-gray-400 sm:line-clamp-2">
         
     | 
| 277 | 
         
             
            						{assistant.description}
         
     | 
| 278 | 
         
             
            					</p>
         
     | 
| 279 | 
         
             
            					{#if assistant.createdByName}
         
     | 
    	
        src/routes/conversation/+server.ts
    CHANGED
    
    | 
         @@ -27,23 +27,20 @@ export const POST: RequestHandler = async ({ locals, request }) => { 
     | 
|
| 27 | 
         
             
            		.safeParse(JSON.parse(body));
         
     | 
| 28 | 
         | 
| 29 | 
         
             
            	if (!parsedBody.success) {
         
     | 
| 30 | 
         
            -
            		 
     | 
| 31 | 
         
             
            	}
         
     | 
| 32 | 
         
             
            	const values = parsedBody.data;
         
     | 
| 33 | 
         | 
| 34 | 
         
             
            	const convCount = await collections.conversations.countDocuments(authCondition(locals));
         
     | 
| 35 | 
         | 
| 36 | 
         
             
            	if (usageLimits?.conversations && convCount > usageLimits?.conversations) {
         
     | 
| 37 | 
         
            -
            		 
     | 
| 38 | 
         
            -
            			429,
         
     | 
| 39 | 
         
            -
            			"You have reached the maximum number of conversations. Delete some to continue."
         
     | 
| 40 | 
         
            -
            		);
         
     | 
| 41 | 
         
             
            	}
         
     | 
| 42 | 
         | 
| 43 | 
         
             
            	const model = models.find((m) => (m.id || m.name) === values.model);
         
     | 
| 44 | 
         | 
| 45 | 
         
             
            	if (!model) {
         
     | 
| 46 | 
         
            -
            		 
     | 
| 47 | 
         
             
            	}
         
     | 
| 48 | 
         | 
| 49 | 
         
             
            	let messages: Message[] = [
         
     | 
| 
         @@ -67,7 +64,7 @@ export const POST: RequestHandler = async ({ locals, request }) => { 
     | 
|
| 67 | 
         
             
            		});
         
     | 
| 68 | 
         | 
| 69 | 
         
             
            		if (!conversation) {
         
     | 
| 70 | 
         
            -
            			 
     | 
| 71 | 
         
             
            		}
         
     | 
| 72 | 
         | 
| 73 | 
         
             
            		title = conversation.title;
         
     | 
| 
         @@ -82,7 +79,7 @@ export const POST: RequestHandler = async ({ locals, request }) => { 
     | 
|
| 82 | 
         
             
            	embeddingModel ??= model.embeddingModel ?? defaultEmbeddingModel.name;
         
     | 
| 83 | 
         | 
| 84 | 
         
             
            	if (model.unlisted) {
         
     | 
| 85 | 
         
            -
            		 
     | 
| 86 | 
         
             
            	}
         
     | 
| 87 | 
         | 
| 88 | 
         
             
            	// get preprompt from assistant if it exists
         
     | 
| 
         @@ -127,5 +124,5 @@ export const POST: RequestHandler = async ({ locals, request }) => { 
     | 
|
| 127 | 
         
             
            };
         
     | 
| 128 | 
         | 
| 129 | 
         
             
            export const GET: RequestHandler = async () => {
         
     | 
| 130 | 
         
            -
            	 
     | 
| 131 | 
         
             
            };
         
     | 
| 
         | 
|
| 27 | 
         
             
            		.safeParse(JSON.parse(body));
         
     | 
| 28 | 
         | 
| 29 | 
         
             
            	if (!parsedBody.success) {
         
     | 
| 30 | 
         
            +
            		error(400, "Invalid request");
         
     | 
| 31 | 
         
             
            	}
         
     | 
| 32 | 
         
             
            	const values = parsedBody.data;
         
     | 
| 33 | 
         | 
| 34 | 
         
             
            	const convCount = await collections.conversations.countDocuments(authCondition(locals));
         
     | 
| 35 | 
         | 
| 36 | 
         
             
            	if (usageLimits?.conversations && convCount > usageLimits?.conversations) {
         
     | 
| 37 | 
         
            +
            		error(429, "You have reached the maximum number of conversations. Delete some to continue.");
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 38 | 
         
             
            	}
         
     | 
| 39 | 
         | 
| 40 | 
         
             
            	const model = models.find((m) => (m.id || m.name) === values.model);
         
     | 
| 41 | 
         | 
| 42 | 
         
             
            	if (!model) {
         
     | 
| 43 | 
         
            +
            		error(400, "Invalid model");
         
     | 
| 44 | 
         
             
            	}
         
     | 
| 45 | 
         | 
| 46 | 
         
             
            	let messages: Message[] = [
         
     | 
| 
         | 
|
| 64 | 
         
             
            		});
         
     | 
| 65 | 
         | 
| 66 | 
         
             
            		if (!conversation) {
         
     | 
| 67 | 
         
            +
            			error(404, "Conversation not found");
         
     | 
| 68 | 
         
             
            		}
         
     | 
| 69 | 
         | 
| 70 | 
         
             
            		title = conversation.title;
         
     | 
| 
         | 
|
| 79 | 
         
             
            	embeddingModel ??= model.embeddingModel ?? defaultEmbeddingModel.name;
         
     | 
| 80 | 
         | 
| 81 | 
         
             
            	if (model.unlisted) {
         
     | 
| 82 | 
         
            +
            		error(400, "Can't start a conversation with an unlisted model");
         
     | 
| 83 | 
         
             
            	}
         
     | 
| 84 | 
         | 
| 85 | 
         
             
            	// get preprompt from assistant if it exists
         
     | 
| 
         | 
|
| 124 | 
         
             
            };
         
     | 
| 125 | 
         | 
| 126 | 
         
             
            export const GET: RequestHandler = async () => {
         
     | 
| 127 | 
         
            +
            	redirect(302, `${base}/`);
         
     | 
| 128 | 
         
             
            };
         
     | 
    	
        src/routes/conversation/[id]/+page.server.ts
    CHANGED
    
    | 
         @@ -18,7 +18,7 @@ export const load = async ({ params, depends, locals }) => { 
     | 
|
| 18 | 
         
             
            		shared = true;
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            		if (!conversation) {
         
     | 
| 21 | 
         
            -
            			 
     | 
| 22 | 
         
             
            		}
         
     | 
| 23 | 
         
             
            	} else {
         
     | 
| 24 | 
         
             
            		// todo: add validation on params.id
         
     | 
| 
         @@ -36,13 +36,13 @@ export const load = async ({ params, depends, locals }) => { 
     | 
|
| 36 | 
         
             
            				})) !== 0;
         
     | 
| 37 | 
         | 
| 38 | 
         
             
            			if (conversationExists) {
         
     | 
| 39 | 
         
            -
            				 
     | 
| 40 | 
         
             
            					403,
         
     | 
| 41 | 
         
             
            					"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
         
     | 
| 42 | 
         
             
            				);
         
     | 
| 43 | 
         
             
            			}
         
     | 
| 44 | 
         | 
| 45 | 
         
            -
            			 
     | 
| 46 | 
         
             
            		}
         
     | 
| 47 | 
         
             
            	}
         
     | 
| 48 | 
         | 
| 
         @@ -73,7 +73,7 @@ export const actions = { 
     | 
|
| 73 | 
         
             
            		const messageId = data.get("messageId");
         
     | 
| 74 | 
         | 
| 75 | 
         
             
            		if (!messageId || typeof messageId !== "string") {
         
     | 
| 76 | 
         
            -
            			 
     | 
| 77 | 
         
             
            		}
         
     | 
| 78 | 
         | 
| 79 | 
         
             
            		const conversation = await collections.conversations.findOne({
         
     | 
| 
         @@ -82,7 +82,7 @@ export const actions = { 
     | 
|
| 82 | 
         
             
            		});
         
     | 
| 83 | 
         | 
| 84 | 
         
             
            		if (!conversation) {
         
     | 
| 85 | 
         
            -
            			 
     | 
| 86 | 
         
             
            		}
         
     | 
| 87 | 
         | 
| 88 | 
         
             
            		const filteredMessages = conversation.messages
         
     | 
| 
         | 
|
| 18 | 
         
             
            		shared = true;
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            		if (!conversation) {
         
     | 
| 21 | 
         
            +
            			error(404, "Conversation not found");
         
     | 
| 22 | 
         
             
            		}
         
     | 
| 23 | 
         
             
            	} else {
         
     | 
| 24 | 
         
             
            		// todo: add validation on params.id
         
     | 
| 
         | 
|
| 36 | 
         
             
            				})) !== 0;
         
     | 
| 37 | 
         | 
| 38 | 
         
             
            			if (conversationExists) {
         
     | 
| 39 | 
         
            +
            				error(
         
     | 
| 40 | 
         
             
            					403,
         
     | 
| 41 | 
         
             
            					"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
         
     | 
| 42 | 
         
             
            				);
         
     | 
| 43 | 
         
             
            			}
         
     | 
| 44 | 
         | 
| 45 | 
         
            +
            			error(404, "Conversation not found.");
         
     | 
| 46 | 
         
             
            		}
         
     | 
| 47 | 
         
             
            	}
         
     | 
| 48 | 
         | 
| 
         | 
|
| 73 | 
         
             
            		const messageId = data.get("messageId");
         
     | 
| 74 | 
         | 
| 75 | 
         
             
            		if (!messageId || typeof messageId !== "string") {
         
     | 
| 76 | 
         
            +
            			error(400, "Invalid message id");
         
     | 
| 77 | 
         
             
            		}
         
     | 
| 78 | 
         | 
| 79 | 
         
             
            		const conversation = await collections.conversations.findOne({
         
     | 
| 
         | 
|
| 82 | 
         
             
            		});
         
     | 
| 83 | 
         | 
| 84 | 
         
             
            		if (!conversation) {
         
     | 
| 85 | 
         
            +
            			error(404, "Conversation not found");
         
     | 
| 86 | 
         
             
            		}
         
     | 
| 87 | 
         | 
| 88 | 
         
             
            		const filteredMessages = conversation.messages
         
     | 
    	
        src/routes/conversation/[id]/+server.ts
    CHANGED
    
    | 
         @@ -33,7 +33,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 33 | 
         | 
| 34 | 
         
             
            	// check user
         
     | 
| 35 | 
         
             
            	if (!userId) {
         
     | 
| 36 | 
         
            -
            		 
     | 
| 37 | 
         
             
            	}
         
     | 
| 38 | 
         | 
| 39 | 
         
             
            	// check if the user has access to the conversation
         
     | 
| 
         @@ -56,7 +56,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 56 | 
         
             
            		);
         
     | 
| 57 | 
         | 
| 58 | 
         
             
            		if (!res.acknowledged) {
         
     | 
| 59 | 
         
            -
            			 
     | 
| 60 | 
         
             
            		}
         
     | 
| 61 | 
         
             
            	}
         
     | 
| 62 | 
         | 
| 
         @@ -66,7 +66,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 66 | 
         
             
            	});
         
     | 
| 67 | 
         | 
| 68 | 
         
             
            	if (!conv) {
         
     | 
| 69 | 
         
            -
            		 
     | 
| 70 | 
         
             
            	}
         
     | 
| 71 | 
         | 
| 72 | 
         
             
            	// register the event for ratelimiting
         
     | 
| 
         @@ -95,7 +95,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 95 | 
         
             
            			)[0]?.messages ?? 0;
         
     | 
| 96 | 
         | 
| 97 | 
         
             
            		if (totalMessages > messagesBeforeLogin) {
         
     | 
| 98 | 
         
            -
            			 
     | 
| 99 | 
         
             
            		}
         
     | 
| 100 | 
         
             
            	}
         
     | 
| 101 | 
         | 
| 
         @@ -112,12 +112,12 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 112 | 
         
             
            			})
         
     | 
| 113 | 
         
             
            		);
         
     | 
| 114 | 
         
             
            		if (nEvents > usageLimits.messagesPerMinute) {
         
     | 
| 115 | 
         
            -
            			 
     | 
| 116 | 
         
             
            		}
         
     | 
| 117 | 
         
             
            	}
         
     | 
| 118 | 
         | 
| 119 | 
         
             
            	if (usageLimits?.messages && conv.messages.length > usageLimits.messages) {
         
     | 
| 120 | 
         
            -
            		 
     | 
| 121 | 
         
             
            			429,
         
     | 
| 122 | 
         
             
            			`This conversation has more than ${usageLimits.messages} messages. Start a new one to continue`
         
     | 
| 123 | 
         
             
            		);
         
     | 
| 
         @@ -127,7 +127,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 127 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 128 | 
         | 
| 129 | 
         
             
            	if (!model) {
         
     | 
| 130 | 
         
            -
            		 
     | 
| 131 | 
         
             
            	}
         
     | 
| 132 | 
         | 
| 133 | 
         
             
            	// finally parse the content of the request
         
     | 
| 
         @@ -136,7 +136,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 136 | 
         
             
            	const json = form.get("data");
         
     | 
| 137 | 
         | 
| 138 | 
         
             
            	if (!json || typeof json !== "string") {
         
     | 
| 139 | 
         
            -
            		 
     | 
| 140 | 
         
             
            	}
         
     | 
| 141 | 
         | 
| 142 | 
         
             
            	const {
         
     | 
| 
         @@ -185,7 +185,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 185 | 
         
             
            	);
         
     | 
| 186 | 
         | 
| 187 | 
         
             
            	if (usageLimits?.messageLength && (newPrompt?.length ?? 0) > usageLimits.messageLength) {
         
     | 
| 188 | 
         
            -
            		 
     | 
| 189 | 
         
             
            	}
         
     | 
| 190 | 
         | 
| 191 | 
         
             
            	// each file is either:
         
     | 
| 
         @@ -203,7 +203,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 203 | 
         
             
            	// check sizes
         
     | 
| 204 | 
         
             
            	// todo: make configurable
         
     | 
| 205 | 
         
             
            	if (b64Files.some((file) => file.size > 10 * 1024 * 1024)) {
         
     | 
| 206 | 
         
            -
            		 
     | 
| 207 | 
         
             
            	}
         
     | 
| 208 | 
         | 
| 209 | 
         
             
            	const uploadedFiles = await Promise.all(b64Files.map((file) => uploadFile(file, conv))).then(
         
     | 
| 
         @@ -219,7 +219,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 219 | 
         
             
            		// if it's the last message and we continue then we build the prompt up to the last message
         
     | 
| 220 | 
         
             
            		// we will strip the end tokens afterwards when the prompt is built
         
     | 
| 221 | 
         
             
            		if ((conv.messages.find((msg) => msg.id === messageId)?.children?.length ?? 0) > 0) {
         
     | 
| 222 | 
         
            -
            			 
     | 
| 223 | 
         
             
            		}
         
     | 
| 224 | 
         
             
            		messageToWriteToId = messageId;
         
     | 
| 225 | 
         
             
            		messagesForPrompt = buildSubtree(conv, messageId);
         
     | 
| 
         @@ -232,7 +232,7 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 232 | 
         
             
            		const messageToRetry = conv.messages.find((message) => message.id === messageId);
         
     | 
| 233 | 
         | 
| 234 | 
         
             
            		if (!messageToRetry) {
         
     | 
| 235 | 
         
            -
            			 
     | 
| 236 | 
         
             
            		}
         
     | 
| 237 | 
         | 
| 238 | 
         
             
            		if (messageToRetry.from === "user" && newPrompt) {
         
     | 
| 
         @@ -302,10 +302,10 @@ export async function POST({ request, locals, params, getClientAddress }) { 
     | 
|
| 302 | 
         | 
| 303 | 
         
             
            	const messageToWriteTo = conv.messages.find((message) => message.id === messageToWriteToId);
         
     | 
| 304 | 
         
             
            	if (!messageToWriteTo) {
         
     | 
| 305 | 
         
            -
            		 
     | 
| 306 | 
         
             
            	}
         
     | 
| 307 | 
         
             
            	if (messagesForPrompt.length === 0) {
         
     | 
| 308 | 
         
            -
            		 
     | 
| 309 | 
         
             
            	}
         
     | 
| 310 | 
         | 
| 311 | 
         
             
            	// update the conversation with the new messages
         
     | 
| 
         @@ -491,7 +491,7 @@ export async function DELETE({ locals, params }) { 
     | 
|
| 491 | 
         
             
            	});
         
     | 
| 492 | 
         | 
| 493 | 
         
             
            	if (!conv) {
         
     | 
| 494 | 
         
            -
            		 
     | 
| 495 | 
         
             
            	}
         
     | 
| 496 | 
         | 
| 497 | 
         
             
            	await collections.conversations.deleteOne({ _id: conv._id });
         
     | 
| 
         @@ -512,7 +512,7 @@ export async function PATCH({ request, locals, params }) { 
     | 
|
| 512 | 
         
             
            	});
         
     | 
| 513 | 
         | 
| 514 | 
         
             
            	if (!conv) {
         
     | 
| 515 | 
         
            -
            		 
     | 
| 516 | 
         
             
            	}
         
     | 
| 517 | 
         | 
| 518 | 
         
             
            	await collections.conversations.updateOne(
         
     | 
| 
         | 
|
| 33 | 
         | 
| 34 | 
         
             
            	// check user
         
     | 
| 35 | 
         
             
            	if (!userId) {
         
     | 
| 36 | 
         
            +
            		error(401, "Unauthorized");
         
     | 
| 37 | 
         
             
            	}
         
     | 
| 38 | 
         | 
| 39 | 
         
             
            	// check if the user has access to the conversation
         
     | 
| 
         | 
|
| 56 | 
         
             
            		);
         
     | 
| 57 | 
         | 
| 58 | 
         
             
            		if (!res.acknowledged) {
         
     | 
| 59 | 
         
            +
            			error(500, "Failed to convert conversation");
         
     | 
| 60 | 
         
             
            		}
         
     | 
| 61 | 
         
             
            	}
         
     | 
| 62 | 
         | 
| 
         | 
|
| 66 | 
         
             
            	});
         
     | 
| 67 | 
         | 
| 68 | 
         
             
            	if (!conv) {
         
     | 
| 69 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 70 | 
         
             
            	}
         
     | 
| 71 | 
         | 
| 72 | 
         
             
            	// register the event for ratelimiting
         
     | 
| 
         | 
|
| 95 | 
         
             
            			)[0]?.messages ?? 0;
         
     | 
| 96 | 
         | 
| 97 | 
         
             
            		if (totalMessages > messagesBeforeLogin) {
         
     | 
| 98 | 
         
            +
            			error(429, "Exceeded number of messages before login");
         
     | 
| 99 | 
         
             
            		}
         
     | 
| 100 | 
         
             
            	}
         
     | 
| 101 | 
         | 
| 
         | 
|
| 112 | 
         
             
            			})
         
     | 
| 113 | 
         
             
            		);
         
     | 
| 114 | 
         
             
            		if (nEvents > usageLimits.messagesPerMinute) {
         
     | 
| 115 | 
         
            +
            			error(429, ERROR_MESSAGES.rateLimited);
         
     | 
| 116 | 
         
             
            		}
         
     | 
| 117 | 
         
             
            	}
         
     | 
| 118 | 
         | 
| 119 | 
         
             
            	if (usageLimits?.messages && conv.messages.length > usageLimits.messages) {
         
     | 
| 120 | 
         
            +
            		error(
         
     | 
| 121 | 
         
             
            			429,
         
     | 
| 122 | 
         
             
            			`This conversation has more than ${usageLimits.messages} messages. Start a new one to continue`
         
     | 
| 123 | 
         
             
            		);
         
     | 
| 
         | 
|
| 127 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 128 | 
         | 
| 129 | 
         
             
            	if (!model) {
         
     | 
| 130 | 
         
            +
            		error(410, "Model not available anymore");
         
     | 
| 131 | 
         
             
            	}
         
     | 
| 132 | 
         | 
| 133 | 
         
             
            	// finally parse the content of the request
         
     | 
| 
         | 
|
| 136 | 
         
             
            	const json = form.get("data");
         
     | 
| 137 | 
         | 
| 138 | 
         
             
            	if (!json || typeof json !== "string") {
         
     | 
| 139 | 
         
            +
            		error(400, "Invalid request");
         
     | 
| 140 | 
         
             
            	}
         
     | 
| 141 | 
         | 
| 142 | 
         
             
            	const {
         
     | 
| 
         | 
|
| 185 | 
         
             
            	);
         
     | 
| 186 | 
         | 
| 187 | 
         
             
            	if (usageLimits?.messageLength && (newPrompt?.length ?? 0) > usageLimits.messageLength) {
         
     | 
| 188 | 
         
            +
            		error(400, "Message too long.");
         
     | 
| 189 | 
         
             
            	}
         
     | 
| 190 | 
         | 
| 191 | 
         
             
            	// each file is either:
         
     | 
| 
         | 
|
| 203 | 
         
             
            	// check sizes
         
     | 
| 204 | 
         
             
            	// todo: make configurable
         
     | 
| 205 | 
         
             
            	if (b64Files.some((file) => file.size > 10 * 1024 * 1024)) {
         
     | 
| 206 | 
         
            +
            		error(413, "File too large, should be <10MB");
         
     | 
| 207 | 
         
             
            	}
         
     | 
| 208 | 
         | 
| 209 | 
         
             
            	const uploadedFiles = await Promise.all(b64Files.map((file) => uploadFile(file, conv))).then(
         
     | 
| 
         | 
|
| 219 | 
         
             
            		// if it's the last message and we continue then we build the prompt up to the last message
         
     | 
| 220 | 
         
             
            		// we will strip the end tokens afterwards when the prompt is built
         
     | 
| 221 | 
         
             
            		if ((conv.messages.find((msg) => msg.id === messageId)?.children?.length ?? 0) > 0) {
         
     | 
| 222 | 
         
            +
            			error(400, "Can only continue the last message");
         
     | 
| 223 | 
         
             
            		}
         
     | 
| 224 | 
         
             
            		messageToWriteToId = messageId;
         
     | 
| 225 | 
         
             
            		messagesForPrompt = buildSubtree(conv, messageId);
         
     | 
| 
         | 
|
| 232 | 
         
             
            		const messageToRetry = conv.messages.find((message) => message.id === messageId);
         
     | 
| 233 | 
         | 
| 234 | 
         
             
            		if (!messageToRetry) {
         
     | 
| 235 | 
         
            +
            			error(404, "Message not found");
         
     | 
| 236 | 
         
             
            		}
         
     | 
| 237 | 
         | 
| 238 | 
         
             
            		if (messageToRetry.from === "user" && newPrompt) {
         
     | 
| 
         | 
|
| 302 | 
         | 
| 303 | 
         
             
            	const messageToWriteTo = conv.messages.find((message) => message.id === messageToWriteToId);
         
     | 
| 304 | 
         
             
            	if (!messageToWriteTo) {
         
     | 
| 305 | 
         
            +
            		error(500, "Failed to create message");
         
     | 
| 306 | 
         
             
            	}
         
     | 
| 307 | 
         
             
            	if (messagesForPrompt.length === 0) {
         
     | 
| 308 | 
         
            +
            		error(500, "Failed to create prompt");
         
     | 
| 309 | 
         
             
            	}
         
     | 
| 310 | 
         | 
| 311 | 
         
             
            	// update the conversation with the new messages
         
     | 
| 
         | 
|
| 491 | 
         
             
            	});
         
     | 
| 492 | 
         | 
| 493 | 
         
             
            	if (!conv) {
         
     | 
| 494 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 495 | 
         
             
            	}
         
     | 
| 496 | 
         | 
| 497 | 
         
             
            	await collections.conversations.deleteOne({ _id: conv._id });
         
     | 
| 
         | 
|
| 512 | 
         
             
            	});
         
     | 
| 513 | 
         | 
| 514 | 
         
             
            	if (!conv) {
         
     | 
| 515 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 516 | 
         
             
            	}
         
     | 
| 517 | 
         | 
| 518 | 
         
             
            	await collections.conversations.updateOne(
         
     | 
    	
        src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts
    CHANGED
    
    | 
         @@ -19,7 +19,7 @@ export async function GET({ params, locals }) { 
     | 
|
| 19 | 
         
             
            			  });
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	if (conv === null) {
         
     | 
| 22 | 
         
            -
            		 
     | 
| 23 | 
         
             
            	}
         
     | 
| 24 | 
         | 
| 25 | 
         
             
            	const messageId = params.messageId;
         
     | 
| 
         @@ -27,13 +27,13 @@ export async function GET({ params, locals }) { 
     | 
|
| 27 | 
         
             
            	const messageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
         
     | 
| 28 | 
         | 
| 29 | 
         
             
            	if (!isMessageId(messageId) || messageIndex === -1) {
         
     | 
| 30 | 
         
            -
            		 
     | 
| 31 | 
         
             
            	}
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 34 | 
         | 
| 35 | 
         
             
            	if (!model) {
         
     | 
| 36 | 
         
            -
            		 
     | 
| 37 | 
         
             
            	}
         
     | 
| 38 | 
         | 
| 39 | 
         
             
            	const messagesUpTo = buildSubtree(conv, messageId);
         
     | 
| 
         | 
|
| 19 | 
         
             
            			  });
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	if (conv === null) {
         
     | 
| 22 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 23 | 
         
             
            	}
         
     | 
| 24 | 
         | 
| 25 | 
         
             
            	const messageId = params.messageId;
         
     | 
| 
         | 
|
| 27 | 
         
             
            	const messageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
         
     | 
| 28 | 
         | 
| 29 | 
         
             
            	if (!isMessageId(messageId) || messageIndex === -1) {
         
     | 
| 30 | 
         
            +
            		error(404, "Message not found");
         
     | 
| 31 | 
         
             
            	}
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 34 | 
         | 
| 35 | 
         
             
            	if (!model) {
         
     | 
| 36 | 
         
            +
            		error(404, "Conversation model not found");
         
     | 
| 37 | 
         
             
            	}
         
     | 
| 38 | 
         | 
| 39 | 
         
             
            	const messagesUpTo = buildSubtree(conv, messageId);
         
     | 
    	
        src/routes/conversation/[id]/message/[messageId]/vote/+server.ts
    CHANGED
    
    | 
         @@ -31,7 +31,7 @@ export async function POST({ params, request, locals }) { 
     | 
|
| 31 | 
         
             
            	);
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            	if (!document.matchedCount) {
         
     | 
| 34 | 
         
            -
            		 
     | 
| 35 | 
         
             
            	}
         
     | 
| 36 | 
         | 
| 37 | 
         
             
            	return new Response();
         
     | 
| 
         | 
|
| 31 | 
         
             
            	);
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            	if (!document.matchedCount) {
         
     | 
| 34 | 
         
            +
            		error(404, "Message not found");
         
     | 
| 35 | 
         
             
            	}
         
     | 
| 36 | 
         | 
| 37 | 
         
             
            	return new Response();
         
     | 
    	
        src/routes/conversation/[id]/output/[sha256]/+server.ts
    CHANGED
    
    | 
         @@ -13,7 +13,7 @@ export const GET: RequestHandler = async ({ locals, params }) => { 
     | 
|
| 13 | 
         | 
| 14 | 
         
             
            	// check user
         
     | 
| 15 | 
         
             
            	if (!userId) {
         
     | 
| 16 | 
         
            -
            		 
     | 
| 17 | 
         
             
            	}
         
     | 
| 18 | 
         | 
| 19 | 
         
             
            	if (params.id.length !== 7) {
         
     | 
| 
         @@ -26,7 +26,7 @@ export const GET: RequestHandler = async ({ locals, params }) => { 
     | 
|
| 26 | 
         
             
            		});
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            		if (!conv) {
         
     | 
| 29 | 
         
            -
            			 
     | 
| 30 | 
         
             
            		}
         
     | 
| 31 | 
         
             
            	} else {
         
     | 
| 32 | 
         
             
            		// look for the conversation in shared conversations
         
     | 
| 
         @@ -35,7 +35,7 @@ export const GET: RequestHandler = async ({ locals, params }) => { 
     | 
|
| 35 | 
         
             
            		});
         
     | 
| 36 | 
         | 
| 37 | 
         
             
            		if (!conv) {
         
     | 
| 38 | 
         
            -
            			 
     | 
| 39 | 
         
             
            		}
         
     | 
| 40 | 
         
             
            	}
         
     | 
| 41 | 
         | 
| 
         | 
|
| 13 | 
         | 
| 14 | 
         
             
            	// check user
         
     | 
| 15 | 
         
             
            	if (!userId) {
         
     | 
| 16 | 
         
            +
            		error(401, "Unauthorized");
         
     | 
| 17 | 
         
             
            	}
         
     | 
| 18 | 
         | 
| 19 | 
         
             
            	if (params.id.length !== 7) {
         
     | 
| 
         | 
|
| 26 | 
         
             
            		});
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            		if (!conv) {
         
     | 
| 29 | 
         
            +
            			error(404, "Conversation not found");
         
     | 
| 30 | 
         
             
            		}
         
     | 
| 31 | 
         
             
            	} else {
         
     | 
| 32 | 
         
             
            		// look for the conversation in shared conversations
         
     | 
| 
         | 
|
| 35 | 
         
             
            		});
         
     | 
| 36 | 
         | 
| 37 | 
         
             
            		if (!conv) {
         
     | 
| 38 | 
         
            +
            			error(404, "Conversation not found");
         
     | 
| 39 | 
         
             
            		}
         
     | 
| 40 | 
         
             
            	}
         
     | 
| 41 | 
         | 
    	
        src/routes/conversation/[id]/share/+server.ts
    CHANGED
    
    | 
         @@ -14,7 +14,7 @@ export async function POST({ params, url, locals }) { 
     | 
|
| 14 | 
         
             
            	});
         
     | 
| 15 | 
         | 
| 16 | 
         
             
            	if (!conversation) {
         
     | 
| 17 | 
         
            -
            		 
     | 
| 18 | 
         
             
            	}
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const hash = await hashConv(conversation);
         
     | 
| 
         | 
|
| 14 | 
         
             
            	});
         
     | 
| 15 | 
         | 
| 16 | 
         
             
            	if (!conversation) {
         
     | 
| 17 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 18 | 
         
             
            	}
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const hash = await hashConv(conversation);
         
     | 
    	
        src/routes/conversation/[id]/stop-generating/+server.ts
    CHANGED
    
    | 
         @@ -15,7 +15,7 @@ export async function POST({ params, locals }) { 
     | 
|
| 15 | 
         
             
            	});
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	if (!conversation) {
         
     | 
| 18 | 
         
            -
            		 
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	await collections.abortedGenerations.updateOne(
         
     | 
| 
         | 
|
| 15 | 
         
             
            	});
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	if (!conversation) {
         
     | 
| 18 | 
         
            +
            		error(404, "Conversation not found");
         
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         | 
| 21 | 
         
             
            	await collections.abortedGenerations.updateOne(
         
     | 
    	
        src/routes/conversations/+page.server.ts
    CHANGED
    
    | 
         @@ -12,6 +12,6 @@ export const actions = { 
     | 
|
| 12 | 
         
             
            			});
         
     | 
| 13 | 
         
             
            		}
         
     | 
| 14 | 
         | 
| 15 | 
         
            -
            		 
     | 
| 16 | 
         
             
            	},
         
     | 
| 17 | 
         
             
            };
         
     | 
| 
         | 
|
| 12 | 
         
             
            			});
         
     | 
| 13 | 
         
             
            		}
         
     | 
| 14 | 
         | 
| 15 | 
         
            +
            		redirect(303, `${base}/`);
         
     | 
| 16 | 
         
             
            	},
         
     | 
| 17 | 
         
             
            };
         
     | 
    	
        src/routes/login/+page.server.ts
    CHANGED
    
    | 
         @@ -22,6 +22,6 @@ export const actions = { 
     | 
|
| 22 | 
         
             
            			{ sessionId: locals.sessionId }
         
     | 
| 23 | 
         
             
            		);
         
     | 
| 24 | 
         | 
| 25 | 
         
            -
            		 
     | 
| 26 | 
         
             
            	},
         
     | 
| 27 | 
         
             
            };
         
     | 
| 
         | 
|
| 22 | 
         
             
            			{ sessionId: locals.sessionId }
         
     | 
| 23 | 
         
             
            		);
         
     | 
| 24 | 
         | 
| 25 | 
         
            +
            		redirect(303, authorizationUrl);
         
     | 
| 26 | 
         
             
            	},
         
     | 
| 27 | 
         
             
            };
         
     | 
    	
        src/routes/login/callback/+page.server.ts
    CHANGED
    
    | 
         @@ -22,7 +22,7 @@ export async function load({ url, locals, cookies, request, getClientAddress }) 
     | 
|
| 22 | 
         
             
            		.parse(Object.fromEntries(url.searchParams.entries()));
         
     | 
| 23 | 
         | 
| 24 | 
         
             
            	if (errorName) {
         
     | 
| 25 | 
         
            -
            		 
     | 
| 26 | 
         
             
            	}
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            	const { code, state, iss } = z
         
     | 
| 
         @@ -38,7 +38,7 @@ export async function load({ url, locals, cookies, request, getClientAddress }) 
     | 
|
| 38 | 
         
             
            	const validatedToken = await validateAndParseCsrfToken(csrfToken, locals.sessionId);
         
     | 
| 39 | 
         | 
| 40 | 
         
             
            	if (!validatedToken) {
         
     | 
| 41 | 
         
            -
            		 
     | 
| 42 | 
         
             
            	}
         
     | 
| 43 | 
         | 
| 44 | 
         
             
            	const { userData } = await getOIDCUserData(
         
     | 
| 
         @@ -50,14 +50,14 @@ export async function load({ url, locals, cookies, request, getClientAddress }) 
     | 
|
| 50 | 
         
             
            	// Filter by allowed user emails
         
     | 
| 51 | 
         
             
            	if (allowedUserEmails.length > 0) {
         
     | 
| 52 | 
         
             
            		if (!userData.email) {
         
     | 
| 53 | 
         
            -
            			 
     | 
| 54 | 
         
             
            		}
         
     | 
| 55 | 
         
             
            		const emailVerified = userData.email_verified ?? true;
         
     | 
| 56 | 
         
             
            		if (!emailVerified) {
         
     | 
| 57 | 
         
            -
            			 
     | 
| 58 | 
         
             
            		}
         
     | 
| 59 | 
         
             
            		if (!allowedUserEmails.includes(userData.email)) {
         
     | 
| 60 | 
         
            -
            			 
     | 
| 61 | 
         
             
            		}
         
     | 
| 62 | 
         
             
            	}
         
     | 
| 63 | 
         | 
| 
         @@ -71,5 +71,5 @@ export async function load({ url, locals, cookies, request, getClientAddress }) 
     | 
|
| 71 | 
         
             
            		ip: getClientAddress(),
         
     | 
| 72 | 
         
             
            	});
         
     | 
| 73 | 
         | 
| 74 | 
         
            -
            	 
     | 
| 75 | 
         
             
            }
         
     | 
| 
         | 
|
| 22 | 
         
             
            		.parse(Object.fromEntries(url.searchParams.entries()));
         
     | 
| 23 | 
         | 
| 24 | 
         
             
            	if (errorName) {
         
     | 
| 25 | 
         
            +
            		error(400, errorName + (errorDescription ? ": " + errorDescription : ""));
         
     | 
| 26 | 
         
             
            	}
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            	const { code, state, iss } = z
         
     | 
| 
         | 
|
| 38 | 
         
             
            	const validatedToken = await validateAndParseCsrfToken(csrfToken, locals.sessionId);
         
     | 
| 39 | 
         | 
| 40 | 
         
             
            	if (!validatedToken) {
         
     | 
| 41 | 
         
            +
            		error(403, "Invalid or expired CSRF token");
         
     | 
| 42 | 
         
             
            	}
         
     | 
| 43 | 
         | 
| 44 | 
         
             
            	const { userData } = await getOIDCUserData(
         
     | 
| 
         | 
|
| 50 | 
         
             
            	// Filter by allowed user emails
         
     | 
| 51 | 
         
             
            	if (allowedUserEmails.length > 0) {
         
     | 
| 52 | 
         
             
            		if (!userData.email) {
         
     | 
| 53 | 
         
            +
            			error(403, "User not allowed: email not returned");
         
     | 
| 54 | 
         
             
            		}
         
     | 
| 55 | 
         
             
            		const emailVerified = userData.email_verified ?? true;
         
     | 
| 56 | 
         
             
            		if (!emailVerified) {
         
     | 
| 57 | 
         
            +
            			error(403, "User not allowed: email not verified");
         
     | 
| 58 | 
         
             
            		}
         
     | 
| 59 | 
         
             
            		if (!allowedUserEmails.includes(userData.email)) {
         
     | 
| 60 | 
         
            +
            			error(403, "User not allowed");
         
     | 
| 61 | 
         
             
            		}
         
     | 
| 62 | 
         
             
            	}
         
     | 
| 63 | 
         | 
| 
         | 
|
| 71 | 
         
             
            		ip: getClientAddress(),
         
     | 
| 72 | 
         
             
            	});
         
     | 
| 73 | 
         | 
| 74 | 
         
            +
            	redirect(302, `${base}/`);
         
     | 
| 75 | 
         
             
            }
         
     | 
    	
        src/routes/login/callback/updateUser.ts
    CHANGED
    
    | 
         @@ -103,7 +103,7 @@ export async function updateUser(params: { 
     | 
|
| 103 | 
         
             
            	const sessionId = await sha256(secretSessionId);
         
     | 
| 104 | 
         | 
| 105 | 
         
             
            	if (await collections.sessions.findOne({ sessionId })) {
         
     | 
| 106 | 
         
            -
            		 
     | 
| 107 | 
         
             
            	}
         
     | 
| 108 | 
         | 
| 109 | 
         
             
            	locals.sessionId = sessionId;
         
     | 
| 
         | 
|
| 103 | 
         
             
            	const sessionId = await sha256(secretSessionId);
         
     | 
| 104 | 
         | 
| 105 | 
         
             
            	if (await collections.sessions.findOne({ sessionId })) {
         
     | 
| 106 | 
         
            +
            		error(500, "Session ID collision");
         
     | 
| 107 | 
         
             
            	}
         
     | 
| 108 | 
         | 
| 109 | 
         
             
            	locals.sessionId = sessionId;
         
     | 
    	
        src/routes/logout/+page.server.ts
    CHANGED
    
    | 
         @@ -15,6 +15,6 @@ export const actions = { 
     | 
|
| 15 | 
         
             
            			secure: !dev && !(env.ALLOW_INSECURE_COOKIES === "true"),
         
     | 
| 16 | 
         
             
            			httpOnly: true,
         
     | 
| 17 | 
         
             
            		});
         
     | 
| 18 | 
         
            -
            		 
     | 
| 19 | 
         
             
            	},
         
     | 
| 20 | 
         
             
            };
         
     | 
| 
         | 
|
| 15 | 
         
             
            			secure: !dev && !(env.ALLOW_INSECURE_COOKIES === "true"),
         
     | 
| 16 | 
         
             
            			httpOnly: true,
         
     | 
| 17 | 
         
             
            		});
         
     | 
| 18 | 
         
            +
            		redirect(303, `${base}/`);
         
     | 
| 19 | 
         
             
            	},
         
     | 
| 20 | 
         
             
            };
         
     | 
    	
        src/routes/models/[...model]/+page.server.ts
    CHANGED
    
    | 
         @@ -9,7 +9,7 @@ export async function load({ params, locals, parent }) { 
     | 
|
| 9 | 
         
             
            	const data = await parent();
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 12 | 
         
            -
            		 
     | 
| 13 | 
         
             
            	}
         
     | 
| 14 | 
         | 
| 15 | 
         
             
            	if (locals.user?._id ?? locals.sessionId) {
         
     | 
| 
         | 
|
| 9 | 
         
             
            	const data = await parent();
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 12 | 
         
            +
            		redirect(302, `${base}/`);
         
     | 
| 13 | 
         
             
            	}
         
     | 
| 14 | 
         | 
| 15 | 
         
             
            	if (locals.user?._id ?? locals.sessionId) {
         
     | 
    	
        src/routes/models/[...model]/thumbnail.png/+server.ts
    CHANGED
    
    | 
         @@ -15,7 +15,7 @@ export const GET: RequestHandler = (async ({ params }) => { 
     | 
|
| 15 | 
         
             
            	const model = models.find(({ id }) => id === params.model);
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 18 | 
         
            -
            		 
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         
             
            	const renderedComponent = (ModelThumbnail as unknown as SvelteComponent).render({
         
     | 
| 21 | 
         
             
            		name: model.name,
         
     | 
| 
         | 
|
| 15 | 
         
             
            	const model = models.find(({ id }) => id === params.model);
         
     | 
| 16 | 
         | 
| 17 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 18 | 
         
            +
            		redirect(302, `${base}/`);
         
     | 
| 19 | 
         
             
            	}
         
     | 
| 20 | 
         
             
            	const renderedComponent = (ModelThumbnail as unknown as SvelteComponent).render({
         
     | 
| 21 | 
         
             
            		name: model.name,
         
     | 
    	
        src/routes/r/[id]/+page.ts
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 1 | 
         
             
            import { redirect } from "@sveltejs/kit";
         
     | 
| 2 | 
         | 
| 3 | 
         
             
            export const load = async ({ params }) => {
         
     | 
| 4 | 
         
            -
            	 
     | 
| 5 | 
         
             
            };
         
     | 
| 
         | 
|
| 1 | 
         
             
            import { redirect } from "@sveltejs/kit";
         
     | 
| 2 | 
         | 
| 3 | 
         
             
            export const load = async ({ params }) => {
         
     | 
| 4 | 
         
            +
            	redirect(302, "../conversation/" + params.id);
         
     | 
| 5 | 
         
             
            };
         
     | 
    	
        src/routes/settings/(nav)/+page.svelte
    CHANGED
    
    | 
         @@ -96,7 +96,7 @@ 
     | 
|
| 96 | 
         
             
            				</p>
         
     | 
| 97 | 
         
             
            				<button
         
     | 
| 98 | 
         
             
            					type="submit"
         
     | 
| 99 | 
         
            -
            					class="mt-2 rounded-full bg-red-700 px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-all focus-visible:outline-none focus-visible:ring 
     | 
| 100 | 
         
             
            				>
         
     | 
| 101 | 
         
             
            					Confirm deletion
         
     | 
| 102 | 
         
             
            				</button>
         
     | 
| 
         | 
|
| 96 | 
         
             
            				</p>
         
     | 
| 97 | 
         
             
            				<button
         
     | 
| 98 | 
         
             
            					type="submit"
         
     | 
| 99 | 
         
            +
            					class="mt-2 rounded-full bg-red-700 px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-all hover:ring focus-visible:outline-none focus-visible:ring"
         
     | 
| 100 | 
         
             
            				>
         
     | 
| 101 | 
         
             
            					Confirm deletion
         
     | 
| 102 | 
         
             
            				</button>
         
     | 
    	
        src/routes/settings/(nav)/[...model]/+page.ts
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ export async function load({ parent, params }) { 
     | 
|
| 7 | 
         
             
            	const model = data.models.find((m: { id: string }) => m.id === params.model);
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 10 | 
         
            -
            		 
     | 
| 11 | 
         
             
            	}
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            	return data;
         
     | 
| 
         | 
|
| 7 | 
         
             
            	const model = data.models.find((m: { id: string }) => m.id === params.model);
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            	if (!model || model.unlisted) {
         
     | 
| 10 | 
         
            +
            		redirect(302, `${base}/settings`);
         
     | 
| 11 | 
         
             
            	}
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            	return data;
         
     | 
    	
        src/routes/settings/(nav)/assistants/[assistantId]/+page.server.ts
    CHANGED
    
    | 
         @@ -57,7 +57,7 @@ export const actions: Actions = { 
     | 
|
| 57 | 
         
             
            			fileId = await fileCursor.next();
         
     | 
| 58 | 
         
             
            		}
         
     | 
| 59 | 
         | 
| 60 | 
         
            -
            		 
     | 
| 61 | 
         
             
            	},
         
     | 
| 62 | 
         
             
            	report: async ({ request, params, locals, url }) => {
         
     | 
| 63 | 
         
             
            		// is there already a report from this user for this model ?
         
     | 
| 
         @@ -168,7 +168,7 @@ export const actions: Actions = { 
     | 
|
| 168 | 
         
             
            			await collections.assistants.updateOne({ _id: assistant._id }, { $inc: { userCount: -1 } });
         
     | 
| 169 | 
         
             
            		}
         
     | 
| 170 | 
         | 
| 171 | 
         
            -
            		 
     | 
| 172 | 
         
             
            	},
         
     | 
| 173 | 
         | 
| 174 | 
         
             
            	unfeature: async ({ params, locals }) => {
         
     | 
| 
         | 
|
| 57 | 
         
             
            			fileId = await fileCursor.next();
         
     | 
| 58 | 
         
             
            		}
         
     | 
| 59 | 
         | 
| 60 | 
         
            +
            		redirect(302, `${base}/settings`);
         
     | 
| 61 | 
         
             
            	},
         
     | 
| 62 | 
         
             
            	report: async ({ request, params, locals, url }) => {
         
     | 
| 63 | 
         
             
            		// is there already a report from this user for this model ?
         
     | 
| 
         | 
|
| 168 | 
         
             
            			await collections.assistants.updateOne({ _id: assistant._id }, { $inc: { userCount: -1 } });
         
     | 
| 169 | 
         
             
            		}
         
     | 
| 170 | 
         | 
| 171 | 
         
            +
            		redirect(302, `${base}/settings`);
         
     | 
| 172 | 
         
             
            	},
         
     | 
| 173 | 
         | 
| 174 | 
         
             
            	unfeature: async ({ params, locals }) => {
         
     | 
    	
        src/routes/settings/(nav)/assistants/[assistantId]/+page.ts
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ export async function load({ parent, params }) { 
     | 
|
| 7 | 
         
             
            	const assistant = data.settings.assistants.find((id) => id === params.assistantId);
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            	if (!assistant) {
         
     | 
| 10 | 
         
            -
            		 
     | 
| 11 | 
         
             
            	}
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            	return data;
         
     | 
| 
         | 
|
| 7 | 
         
             
            	const assistant = data.settings.assistants.find((id) => id === params.assistantId);
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            	if (!assistant) {
         
     | 
| 10 | 
         
            +
            		redirect(302, `${base}/assistant/${params.assistantId}`);
         
     | 
| 11 | 
         
             
            	}
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            	return data;
         
     | 
    	
        src/routes/settings/(nav)/assistants/[assistantId]/avatar.jpg/+server.ts
    CHANGED
    
    | 
         @@ -8,18 +8,18 @@ export const GET: RequestHandler = async ({ params }) => { 
     | 
|
| 8 | 
         
             
            	});
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            	if (!assistant) {
         
     | 
| 11 | 
         
            -
            		 
     | 
| 12 | 
         
             
            	}
         
     | 
| 13 | 
         | 
| 14 | 
         
             
            	if (!assistant.avatar) {
         
     | 
| 15 | 
         
            -
            		 
     | 
| 16 | 
         
             
            	}
         
     | 
| 17 | 
         | 
| 18 | 
         
             
            	const fileId = collections.bucket.find({ filename: assistant._id.toString() });
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const content = await fileId.next().then(async (file) => {
         
     | 
| 21 | 
         
             
            		if (!file?._id) {
         
     | 
| 22 | 
         
            -
            			 
     | 
| 23 | 
         
             
            		}
         
     | 
| 24 | 
         | 
| 25 | 
         
             
            		const fileStream = collections.bucket.openDownloadStream(file?._id);
         
     | 
| 
         | 
|
| 8 | 
         
             
            	});
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            	if (!assistant) {
         
     | 
| 11 | 
         
            +
            		error(404, "No assistant found");
         
     | 
| 12 | 
         
             
            	}
         
     | 
| 13 | 
         | 
| 14 | 
         
             
            	if (!assistant.avatar) {
         
     | 
| 15 | 
         
            +
            		error(404, "No avatar found");
         
     | 
| 16 | 
         
             
            	}
         
     | 
| 17 | 
         | 
| 18 | 
         
             
            	const fileId = collections.bucket.find({ filename: assistant._id.toString() });
         
     | 
| 19 | 
         | 
| 20 | 
         
             
            	const content = await fileId.next().then(async (file) => {
         
     | 
| 21 | 
         
             
            		if (!file?._id) {
         
     | 
| 22 | 
         
            +
            			error(404, "Avatar not found");
         
     | 
| 23 | 
         
             
            		}
         
     | 
| 24 | 
         | 
| 25 | 
         
             
            		const fileStream = collections.bucket.openDownloadStream(file?._id);
         
     | 
    	
        src/routes/settings/(nav)/assistants/[assistantId]/edit/+page.server.ts
    CHANGED
    
    | 
         @@ -168,7 +168,7 @@ export const actions: Actions = { 
     | 
|
| 168 | 
         
             
            		);
         
     | 
| 169 | 
         | 
| 170 | 
         
             
            		if (acknowledged) {
         
     | 
| 171 | 
         
            -
            			 
     | 
| 172 | 
         
             
            		} else {
         
     | 
| 173 | 
         
             
            			throw Error("Update failed");
         
     | 
| 174 | 
         
             
            		}
         
     | 
| 
         | 
|
| 168 | 
         
             
            		);
         
     | 
| 169 | 
         | 
| 170 | 
         
             
            		if (acknowledged) {
         
     | 
| 171 | 
         
            +
            			redirect(302, `${base}/settings/assistants/${assistant._id}`);
         
     | 
| 172 | 
         
             
            		} else {
         
     | 
| 173 | 
         
             
            			throw Error("Update failed");
         
     | 
| 174 | 
         
             
            		}
         
     | 
    	
        src/routes/settings/(nav)/assistants/new/+page.server.ts
    CHANGED
    
    | 
         @@ -154,6 +154,6 @@ export const actions: Actions = { 
     | 
|
| 154 | 
         
             
            			$addToSet: { assistants: insertedId },
         
     | 
| 155 | 
         
             
            		});
         
     | 
| 156 | 
         | 
| 157 | 
         
            -
            		 
     | 
| 158 | 
         
             
            	},
         
     | 
| 159 | 
         
             
            };
         
     | 
| 
         | 
|
| 154 | 
         
             
            			$addToSet: { assistants: insertedId },
         
     | 
| 155 | 
         
             
            		});
         
     | 
| 156 | 
         | 
| 157 | 
         
            +
            		redirect(302, `${base}/settings/assistants/${insertedId}`);
         
     | 
| 158 | 
         
             
            	},
         
     | 
| 159 | 
         
             
            };
         
     | 
    	
        svelte.config.js
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 1 | 
         
             
            import adapter from "@sveltejs/adapter-node";
         
     | 
| 2 | 
         
            -
            import { vitePreprocess } from "@sveltejs/ 
     | 
| 3 | 
         
             
            import dotenv from "dotenv";
         
     | 
| 4 | 
         | 
| 5 | 
         
             
            dotenv.config({ path: "./.env.local" });
         
     | 
| 
         | 
|
| 1 | 
         
             
            import adapter from "@sveltejs/adapter-node";
         
     | 
| 2 | 
         
            +
            import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
         
     | 
| 3 | 
         
             
            import dotenv from "dotenv";
         
     | 
| 4 | 
         | 
| 5 | 
         
             
            dotenv.config({ path: "./.env.local" });
         
     |