diff --git a/static/src/components/chat/quickdock/RunnerDetailPanel.vue b/static/src/components/chat/quickdock/RunnerDetailPanel.vue
index a8bb4c1f..90ec4be0 100644
--- a/static/src/components/chat/quickdock/RunnerDetailPanel.vue
+++ b/static/src/components/chat/quickdock/RunnerDetailPanel.vue
@@ -30,15 +30,23 @@
v-for="item in timelineItems"
:key="item.key"
class="qd-feed-row"
- :class="[item.kind === 'tool' ? 'feed-tool' : 'feed-text', { 'is-new': animatedKeys.has(item.key) }]"
+ :class="[item.kind === 'tool' ? 'feed-tool' : item.kind === 'compression' ? 'feed-compressed' : 'feed-text', { 'is-new': animatedKeys.has(item.key) }]"
>
-
- {{ item.state === 'failed' ? '✕' : '✓' }}
{{ item.toolName }}
{{ item.text }}
-
- {{ item.stateLabel }}
+
+
+ {{ item.state === 'failed' ? '✕' : '✓' }}
+
+
+
+
+
+ {{ t('quickdock.contextCompressed', { round: item.round }) }}
{{ item.content }}
@@ -283,14 +291,6 @@ function isEntryTerminal(status?: string) {
].includes(normalized);
}
-/** 工具条目状态标签:映射表存 key、使用处解析(规范 §3.3,模块顶层禁止调 t()) */
-const TOOL_STATE_LABEL_KEYS: Record = {
- completed: 'quickdock.toolStateDone',
- failed: 'quickdock.toolStateFailed',
- calling: 'quickdock.toolStateCalling',
- running: 'quickdock.toolStateProgress'
-};
-
function buildText(entry: any): string {
const tool = entry.tool || '';
const args = entry.args || {};
@@ -309,7 +309,6 @@ interface ToolTimelineItem {
kind: 'tool';
key: string;
state: string;
- stateLabel: string;
toolName: string;
text: string;
}
@@ -320,10 +319,16 @@ interface OutputTimelineItem {
content: string;
}
-const timelineItems = computed<(ToolTimelineItem | OutputTimelineItem)[]>(() => {
+interface CompressionTimelineItem {
+ kind: 'compression';
+ key: string;
+ round: number;
+}
+
+const timelineItems = computed<(ToolTimelineItem | OutputTimelineItem | CompressionTimelineItem)[]>(() => {
void currentLocale.value;
const entries = activityEntries.value || [];
- const rawItems: ({ kind: 'tool'; key: string; entry: any } | OutputTimelineItem)[] = [];
+ const rawItems: ({ kind: 'tool'; key: string; entry: any } | OutputTimelineItem | CompressionTimelineItem)[] = [];
let currentToolGroup: { kind: 'tool'; key: string; entry: any } | null = null;
const flushToolGroup = () => {
@@ -361,6 +366,17 @@ const timelineItems = computed<(ToolTimelineItem | OutputTimelineItem)[]>(() =>
return;
}
+ // 上下文压缩提示:在压缩发生的位置插入一条提示条目
+ if (entry?.type === 'progress' && entry?.subtype === 'compression') {
+ flushToolGroup();
+ rawItems.push({
+ kind: 'compression',
+ key: `compression-${entry.ts || index}`,
+ round: Number(entry.round) || 0,
+ });
+ return;
+ }
+
if (!entry || entry.type !== 'progress' || !entry.tool) {
return;
}
@@ -401,7 +417,7 @@ const timelineItems = computed<(ToolTimelineItem | OutputTimelineItem)[]>(() =>
flushToolGroup();
return rawItems.map((item) => {
- if (item.kind === 'output') {
+ if (item.kind === 'output' || item.kind === 'compression') {
return item;
}
const state = normalizeStatus(item.entry.status);
@@ -409,7 +425,6 @@ const timelineItems = computed<(ToolTimelineItem | OutputTimelineItem)[]>(() =>
kind: 'tool' as const,
key: item.key,
state,
- stateLabel: t(TOOL_STATE_LABEL_KEYS[state] || 'quickdock.toolStateProgress'),
toolName: item.entry.tool || t('common.tool'),
text: buildText(item.entry)
};
diff --git a/static/src/components/chat/quickdock/quickdock.css b/static/src/components/chat/quickdock/quickdock.css
index 1611d80a..dd894ae1 100644
--- a/static/src/components/chat/quickdock/quickdock.css
+++ b/static/src/components/chat/quickdock/quickdock.css
@@ -697,15 +697,16 @@
min-width: 0;
}
-.qd-feed-row.feed-tool .tool-result {
+.qd-feed-row.feed-tool .tool-status {
flex: none;
margin-left: auto;
- font-size: 11.5px;
- color: var(--text-tertiary);
- font-variant-numeric: tabular-nums;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 14px;
}
-.qd-feed-row.feed-tool .tool-result.is-error {
+.qd-feed-row.feed-tool .tool-status.is-error .qd-tool-done {
color: var(--state-danger);
}
@@ -733,6 +734,25 @@
color: var(--accent);
}
+.qd-feed-row.feed-compressed {
+ justify-content: center;
+ padding: 2px 14px;
+}
+
+.qd-feed-row.feed-compressed .feed-compressed__label {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ font-size: 11.5px;
+ color: var(--text-tertiary);
+}
+
+.qd-feed-row.feed-compressed .feed-compressed__icon {
+ width: 12px;
+ height: 12px;
+ flex: none;
+}
+
.qd-feed-row.feed-term {
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
font-size: 12px;
diff --git a/static/src/locales/en-US/quickdock.ts b/static/src/locales/en-US/quickdock.ts
index 578fb469..9e9617ce 100644
--- a/static/src/locales/en-US/quickdock.ts
+++ b/static/src/locales/en-US/quickdock.ts
@@ -39,10 +39,9 @@ export default {
toolRunCommand: 'Run command {command}',
toolEditFile: 'Edit {path}',
toolReadMedia: 'Read media file {path}',
- toolStateDone: 'Done',
- toolStateFailed: 'Failed',
- toolStateCalling: 'Calling...',
- toolStateProgress: 'In progress',
+
+ // —— Sub-agent detail panel: context compression notice ——
+ contextCompressed: 'Context compressed (round {round})',
// —— File preview panel ——
resizeWidthHint: 'Drag to resize width',
diff --git a/static/src/locales/zh-CN/quickdock.ts b/static/src/locales/zh-CN/quickdock.ts
index ab36406d..d8b45681 100644
--- a/static/src/locales/zh-CN/quickdock.ts
+++ b/static/src/locales/zh-CN/quickdock.ts
@@ -46,10 +46,9 @@ export default {
toolRunCommand: '运行命令 {command}',
toolEditFile: '编辑 {path}',
toolReadMedia: '读取媒体文件 {path}',
- toolStateDone: '完成',
- toolStateFailed: '失败',
- toolStateCalling: '调用中',
- toolStateProgress: '进行中',
+
+ // —— 子智能体详情面板:上下文压缩提示 ——
+ contextCompressed: '上下文已压缩(第 {round} 轮)',
// —— 文件预览面板(FilePreviewPanel) ——
resizeWidthHint: '拖拽调整宽度',