fix: 修复参数传递bug
This commit is contained in:
parent
feabfc8537
commit
29fe4b6e6f
|
|
@ -40,10 +40,6 @@ const navItems = [
|
||||||
path: '/tools',
|
path: '/tools',
|
||||||
icon: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path></svg>`
|
icon: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path></svg>`
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/agents',
|
|
||||||
icon: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"></path><path d="M8.5 8.5v.01"></path><path d="M16 15.5v.01"></path><path d="M12 12v.01"></path><path d="M11 17v.01"></path><path d="M7 14v.01"></path></svg>`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
icon: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`
|
icon: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
<template>
|
||||||
|
<div class="inline-form">
|
||||||
|
<div class="form-header">
|
||||||
|
<h3>{{ title }}</h3>
|
||||||
|
<button class="btn-close" @click="$emit('close')">×</button>
|
||||||
|
</div>
|
||||||
|
<form @submit.prevent="$emit('submit')">
|
||||||
|
<slot></slot>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="button" class="btn-secondary" @click="$emit('close')">取消</button>
|
||||||
|
<button type="submit" class="btn-primary">{{ submitText }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
title: { type: String, required: true },
|
||||||
|
submitText: { type: String, default: '保存' },
|
||||||
|
})
|
||||||
|
|
||||||
|
defineEmits(['submit', 'close'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.inline-form {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
border-bottom: 1px solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-close {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-close:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group textarea,
|
||||||
|
.form-group select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid var(--border-input);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--bg-input);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary,
|
||||||
|
.btn-primary {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--accent-primary);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: var(--accent-primary-hover);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
<template>
|
||||||
|
<div class="list-item" :class="{ active, 'in-room': inRoom }" @click="$emit('click')">
|
||||||
|
<!-- 左侧图标/头像 -->
|
||||||
|
<div v-if="avatar" class="item-avatar" :style="avatarStyle">
|
||||||
|
{{ avatar }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="icon" class="item-icon">
|
||||||
|
{{ icon }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 信息 -->
|
||||||
|
<div class="item-info">
|
||||||
|
<span class="item-name">{{ title }}</span>
|
||||||
|
<span v-if="subtitle" class="item-subtitle">{{ subtitle }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="item-actions">
|
||||||
|
<slot name="actions">
|
||||||
|
<button v-if="onEdit" @click.stop="$emit('edit')" class="btn-icon" title="编辑">
|
||||||
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
|
||||||
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button v-if="onDelete" @click.stop="$emit('delete')" class="btn-icon btn-delete-icon" title="删除">
|
||||||
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<polyline points="3 6 5 6 21 6"></polyline>
|
||||||
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: { type: String, required: true },
|
||||||
|
subtitle: { type: String, default: '' },
|
||||||
|
icon: { type: String, default: '' },
|
||||||
|
avatar: { type: String, default: '' },
|
||||||
|
avatarColor: { type: String, default: '#667eea' },
|
||||||
|
active: { type: Boolean, default: false },
|
||||||
|
inRoom: { type: Boolean, default: false },
|
||||||
|
onEdit: { type: Boolean, default: true },
|
||||||
|
onDelete: { type: Boolean, default: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
defineEmits(['click', 'edit', 'delete'])
|
||||||
|
|
||||||
|
const avatarStyle = computed(() => ({
|
||||||
|
background: `linear-gradient(135deg, ${props.avatarColor}, #764ba2)`
|
||||||
|
}))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.85rem 1rem;
|
||||||
|
border-bottom: 1px solid var(--border-light);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item.active {
|
||||||
|
background: var(--accent-primary-light);
|
||||||
|
border-left: 3px solid var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item.in-room {
|
||||||
|
background: var(--accent-primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-subtitle {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item:hover .item-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: all 0.15s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon svg {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-delete-icon {
|
||||||
|
color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-delete-icon:hover {
|
||||||
|
background: var(--danger-bg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
<template>
|
||||||
|
<div class="message-bubble" :class="message.sender_type">
|
||||||
|
<div class="message-avatar">
|
||||||
|
{{ message.sender_name?.charAt(0).toUpperCase() }}
|
||||||
|
</div>
|
||||||
|
<div class="message-container">
|
||||||
|
<div class="message-body">
|
||||||
|
<ProcessBlock
|
||||||
|
v-if="message.process_steps && message.process_steps.length > 0"
|
||||||
|
:process-steps="message.process_steps"
|
||||||
|
/>
|
||||||
|
<div v-else class="md-content message-text" v-html="renderedContent"></div>
|
||||||
|
</div>
|
||||||
|
<div class="message-footer">
|
||||||
|
<span class="sender-name">{{ message.sender_name }}</span>
|
||||||
|
<span class="message-time">{{ formatTime(message.created_at) }}</span>
|
||||||
|
<button class="ghost-btn accent" @click="copyContent" title="复制">
|
||||||
|
<span v-html="copyIcon"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { renderMarkdown } from '@/utils/markdown.js'
|
||||||
|
import ProcessBlock from './ProcessBlock.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
message: { type: Object, required: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
const renderedContent = computed(() => {
|
||||||
|
const text = props.message.content || props.message.text || ''
|
||||||
|
if (!text) return ''
|
||||||
|
return renderMarkdown(text)
|
||||||
|
})
|
||||||
|
|
||||||
|
function formatTime(time) {
|
||||||
|
if (!time) return ''
|
||||||
|
return new Date(time).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyContent() {
|
||||||
|
let text = props.message.content || props.message.text || ''
|
||||||
|
if (props.message.process_steps && props.message.process_steps.length > 0) {
|
||||||
|
const parts = props.message.process_steps
|
||||||
|
.filter(s => s && s.type === 'text')
|
||||||
|
.map(s => s.content)
|
||||||
|
if (parts.length > 0) text = parts.join('\n\n')
|
||||||
|
}
|
||||||
|
navigator.clipboard.writeText(text).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyIcon = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.message-bubble {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-bubble.user {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-bubble.user .message-avatar {
|
||||||
|
background: linear-gradient(135deg, #11998e, #38ef7d);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container {
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-bubble.user .message-text {
|
||||||
|
background: var(--accent-primary);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-bubble.user .message-footer {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sender-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
transition: all 0.15s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-btn:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -123,27 +123,48 @@ async def websocket_handler(websocket: WebSocket, room_id: str):
|
||||||
})
|
})
|
||||||
|
|
||||||
context = {"user_id": user_id, "username": user_name}
|
context = {"user_id": user_id, "username": user_name}
|
||||||
|
logger.info(f"[ROOM_WS] Starting process_message, agents count: {len(agents)}")
|
||||||
|
|
||||||
|
event_count = 0
|
||||||
async for event in chat_room_service.process_message(
|
async for event in chat_room_service.process_message(
|
||||||
room_id=room_id, user_message=content, user_id=user_id,
|
room_id=room_id, user_message=content, user_id=user_id,
|
||||||
user_name=user_name, context=context
|
user_name=user_name, context=context
|
||||||
):
|
):
|
||||||
|
event_count += 1
|
||||||
|
logger.info(f"[ROOM_WS] Received event {event_count}: {event.get('event')}")
|
||||||
|
|
||||||
if event.get("event") in ["process_step", "done", "error"]:
|
if event.get("event") in ["process_step", "done", "error"]:
|
||||||
|
# Find agent_name from agents list
|
||||||
|
agent_name = None
|
||||||
|
for agent in agents:
|
||||||
|
if agent.agent_id == event.get("agent_id"):
|
||||||
|
agent_name = agent.name
|
||||||
|
break
|
||||||
await connection_manager.broadcast_to_room(room_id, {
|
await connection_manager.broadcast_to_room(room_id, {
|
||||||
"event": event.get("event"),
|
"event": event.get("event"),
|
||||||
"data": event.get("data", {}),
|
"data": event.get("data", {}),
|
||||||
"agent_id": event.get("agent_id"),
|
"agent_id": event.get("agent_id"),
|
||||||
"agent_name": event.get("agent_name")
|
"agent_name": agent_name
|
||||||
})
|
})
|
||||||
|
|
||||||
if event.get("event") == "done":
|
if event.get("event") == "done":
|
||||||
|
# Find agent_name from agents list
|
||||||
|
agent_name = None
|
||||||
|
for agent in agents:
|
||||||
|
if agent.agent_id == event.get("agent_id"):
|
||||||
|
agent_name = agent.name
|
||||||
|
break
|
||||||
chat_room_service.save_message(
|
chat_room_service.save_message(
|
||||||
room_id=room_id, sender_type="agent",
|
room_id=room_id, sender_type="agent",
|
||||||
sender_id=event.get("agent_id"),
|
sender_id=event.get("agent_id"),
|
||||||
sender_name=event.get("agent_name"),
|
sender_name=agent_name,
|
||||||
content=event.get("content", ""),
|
content=event.get("data", {}).get("content", "") if isinstance(event.get("data"), dict) else "",
|
||||||
token_count=event.get("token_count", 0)
|
token_count=event.get("data", {}).get("token_count", 0) if isinstance(event.get("data"), dict) else 0
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
logger.info(f"[ROOM_WS] Skipping event: {event.get('event')}")
|
||||||
|
|
||||||
|
logger.info(f"[ROOM_WS] process_message completed, total events: {event_count}")
|
||||||
|
|
||||||
for agent in agents:
|
for agent in agents:
|
||||||
await connection_manager.broadcast_to_room(room_id, {
|
await connection_manager.broadcast_to_room(room_id, {
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,7 @@ class StreamService:
|
||||||
|
|
||||||
yield _sse_event("done", {
|
yield _sse_event("done", {
|
||||||
"message_id": msg_id,
|
"message_id": msg_id,
|
||||||
|
"content": ctx.full_content,
|
||||||
"token_count": actual_token_count,
|
"token_count": actual_token_count,
|
||||||
"usage": total_usage
|
"usage": total_usage
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue