Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 14 additions & 3 deletions frontend/src/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface ChatMessage {
export interface SendMessageRequest {
session_id: string
content: string
team_id?: string | null
team_name?: string | null
}

export interface ChatHistoryResponse {
Expand Down Expand Up @@ -85,15 +87,21 @@ export interface ErrorEvent {

export interface DebugEvent {
type: 'debug'
debug_type: 'classification' | 'routing' | 'agent_start' | 'agent_end' | 'tool_result' | 'handoff' | 'data_sharing' | 'discussion_argument' | 'decision_summary' | 'preview_signal' | 'arena_error'
debug_type: 'classification' | 'routing' | 'agent_start' | 'agent_end' | 'tool_result' | 'handoff' | 'data_sharing' | 'discussion_argument' | 'decision_summary' | 'preview_signal' | 'arena_error' | 'decision_trace'
agent: string
timestamp: number
data: {
// classification
// classification / decision_trace
intent?: string
selected_agent?: string
selected_team?: string
rationale?: string
available_agents?: string[]
stage?: 'orchestrator' | 'team_agent' | 'team_summary' | 'agent'
title?: string
role?: string
key_points?: string[]
direction?: 'bullish' | 'bearish' | 'neutral'
// routing
from_agent?: string
to_agent?: string
Expand Down Expand Up @@ -189,6 +197,7 @@ export const chatApi = {
async streamMessagePost(
sessionId: string,
content: string,
team: { team_id?: string | null; team_name?: string | null } | null,
onEvent: (event: StreamEvent) => void,
onError?: (error: Error) => void,
abortController?: AbortController
Expand All @@ -211,7 +220,9 @@ export const chatApi = {
headers,
body: JSON.stringify({
session_id: sessionId,
content: content
content: content,
...(team?.team_id ? { team_id: team.team_id } : {}),
...(team?.team_name ? { team_name: team.team_name } : {})
}),
signal: controller.signal
})
Expand Down
37 changes: 36 additions & 1 deletion frontend/src/stores/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ export const useChatStore = defineStore('chat', () => {
} | null>(null)
const decisionSidebarOpen = ref(false)

// Selected Agent team for Chat requests
const activeTeamId = ref<string | null>(null)
const activeTeamName = ref<string | null>(null)

// Preview signal state (instant rule-based, before full LLM synthesis)
const previewSignal = ref<{
signal: 'BUY' | 'SELL' | 'HOLD'
Expand Down Expand Up @@ -492,7 +496,7 @@ export const useChatStore = defineStore('chat', () => {
role = 'handoff'
} else if (debugType === 'data_sharing') {
role = 'system'
} else if (debugType === 'discussion_argument' || debugType === 'decision_summary' || debugType === 'preview_signal' || debugType === 'arena_error') {
} else if (debugType === 'discussion_argument' || debugType === 'decision_summary' || debugType === 'preview_signal' || debugType === 'arena_error' || debugType === 'decision_trace') {
role = 'discussion'
}

Expand Down Expand Up @@ -541,6 +545,20 @@ export const useChatStore = defineStore('chat', () => {
console.log('[Chat] Preview signal received:', previewSignal.value)
}

// Special handling for decision_trace team_summary: update decision state
if (debugType === 'decision_trace' && data.stage === 'team_summary' && data.signal) {
previewSignal.value = null
decisionSummary.value = {
signal: data.signal as 'BUY' | 'SELL' | 'HOLD' | 'NONE',
confidence: data.confidence || 0,
bull_count: data.bull_count || 0,
bear_count: data.bear_count || 0,
neutral_count: data.neutral_count || 0,
suggested_action: data.suggested_action || '',
}
decisionSidebarOpen.value = true
}

// Special handling for decision_summary: update decision state (upgrades preview)
if (debugType === 'decision_summary' && data.signal) {
// Clear preview signal — the full summary replaces it
Expand Down Expand Up @@ -586,6 +604,16 @@ export const useChatStore = defineStore('chat', () => {
}
}

const setActiveTeam = (team: { id?: string; name?: string } | null) => {
activeTeamId.value = team?.id || null
activeTeamName.value = team?.name || null
}

const clearActiveTeam = () => {
activeTeamId.value = null
activeTeamName.value = null
}

const sendMessage = async (content: string) => {
if (!sessionId.value) {
await initSession()
Expand Down Expand Up @@ -629,6 +657,9 @@ export const useChatStore = defineStore('chat', () => {
await chatApi.streamMessagePost(
sendingSessionId,
content,
activeTeamId.value || activeTeamName.value
? { team_id: activeTeamId.value, team_name: activeTeamName.value }
: null,
(event: StreamEvent) => {
// SESSION GUARD: If user switched sessions, discard stale events
if (sessionId.value !== sendingSessionId) {
Expand Down Expand Up @@ -899,6 +930,8 @@ export const useChatStore = defineStore('chat', () => {
decisionSummary,
decisionSidebarOpen,
previewSignal,
activeTeamId,
activeTeamName,
lastSessionRef,
// Actions
initSession,
Expand All @@ -909,6 +942,8 @@ export const useChatStore = defineStore('chat', () => {
updateSessionTitle,
newConversation,
clearCurrentConversation,
setActiveTeam,
clearActiveTeam,
sendMessage,
loadHistory,
clearMessages,
Expand Down
32 changes: 23 additions & 9 deletions frontend/src/views/chat/ChatView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ const loadTeams = async () => {
}

const handleTeamChat = (team: any) => {
// Send team name as message to trigger multi-agent collaboration
const msg = `请使用"${team.name}"团队模式来协作处理我的下一个问题`
chatStore.setActiveTeam(team)
chatStore.decisionSidebarOpen = true
showTeamPanel.value = false
handleSend(msg)
MessagePlugin.success(`已启用 ${team.name} 团队模式`)
}
const showSessionsSidebar = ref(false)
const editingSessionId = ref('')
Expand Down Expand Up @@ -267,7 +267,7 @@ onMounted(async () => {
MessagePlugin.error('加载历史对话失败,请重新登录后重试')
}

// 加载Agent Teams
// 加载投研团队
loadTeams()
})

Expand Down Expand Up @@ -569,14 +569,21 @@ const syncUrlToSession = () => {
@click="showTeamPanel = !showTeamPanel"
>
<template #icon><t-icon name="usergroup" /></template>
Agent Teams
投研团队
</t-button>
</div>

<!-- Agent Teams Panel -->
<div v-if="chatStore.activeTeamName" class="active-team-bar">
<t-tag theme="primary" variant="light">
当前团队:{{ chatStore.activeTeamName }}
</t-tag>
<t-button size="small" variant="text" @click="chatStore.clearActiveTeam()">退出团队模式</t-button>
</div>

<!-- Research Teams Panel -->
<div v-if="showTeamPanel" class="workflow-panel">
<div class="workflow-panel-header">
<span>Agent 团队</span>
<span>投研团队</span>
<t-button size="small" variant="text" @click="router.push('/orchestration')">管理团队</t-button>
</div>
<div class="workflow-list">
Expand All @@ -589,11 +596,11 @@ const syncUrlToSession = () => {
<t-icon name="usergroup" />
<div class="workflow-info">
<span class="workflow-name">{{ team.name }}</span>
<span class="workflow-desc">{{ team.description || '多Agent协作' }}</span>
<span class="workflow-desc">{{ team.description || '投研角色协作' }}</span>
</div>
</div>
<div v-if="agentTeams.length === 0" class="workflow-item" style="color:#bbb;justify-content:center">
暂无团队,去Agent中心创建
暂无团队,去 AI Agent 投研创建
</div>
</div>
</div>
Expand Down Expand Up @@ -832,6 +839,13 @@ const syncUrlToSession = () => {
opacity: 0.8;
}

.active-team-bar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}

/* Workflow Panel */
.workflow-panel {
background: var(--td-bg-color-secondarycontainer, #f5f5f5);
Expand Down
Loading
Loading