新增: 执行中轨迹卡展开与占用期消息必达

- 执行中 step 卡支持点击展开(复用轨迹展开态, 实时过程工具卡回看)
- 占用期消息改落待发箱自动续投, 不再拒绝让用户重发(959)
- 待发项派发后完成结果回推来源飞书会话(35min 弃守)
- 961 轮次语义/960 聚合防抖设计要点登记
This commit is contained in:
lxy
2026-10-11 07:49:34 +08:00
parent 3dcb3c6fea
commit 461354d7f4
4 changed files with 126 additions and 11 deletions
+33 -5
View File
@@ -1032,7 +1032,7 @@ type RenderItem =
// A 过程压缩:完成轮次的执行轨迹卡(traceMsgs 为折叠在内的过程消息)与执行中的实时步骤摘要;
// round=轨迹序号(卡头「第 N 轮」,与执行中步骤行、轮次导航条同一计数来源)
| { kind: 'trace'; key: string; round: number; stats: TurnCallStats; startTs: number; endTs: number; tokens: number; traceMsgs: AiMessage[]; expanded: boolean }
| { kind: 'step'; key: string; round: number; stats: TurnCallStats }
| { kind: 'step'; key: string; round: number; stats: TurnCallStats; traceMsgs: AiMessage[]; expanded: boolean }
// UX 密度改造:相邻消息间隔 ≥30 分钟或跨天的居中时间分隔线(替代 per-block 相对时间)
| { kind: 'timesep'; key: string; ts: number }
// S1 子代理完成卡(AiAgentFinished 事件):非消息数据(per-conv 存 aiShared),逐卡一项
@@ -1121,7 +1121,12 @@ function genBucketItems(
pushSep(msgs[0].timestamp)
// 闪烁修复(2026-10-09):step 项 key 与下方完成态 trace 项对齐(同为 trace-{首条id}),
// 使「执行中 step → 完成态 trace」切换时 Vue 复用同一 DOM 节点(key 稳定),不销毁重建。
items.push({ kind: 'step', key: 'trace-' + prev[0].id, round, stats: collectTurnStats(msgs) })
// 961①: step 卡可展开——key 与完成态 trace 同构,复用 expandedTraceIds,
// 执行中展开看实时过程,完成后切换 trace 态展开不丢
items.push({
kind: 'step', key: 'trace-' + prev[0].id, round, stats: collectTurnStats(msgs),
traceMsgs: prev, expanded: expandedTraceIds.value.has('trace-' + prev[0].id),
})
} else {
pushSep(cur.timestamp)
}
@@ -1676,12 +1681,35 @@ defineExpose({
骨架与完成态 .ai-trace-card 完全同构(卡头结构一致),仅 chevron→脉冲点、右侧→「进行中」,
使 step→trace 切换时只 patch 内部文字,无高度跳变/闪烁 -->
<div v-else-if="item.kind === 'step'" class="ai-msg-slot ai-msg-slot--proc">
<div class="ai-trace-card ai-trace-card--running">
<div class="ai-trace-head">
<div class="ai-trace-card ai-trace-card--running" :class="{ 'ai-trace-card--open': item.expanded }">
<div
class="ai-trace-head"
role="button"
tabindex="0"
:aria-expanded="item.expanded"
@click="toggleTrace(item.key)"
@keydown.enter.prevent="toggleTrace(item.key)"
@keydown.space.prevent="toggleTrace(item.key)"
>
<span class="ai-trace-chevron" :class="{ 'is-open': item.expanded }">▸</span>
<span class="ai-step-dot"></span>
<span class="ai-trace-title">{{ $t('ai.trace.roundN', { n: item.round }) }}</span>
<span class="ai-trace-agg">{{ stepText(item.stats, item.round) }}</span>
<span class="ai-trace-toggle ai-trace-toggle--running">{{ $t('ai.trace.running') }}</span>
<span class="ai-trace-toggle">{{ item.expanded ? $t('ai.trace.collapse') : $t('ai.trace.running') }}</span>
</div>
<!-- 961① 执行中展开:实时过程回看(每条过程消息的工具卡),与完成态 trace 展开同诉求 -->
<div v-if="item.expanded" class="ai-trace-body">
<template v-for="m in item.traceMsgs" :key="m.id">
<div v-if="m.toolCalls && m.toolCalls.length > 0" class="ai-trace-round">
<ToolCardList
:toolCalls="m.toolCalls"
@approve="({ id, approved, decision }) => store.approveToolCall(id, approved, decision)"
@batch-approve="(decision) => store.batchApprove(decision)"
@install-obscura="onInstallObscura"
@pending-out-of-view="onPendingOutOfView"
/>
</div>
</template>
</div>
</div>
</div>