You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

100 lines
2.4 KiB

<script setup lang="ts">
import type { AgentMessage } from "~/composables/useAgentChat";
const props = defineProps<{
messages: AgentMessage[];
isLoading: boolean;
loggedIn: boolean;
}>();
const emit = defineEmits<{
approve: [toolCallId: string, approved: boolean];
feedback: [messageId: string, feedback: "like" | "dislike"];
edit: [messageId: string, content: string];
regenerate: [];
}>();
const scrollContainer = ref<HTMLElement | null>(null);
const isAtBottom = ref(true);
const isStreaming = ref(false);
function scrollToBottom() {
if (scrollContainer.value) {
scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight;
}
}
function handleScroll() {
if (!scrollContainer.value) return;
const { scrollTop, scrollHeight, clientHeight } = scrollContainer.value;
isAtBottom.value = scrollHeight - scrollTop - clientHeight < 60;
}
watch(
() => props.isLoading,
(loading) => {
isStreaming.value = loading;
if (loading) {
scrollContainer.value?.style.setProperty("scroll-behavior", "auto");
} else {
scrollContainer.value?.style.setProperty("scroll-behavior", "smooth");
nextTick(scrollToBottom);
}
},
);
watch(
() =>
props.messages
.map((m) =>
`${m.content}|${m.parts?.length ?? 0}|${m.parts
?.map((p) => `${p.type}|${p.text ?? ""}|${p.state ?? ""}|${p.result !== undefined ? "1" : "0"}`)
.join(",") ?? ""}`,
)
.join(";"),
() => {
if (isAtBottom.value) {
nextTick(scrollToBottom);
}
},
);
onMounted(() => {
scrollToBottom();
});
</script>
<template>
<div ref="scrollContainer" class="agent-message-list" @scroll="handleScroll">
<div class="message-list-inner">
<AgentMessageItem
v-for="(msg, idx) in messages"
:key="msg.id"
:message="msg"
:is-loading="isLoading"
:is-last="idx === messages.length - 1"
:logged-in="loggedIn"
@approve="(id, approved) => emit('approve', id, approved)"
@feedback="(id, fb) => emit('feedback', id, fb)"
@edit="(id, content) => emit('edit', id, content)"
@regenerate="emit('regenerate')"
/>
</div>
</div>
</template>
<style scoped>
.agent-message-list {
flex: 1;
overflow-y: auto;
}
.message-list-inner {
max-width: 800px;
margin: 0 auto;
padding: 24px 24px 48px;
display: flex;
flex-direction: column;
gap: 20px;
}
</style>