Add streaming support and refactor Chat UI

- Add run_stream method to AgentCore for streaming output
- Add base_url parameter to LLM clients for OpenRouter support
- Add xbot module for new agent implementation
- Refactor Chat.vue into composable + components (ChatHeader, ChatMessage, ChatInput, ChatSidebar, ChatAgentSelector)
- Add ChatStream handler for SSE streaming in Go server
- Add UseXBot field to chat request

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 10:49:44 +08:00
parent 8062144001
commit 5c435ab21e
31 changed files with 2762 additions and 760 deletions

View File

@@ -0,0 +1,72 @@
<script setup lang="ts">
const props = defineProps<{
modelValue: string
loading: boolean
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
(e: 'send'): void
}>()
const handleKeydown = (e: KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
emit('send')
}
}
const autoResize = (e: Event) => {
const target = e.target as HTMLTextAreaElement
target.style.height = 'auto'
target.style.height = Math.min(target.scrollHeight, 160) + 'px'
}
</script>
<template>
<div class="p-5 border-t border-white/[0.06] bg-[#0c0c0f]/60 backdrop-blur-xl">
<div class="max-w-3xl mx-auto">
<div class="relative bg-[#12121a] rounded-2xl border border-white/[0.08] focus-within:border-orange-500/40 focus-within:shadow-[0_0_30px_rgba(249,115,22,0.08)] transition-all duration-300">
<!-- 附件按钮 -->
<button class="absolute left-4 top-1/2 -translate-y-1/2 text-white/25 hover:text-orange-400 transition-colors p-1">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"></path>
</svg>
</button>
<!-- 输入框 -->
<textarea
:value="modelValue"
@input="emit('update:modelValue', ($event.target as HTMLTextAreaElement).value); autoResize($event)"
@keydown="handleKeydown"
placeholder="发送消息..."
rows="1"
class="w-full bg-transparent text-white placeholder-white/25 py-4 pl-12 pr-28 resize-none focus:outline-none text-[15px]"
></textarea>
<!-- 发送按钮 -->
<button
@click="emit('send')"
:disabled="!modelValue.trim() || loading"
class="absolute right-2 top-1/2 -translate-y-1/2 w-9 h-9 rounded-lg flex items-center justify-center transition-all duration-200 disabled:opacity-30 disabled:cursor-not-allowed"
:class="modelValue.trim() && !loading
? 'bg-orange-500 hover:bg-orange-400 shadow-lg shadow-orange-500/30 active:scale-90'
: 'bg-white/10'"
>
<svg v-if="!loading" class="w-4 h-4 text-white" viewBox="0 0 24 24" fill="currentColor">
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
</svg>
<svg v-else class="w-4 h-4 text-white animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</button>
</div>
<!-- 提示 -->
<div class="text-center mt-3">
<span class="text-[10px] text-white/20 tracking-wide">AI 可能会产生错误信息请核实重要内容</span>
</div>
</div>
</div>
</template>