mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 15:53:56 +00:00
merge: 桌面版/鸿蒙端同步阶段管道工具格滚动展示最新一条调用(feature/stage-pipe-tool-cell-clients)
This commit is contained in:
@ -1094,6 +1094,10 @@ function rtTrailPush(g, kind, label, short) {
|
|||||||
function renderRuntimePanel() {
|
function renderRuntimePanel() {
|
||||||
var title = __("运行态", "Runtime");
|
var title = __("运行态", "Runtime");
|
||||||
var rt = state.runtime;
|
var rt = state.runtime;
|
||||||
|
// 工具格的滑入动画只在「新到一条工具调用」那一次播放:overview 是整块
|
||||||
|
// innerHTML 重建,节点每次都是新的;若无条件带动画类,任何重渲染都会闪一下。
|
||||||
|
var toolFlash = !!state.toolFlash;
|
||||||
|
state.toolFlash = false;
|
||||||
if (!rt) {
|
if (!rt) {
|
||||||
return (
|
return (
|
||||||
'<div class="card"><h2>' + title + '</h2><p class="rt-empty">' +
|
'<div class="card"><h2>' + title + '</h2><p class="rt-empty">' +
|
||||||
@ -1133,22 +1137,44 @@ function renderRuntimePanel() {
|
|||||||
var items = (state.stageTrail || []).filter(function (t) {
|
var items = (state.stageTrail || []).filter(function (t) {
|
||||||
return (t.g | 0) === i;
|
return (t.g | 0) === i;
|
||||||
});
|
});
|
||||||
var body = items.length
|
// 「工具」是循环格:一轮里可能调几十次工具/输出通道,全部追加会把这一格
|
||||||
? items
|
// 撑成长条,反而看不出「现在在调什么」。只留**最新一条**,右侧给本轮累计
|
||||||
.map(function (t) {
|
// 次数(与 WebUI 同一口径,见 internal/plugins/webui/dashboard.js)。
|
||||||
var kind = t.kind || "stage";
|
var cls = "rt-pipe-events";
|
||||||
var ico =
|
var body;
|
||||||
kind === "output" ? RT_ICO.out : kind === "tool" ? RT_ICO.tool : "";
|
if (!items.length) {
|
||||||
return (
|
body = '<span class="rt-chip rt-chip-none">' + __("无", "none") + "</span>";
|
||||||
'<span class="rt-chip rt-chip-' + kind + '" title="' +
|
} else if (s.loop) {
|
||||||
escHtml(t.label) + '">' + ico +
|
cls += " rt-pipe-scroll";
|
||||||
escHtml(t.short || t.label) +
|
var total = 0;
|
||||||
(t.n > 1 ? '<i class="rt-chip-n">x' + t.n + "</i>" : "") +
|
for (var k = 0; k < items.length; k++) total += items[k].n || 1;
|
||||||
"</span>"
|
var latest = items[items.length - 1];
|
||||||
);
|
var lkind = latest.kind || "stage";
|
||||||
})
|
var lico = lkind === "output" ? RT_ICO.out : lkind === "tool" ? RT_ICO.tool : "";
|
||||||
.join("")
|
body =
|
||||||
: '<span class="rt-chip rt-chip-none">' + __("无", "none") + "</span>";
|
'<span class="rt-chip rt-chip-' + lkind + (toolFlash ? " rt-chip-enter" : "") +
|
||||||
|
'" title="' + escHtml(latest.label) + '">' + lico +
|
||||||
|
'<b class="rt-chip-t">' + escHtml(latest.short || latest.label) + "</b>" +
|
||||||
|
(latest.n > 1 ? '<i class="rt-chip-n">x' + latest.n + "</i>" : "") +
|
||||||
|
"</span>" +
|
||||||
|
'<i class="rt-scroll-count" title="' +
|
||||||
|
__("本轮工具调用累计次数", "tool calls this turn") + '">x' + total + "</i>";
|
||||||
|
} else {
|
||||||
|
body = items
|
||||||
|
.map(function (t) {
|
||||||
|
var kind = t.kind || "stage";
|
||||||
|
var ico =
|
||||||
|
kind === "output" ? RT_ICO.out : kind === "tool" ? RT_ICO.tool : "";
|
||||||
|
return (
|
||||||
|
'<span class="rt-chip rt-chip-' + kind + '" title="' +
|
||||||
|
escHtml(t.label) + '">' + ico +
|
||||||
|
'<b class="rt-chip-t">' + escHtml(t.short || t.label) + "</b>" +
|
||||||
|
(t.n > 1 ? '<i class="rt-chip-n">x' + t.n + "</i>" : "") +
|
||||||
|
"</span>"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
'<div class="rt-pipe-cell' + (i === g ? " active" : "") + '">' +
|
'<div class="rt-pipe-cell' + (i === g ? " active" : "") + '">' +
|
||||||
'<div class="rt-pipe-head">' + RT_ICO[s.ico] +
|
'<div class="rt-pipe-head">' + RT_ICO[s.ico] +
|
||||||
@ -1158,7 +1184,7 @@ function renderRuntimePanel() {
|
|||||||
__("工具调用会回到行动后,可多次", "tool calls loop back; may repeat") +
|
__("工具调用会回到行动后,可多次", "tool calls loop back; may repeat") +
|
||||||
'">' + RT_ICO.loop + "</em>"
|
'">' + RT_ICO.loop + "</em>"
|
||||||
: "") +
|
: "") +
|
||||||
'</div><div class="rt-pipe-events">' + body + "</div></div>"
|
'</div><div class="' + cls + '">' + body + "</div></div>"
|
||||||
);
|
);
|
||||||
}).join("");
|
}).join("");
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
@ -5477,6 +5503,7 @@ async function connectFetchSSE(url) {
|
|||||||
tool,
|
tool,
|
||||||
rtShortTool(tool),
|
rtShortTool(tool),
|
||||||
);
|
);
|
||||||
|
if (tool) state.toolFlash = true;
|
||||||
state.chatStage = __("工具调用: ", "Tool: ") + (tool || "");
|
state.chatStage = __("工具调用: ", "Tool: ") + (tool || "");
|
||||||
if (tool && (state.pendingTools || []).indexOf(tool) === -1) {
|
if (tool && (state.pendingTools || []).indexOf(tool) === -1) {
|
||||||
if (!state.pendingTools) state.pendingTools = [];
|
if (!state.pendingTools) state.pendingTools = [];
|
||||||
|
|||||||
@ -2287,6 +2287,40 @@ td .switch {
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
min-height: 23px;
|
min-height: 23px;
|
||||||
}
|
}
|
||||||
|
/* 「工具」格的滚动视口:固定一行高,只露最新一条(与 WebUI 同一口径)。 */
|
||||||
|
.rt-pipe-scroll {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
height: 23px;
|
||||||
|
min-height: 23px;
|
||||||
|
overflow: hidden;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.rt-pipe-scroll .rt-chip {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
.rt-chip-enter {
|
||||||
|
animation: rt-chip-scroll-in 0.3s var(--ease-out);
|
||||||
|
}
|
||||||
|
@keyframes rt-chip-scroll-in {
|
||||||
|
from {
|
||||||
|
transform: translateY(115%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rt-scroll-count {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-left: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10.5px;
|
||||||
|
opacity: 0.6;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
.rt-loop {
|
.rt-loop {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
@ -2308,6 +2342,13 @@ td .switch {
|
|||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
.rt-chip-t {
|
||||||
|
font-weight: inherit;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.rt-chip-tool {
|
.rt-chip-tool {
|
||||||
border-color: rgba(136, 192, 208, 0.42);
|
border-color: rgba(136, 192, 208, 0.42);
|
||||||
color: var(--frost-300);
|
color: var(--frost-300);
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import {
|
|||||||
|
|
||||||
/** 四级中断 + 排队的配色:与 WebUI 总览同一套(级别色贯穿框头、槽位、描边) */
|
/** 四级中断 + 排队的配色:与 WebUI 总览同一套(级别色贯穿框头、槽位、描边) */
|
||||||
const LV_COLORS: string[] = ['#A3BE8C', '#4A90D9', '#0A59F7', '#FFA657', '#FF5C7A'];
|
const LV_COLORS: string[] = ['#A3BE8C', '#4A90D9', '#0A59F7', '#FFA657', '#FF5C7A'];
|
||||||
|
/** 阶段管道里的「工具」格(循环格):一轮内可能调几十次,只露最新一条 */
|
||||||
|
const TOOL_GROUP: number = 2;
|
||||||
/** 索引 = lv(0 排队 / 1 L1 / 2 L2 / 3 L3 / 4 L4) */
|
/** 索引 = lv(0 排队 / 1 L1 / 2 L2 / 3 L3 / 4 L4) */
|
||||||
function lvColor(lv: number): string {
|
function lvColor(lv: number): string {
|
||||||
if (lv < 0 || lv > 4) {
|
if (lv < 0 || lv > 4) {
|
||||||
@ -86,6 +88,30 @@ export struct RuntimePanel {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 该阶段本轮事件的**最后一条**(最新)。没有则 undefined。 */
|
||||||
|
private latestEvent(group: number): StageEvent | undefined {
|
||||||
|
let out: StageEvent | undefined = undefined;
|
||||||
|
for (let i = 0; i < this.trail.length; i++) {
|
||||||
|
const e: StageEvent = this.trail[i];
|
||||||
|
if (e.group === group) {
|
||||||
|
out = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 该阶段本轮事件条数合计(同一工具连调会累加到 count 上) */
|
||||||
|
private totalCount(group: number): number {
|
||||||
|
let n: number = 0;
|
||||||
|
for (let i = 0; i < this.trail.length; i++) {
|
||||||
|
const e: StageEvent = this.trail[i];
|
||||||
|
if (e.group === group) {
|
||||||
|
n += e.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
tile(label: string, value: string, warn: boolean) {
|
tile(label: string, value: string, warn: boolean) {
|
||||||
Column({ space: 2 }) {
|
Column({ space: 2 }) {
|
||||||
@ -128,30 +154,57 @@ export struct RuntimePanel {
|
|||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
|
|
||||||
// 本阶段本轮发生的事件;没有就给一个弱化的「无」,让框不空着
|
// 本阶段本轮发生的事件;没有就给一个弱化的「无」,让框不空着。
|
||||||
|
//
|
||||||
|
// 「工具」格是循环格:一轮里可能调几十次工具/输出通道。把每一次都追加成
|
||||||
|
// 一行,这格会被撑成长条,反而看不出「现在在调什么」。所以它只保留**最新
|
||||||
|
// 一条**,右侧给本轮累计次数(与 WebUI/桌面版同一口径)。
|
||||||
Column({ space: 3 }) {
|
Column({ space: 3 }) {
|
||||||
ForEach(this.eventsOf(g.group), (e: StageEvent) => {
|
if (g.group === TOOL_GROUP) {
|
||||||
Row({ space: 3 }) {
|
if (this.eventsOf(g.group).length > 0) {
|
||||||
Text(e.short)
|
Row({ space: 3 }) {
|
||||||
.fontSize(9)
|
Text(this.latestEvent(g.group)?.short ?? '')
|
||||||
.fontColor(e.kind === 'output' ? this.palette().accent
|
.fontSize(9)
|
||||||
: (e.kind === 'tool' ? COLOR_FROST_300 : this.palette().textSecondary))
|
.fontColor(this.latestEvent(g.group)?.kind === 'output' ? this.palette().accent
|
||||||
.maxLines(1)
|
: (this.latestEvent(g.group)?.kind === 'tool' ? COLOR_FROST_300 : this.palette().textSecondary))
|
||||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
.maxLines(1)
|
||||||
if (e.count > 1) {
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
Text('x' + e.count.toString())
|
.layoutWeight(1)
|
||||||
|
Text('x' + this.totalCount(g.group).toString())
|
||||||
.fontSize(9)
|
.fontSize(9)
|
||||||
.fontColor(this.palette().textMuted)
|
.fontColor(this.palette().textMuted)
|
||||||
}
|
}
|
||||||
|
.width('100%')
|
||||||
|
} else {
|
||||||
|
Text('无')
|
||||||
|
.fontSize(9)
|
||||||
|
.fontColor(this.palette().textMuted)
|
||||||
|
.opacity(0.5)
|
||||||
}
|
}
|
||||||
.width('100%')
|
} else {
|
||||||
}, (e: StageEvent, i: number) => i.toString() + ':' + e.short)
|
ForEach(this.eventsOf(g.group), (e: StageEvent) => {
|
||||||
|
Row({ space: 3 }) {
|
||||||
|
Text(e.short)
|
||||||
|
.fontSize(9)
|
||||||
|
.fontColor(e.kind === 'output' ? this.palette().accent
|
||||||
|
: (e.kind === 'tool' ? COLOR_FROST_300 : this.palette().textSecondary))
|
||||||
|
.maxLines(1)
|
||||||
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
|
if (e.count > 1) {
|
||||||
|
Text('x' + e.count.toString())
|
||||||
|
.fontSize(9)
|
||||||
|
.fontColor(this.palette().textMuted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
}, (e: StageEvent, i: number) => i.toString() + ':' + e.short)
|
||||||
|
|
||||||
if (this.eventsOf(g.group).length === 0) {
|
if (this.eventsOf(g.group).length === 0) {
|
||||||
Text('无')
|
Text('无')
|
||||||
.fontSize(9)
|
.fontSize(9)
|
||||||
.fontColor(this.palette().textMuted)
|
.fontColor(this.palette().textMuted)
|
||||||
.opacity(0.5)
|
.opacity(0.5)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
|
|||||||
Reference in New Issue
Block a user