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
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>
|
|
|