Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c50b39f
Bump flowbite-svelte for VirtualLists
aryadhruv Nov 17, 2025
54dae3d
Refactor chat to use virtual list
aryadhruv Nov 17, 2025
42a849e
Formatting d'oh
aryadhruv Nov 17, 2025
2c951c1
Update Chat.svelte
aryadhruv Nov 17, 2025
83b0699
Merge branch 'main' into load-current-thread-from-backend-slg-45
aryadhruv Nov 17, 2025
8213e2a
Merge branch 'main' into load-current-thread-from-backend-slg-45
aryadhruv Nov 17, 2025
b563386
Refactor thread message conversion logic
aryadhruv Nov 18, 2025
5438c9c
Set final_answer_started when loading messages
aryadhruv Nov 18, 2025
3f99991
Revert flowbit package update
aryadhruv Nov 19, 2025
9a4afc4
Rollback changes -Virtual list
aryadhruv Nov 19, 2025
2cc7cbd
Load only list 100 messages
aryadhruv Nov 19, 2025
f7a1cb9
Update Chat.svelte
aryadhruv Nov 19, 2025
31f2897
Prevent's avalanche of message onMount
aryadhruv Nov 19, 2025
49fc83c
Formatting d'oh!
aryadhruv Nov 19, 2025
839b8a2
Fix Clipboard Button size
aryadhruv Nov 19, 2025
538a1fb
Update AIMessageActions.svelte
aryadhruv Nov 19, 2025
79652d4
Added datatype ThreadValues
aryadhruv Nov 19, 2025
5e9aedb
Update AIMessageActions.svelte
aryadhruv Nov 19, 2025
fc3bbf7
Moved chat page to /chat/[threadID]/+page.svelte
aryadhruv Nov 20, 2025
d366db9
Consume thread to load chats
aryadhruv Nov 20, 2025
f450a8c
Use ChatError
aryadhruv Nov 20, 2025
f19f797
Merge branch 'main' into introduce-per-thread-url-structure2-slg-71
aryadhruv Nov 21, 2025
64708d5
Add comment on lazily made threads
aryadhruv Nov 21, 2025
31cc936
Update client.ts
aryadhruv Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/frontend/src/lib/langgraph/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export async function getOrCreateThread(client: Client): Promise<Thread<ThreadVa
sortOrder: 'desc'
});

//We will update this to make threads lazily.
// In our current practice, it's not an urgent task.
if (existingThreads.length > 0) {
const existingThread = existingThreads[0];
console.info('Using existing thread', existingThread);
Expand Down
85 changes: 17 additions & 68 deletions apps/frontend/src/routes/chat/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,92 +1,41 @@
<script lang="ts">
import { error } from '@sveltejs/kit';
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { onMount } from 'svelte';
import Chat from '$lib/components/Chat.svelte';
import { createClient, getOrCreateThread } from '$lib/langgraph/client';
import ChatLoader from '$lib/components/ChatLoader.svelte';
import LoginModal from '$lib/components/LoginModal.svelte';
import { getOrCreateAssistant, createClient, getOrCreateThread } from '$lib/langgraph/client';
import * as m from '$lib/paraglide/messages.js';
import type { Client, Thread } from '@langchain/langgraph-sdk';
import type { ThreadValues } from '$lib/langgraph/types';
import ChatError from '$lib/components/ChatError.svelte';

let show_login_dialog = $state(false);

// Updates client whenever accessToken changes
let client = $derived(page.data.session ? createClient(page.data.session.accessToken) : null);
let assistantId = $state<string | null>(null);
let threadId = $state<string | null>(null);
let thread = $state<Thread<ThreadValues> | null>(null);
let initialization_error = $state<Error | null>(null);
let redirect_error = $state<Error | null>(null);

async function redirectToThread() {
if (!client) return;

async function initLangGraph(client: Client) {
try {
assistantId = await getOrCreateAssistant(client, 'chat');
thread = await getOrCreateThread(client);
threadId = thread.thread_id;
const thread = await getOrCreateThread(client);
await goto(`/chat/${thread.thread_id}`);
} catch (err) {
if (err instanceof Error) initialization_error = err;
error(500, {
message: 'Error during generation'
});
if (err instanceof Error) redirect_error = err;
console.error('Error creating or fetching thread:', err);
}
}

// Trigger redirect when client is ready
$effect(() => {
if ((assistantId === null || threadId === null) && client) initLangGraph(client);
if (client && !redirect_error) {
redirectToThread();
}
});

onMount(async () => {
$effect.pre(() => {
if (!page.data.session) show_login_dialog = true;
});

const suggestions = [
{
title: m.chat_suggestion_0_title(),
description: m.chat_suggestion_0_description(),
suggestedText: m.chat_suggestion_0_text()
},
{
title: m.chat_suggestion_1_title(),
description: m.chat_suggestion_1_description(),
suggestedText: m.chat_suggestion_1_text()
},
{
title: m.chat_suggestion_2_title(),
description: m.chat_suggestion_2_description(),
suggestedText: m.chat_suggestion_2_text()
},
{
title: m.chat_suggestion_3_title(),
description: m.chat_suggestion_3_description(),
suggestedText: m.chat_suggestion_3_text()
}
];

let greeting = $derived.by(() => {
const userName = page.data.session?.user?.name;

if (userName) {
return m.chat_greeting_hello({ name: userName });
} else {
return m.chat_greeting_anonymous();
}
});
</script>

{#if initialization_error}
<ChatError error={initialization_error} />
{:else if assistantId && thread && client}
<!-- We're all set up -->
<Chat
langGraphClient={client}
{assistantId}
{thread}
introTitle={greeting}
intro={m.chat_intro()}
{suggestions}
/>
{#if redirect_error}
<ChatError error={redirect_error} />
{:else}
<ChatLoader />
{/if}
Expand Down
97 changes: 97 additions & 0 deletions apps/frontend/src/routes/chat/[threadID]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script lang="ts">
import { error } from '@sveltejs/kit';
import { page } from '$app/state';
import { onMount } from 'svelte';
import type { Thread } from '@langchain/langgraph-sdk';
import Chat from '$lib/components/Chat.svelte';
import ChatLoader from '$lib/components/ChatLoader.svelte';
import LoginModal from '$lib/components/LoginModal.svelte';
import { getOrCreateAssistant, createClient } from '$lib/langgraph/client';
import * as m from '$lib/paraglide/messages.js';
import type { Client } from '@langchain/langgraph-sdk';
import type { ThreadValues } from '$lib/langgraph/types';
import ChatError from '$lib/components/ChatError.svelte';

let show_login_dialog = $state(false);

// Updates client whenever accessToken changes
let client = $derived(page.data.session ? createClient(page.data.session.accessToken) : null);
let assistantId = $state<string | null>(null);
let thread = $state<Thread<ThreadValues> | null>(null);
let threadId = $derived(page.params.threadID);
let initialization_error = $state<Error | null>(null);

async function initAssistantAndThread(client: Client, threadId: string) {
try {
assistantId = await getOrCreateAssistant(client, 'chat');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would always be getting and never creating. Perhaps good to split this up.

const fetchedThread = await client.threads.get(threadId);
thread = fetchedThread as Thread<ThreadValues>;
} catch (err) {
if (err instanceof Error) initialization_error = err;
error(500, {
message: 'Error during generation'
});
}
}

$effect(() => {
if ((assistantId === null || thread === null) && client && threadId) {
initAssistantAndThread(client, threadId);
}
});

onMount(async () => {
if (!page.data.session) show_login_dialog = true;
});

const suggestions = [
{
title: m.chat_suggestion_0_title(),
description: m.chat_suggestion_0_description(),
suggestedText: m.chat_suggestion_0_text()
},
{
title: m.chat_suggestion_1_title(),
description: m.chat_suggestion_1_description(),
suggestedText: m.chat_suggestion_1_text()
},
{
title: m.chat_suggestion_2_title(),
description: m.chat_suggestion_2_description(),
suggestedText: m.chat_suggestion_2_text()
},
{
title: m.chat_suggestion_3_title(),
description: m.chat_suggestion_3_description(),
suggestedText: m.chat_suggestion_3_text()
}
];

let greeting = $derived.by(() => {
const userName = page.data.session?.user?.name;

if (userName) {
return m.chat_greeting_hello({ name: userName });
} else {
return m.chat_greeting_anonymous();
}
});
</script>

{#if initialization_error}
<ChatError error={initialization_error} />
{:else if assistantId && thread && client}
<!-- We're all set up -->
<Chat
langGraphClient={client}
{assistantId}
{thread}
introTitle={greeting}
intro={m.chat_intro()}
{suggestions}
/>
{:else}
<ChatLoader />
{/if}

<LoginModal bind:open={show_login_dialog} />