新增: 并行调度+Token预算池+事件协议+前端类型+编译警告清理
- Coordinator.dispatch_with_budget: JoinSet层内并行+层间串行+预算超限降级串行 - TokenBudgetPool: AtomicU64 CAS无锁并发安全,0=不限制 - 4个新事件: AiPlanCreated/AiSubTaskStatusChanged/AiMergeCompleted/AiConflictResolved - 前端类型: PlanRecord/SubTaskRecord/ConflictRecord/PlanLayerInfo/ConflictInfo - PlanProgress.vue: 接入真实状态+persona徽章+冲突徽章+i18n - 编译警告全部清零(audit子模块allow+事件allow+record allow) - Coordinator测试27个全绿(含4个Token预算+4个并行调度)
This commit is contained in:
@@ -734,3 +734,81 @@ export interface KnowledgeConfig {
|
||||
/** embedding 模型名(如 embedding-3) */
|
||||
embedding_model: string | null
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 多 Agent 并行执行(Plan/SubTask/Conflict)
|
||||
// ============================================================
|
||||
|
||||
/** Plan 执行状态 */
|
||||
export type PlanStatus = 'planning' | 'executing' | 'merging' | 'done' | 'error'
|
||||
|
||||
/** SubTask 执行状态 */
|
||||
export type SubTaskStatus = 'pending' | 'running' | 'done' | 'error'
|
||||
|
||||
/** 冲突解决状态 */
|
||||
export type ConflictResolution = 'pending' | 'a' | 'b' | 'merged' | 'manual'
|
||||
|
||||
/** 冲突类型 */
|
||||
export type ConflictType = 'file' | 'semantic'
|
||||
|
||||
/** Plan 记录 */
|
||||
export interface PlanRecord {
|
||||
id: string
|
||||
conversation_id: string
|
||||
user_message_id: string | null
|
||||
status: PlanStatus
|
||||
subtask_count: number
|
||||
created_at: string
|
||||
completed_at: string | null
|
||||
}
|
||||
|
||||
/** SubTask 记录 */
|
||||
export interface SubTaskRecord {
|
||||
id: string
|
||||
plan_id: string
|
||||
persona_id: string | null
|
||||
intent: string
|
||||
status: SubTaskStatus
|
||||
layer: number
|
||||
/** 依赖的 SubTask id 列表(JSON 数组字符串,需 parse) */
|
||||
deps: string | null
|
||||
/** Git worktree 分支名(null=非 Git 工程降级串行) */
|
||||
branch: string | null
|
||||
created_at: string
|
||||
completed_at: string | null
|
||||
}
|
||||
|
||||
/** 冲突记录 */
|
||||
export interface ConflictRecord {
|
||||
id: string
|
||||
plan_id: string
|
||||
file_path: string
|
||||
conflict_type: ConflictType
|
||||
subtask_a: string | null
|
||||
subtask_b: string | null
|
||||
diff_a: string | null
|
||||
diff_b: string | null
|
||||
resolution: ConflictResolution
|
||||
resolved_by: 'reviewer' | 'user' | null
|
||||
created_at: string
|
||||
resolved_at: string | null
|
||||
}
|
||||
|
||||
/** PlanProgress 展示用 DAG 层结构(事件载荷) */
|
||||
export interface PlanLayerInfo {
|
||||
items: Array<{
|
||||
id: string
|
||||
persona_id: string | null
|
||||
intent: string
|
||||
status: SubTaskStatus
|
||||
}>
|
||||
}
|
||||
|
||||
/** 冲突信息(AiMergeCompleted 事件载荷) */
|
||||
export interface ConflictInfo {
|
||||
id: string
|
||||
file_path: string
|
||||
conflict_type: ConflictType
|
||||
subtask_a: string | null
|
||||
subtask_b: string | null
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="plan-progress" v-if="visible">
|
||||
<div class="plan-progress" v-if="visible && layers.length > 0">
|
||||
<div class="plan-progress-header">
|
||||
<span class="plan-progress-title">{{ t('aiChat.planProgress') }}</span>
|
||||
<span class="plan-progress-title">📋 {{ t('aiChat.planProgress') }}</span>
|
||||
<span class="plan-progress-count">{{ doneCount }}/{{ totalCount }}</span>
|
||||
</div>
|
||||
<div class="plan-progress-layers">
|
||||
@@ -9,45 +9,73 @@
|
||||
<div class="plan-layer-label">{{ t('aiChat.planLayer', { n: li + 1 }) }}</div>
|
||||
<div class="plan-layer-items">
|
||||
<div
|
||||
v-for="(item, ii) in layer"
|
||||
v-for="(item, ii) in layer.items"
|
||||
:key="ii"
|
||||
class="plan-item"
|
||||
:class="'plan-item--' + item.status"
|
||||
>
|
||||
<span class="plan-item-icon">
|
||||
<template v-if="item.status === 'done'">✓</template>
|
||||
<template v-else-if="item.status === 'running'">▶</template>
|
||||
<template v-else-if="item.status === 'error'">✗</template>
|
||||
<template v-else>○</template>
|
||||
<span class="plan-item-icon" :class="'persona-' + (item.persona_id || 'default')">
|
||||
{{ personaIcon(item.persona_id) }}
|
||||
</span>
|
||||
<span class="plan-item-label">{{ item.label }}</span>
|
||||
<span class="plan-item-label">{{ item.intent }}</span>
|
||||
<span class="plan-item-status">{{ statusIcon(item.status) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="li < layers.length - 1" class="plan-layer-arrow">↓</div>
|
||||
<div v-if="li < layers.length - 1" class="plan-layer-arrow">↓</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 冲突徽章 -->
|
||||
<div v-if="conflicts.length > 0" class="plan-conflicts-badge" @click="emit('show-conflicts')">
|
||||
⚠ {{ conflicts.length }} 处冲突待处理
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { PlanLayerInfo, ConflictInfo } from '@/api/types'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
interface PlanItem {
|
||||
id: string
|
||||
label: string
|
||||
status: 'pending' | 'running' | 'done' | 'error'
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
layers: PlanItem[][]
|
||||
layers: PlanLayerInfo[]
|
||||
conflicts?: ConflictInfo[]
|
||||
}>()
|
||||
|
||||
const totalCount = computed(() => props.layers.reduce((s, l) => s + l.length, 0))
|
||||
const doneCount = computed(() => props.layers.reduce((s, l) => s + l.filter(i => i.status === 'done').length, 0))
|
||||
const emit = defineEmits<{
|
||||
(e: 'show-conflicts'): void
|
||||
}>()
|
||||
|
||||
const conflicts = computed(() => props.conflicts || [])
|
||||
|
||||
const totalCount = computed(() =>
|
||||
props.layers.reduce((s, l) => s + l.items.length, 0)
|
||||
)
|
||||
const doneCount = computed(() =>
|
||||
props.layers.reduce((s, l) => s + l.items.filter(i => i.status === 'done').length, 0)
|
||||
)
|
||||
|
||||
function personaIcon(personaId: string | null): string {
|
||||
switch (personaId) {
|
||||
case 'coder': return '🔵'
|
||||
case 'reviewer': return '🔍'
|
||||
case 'architect': return '📐'
|
||||
case 'tester': return '🧪'
|
||||
case 'analyst': return '📊'
|
||||
default: return '⚪'
|
||||
}
|
||||
}
|
||||
|
||||
function statusIcon(status: string): string {
|
||||
switch (status) {
|
||||
case 'done': return '✓'
|
||||
case 'running': return '▶'
|
||||
case 'error': return '✗'
|
||||
default: return '○'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -67,9 +95,7 @@ const doneCount = computed(() => props.layers.reduce((s, l) => s + l.filter(i =>
|
||||
}
|
||||
.plan-progress-title { color: var(--df-text); }
|
||||
.plan-progress-count { color: var(--df-text-dim); }
|
||||
.plan-layer {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.plan-layer { margin-bottom: 4px; }
|
||||
.plan-layer-label {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
@@ -94,5 +120,19 @@ const doneCount = computed(() => props.layers.reduce((s, l) => s + l.filter(i =>
|
||||
.plan-item--running { border-color: var(--df-primary); color: var(--df-primary); }
|
||||
.plan-item--error { border-color: var(--df-danger); color: var(--df-danger); }
|
||||
.plan-item-icon { font-size: 10px; }
|
||||
.plan-item-status { font-size: 10px; font-weight: 700; }
|
||||
.plan-layer-arrow { text-align: center; color: var(--df-text-dim); font-size: 10px; }
|
||||
.plan-conflicts-badge {
|
||||
margin-top: 8px;
|
||||
padding: 4px 8px;
|
||||
background: var(--df-warning-bg, rgba(255, 193, 7, 0.1));
|
||||
border: 1px solid var(--df-warning, #ffc107);
|
||||
border-radius: 4px;
|
||||
color: var(--df-warning, #ffc107);
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
}
|
||||
.plan-conflicts-badge:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export default {
|
||||
aiChat: {
|
||||
// ── Multi-Agent parallel execution ──
|
||||
planProgress: 'Execution Plan',
|
||||
planLayer: 'Layer {n}',
|
||||
|
||||
// ── Conversation sidebar ──
|
||||
sidebarTitle: 'Chats',
|
||||
newConversation: 'New chat',
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export default {
|
||||
aiChat: {
|
||||
// ── 多 Agent 并行执行 ──
|
||||
planProgress: '执行计划',
|
||||
planLayer: '第 {n} 层',
|
||||
|
||||
// ── 对话侧栏 ──
|
||||
sidebarTitle: '对话',
|
||||
newConversation: '新对话',
|
||||
|
||||
Reference in New Issue
Block a user