@wendongfly/myhi 1.3.154 → 1.3.156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat.html +81 -4
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -402,8 +402,7 @@
|
|
|
402
402
|
<button class="top-btn" onclick="openSettings()" title="设置">
|
|
403
403
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 01-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
|
|
404
404
|
</button>
|
|
405
|
-
<button class="top-btn" id="ctx-chip" onclick="
|
|
406
|
-
<button class="top-btn" onclick="showUsage()" title="用量" style="font-size:0.7rem;color:var(--muted)">用量</button>
|
|
405
|
+
<button class="top-btn" id="ctx-chip" onclick="openCtxSheet()" title="会话数据:上下文水位 / 成本 / token 明细" style="display:none;width:auto;padding:0 0.5rem;white-space:nowrap;font-size:0.7rem;color:var(--muted)">◈ --</button>
|
|
407
406
|
<button class="top-btn" onclick="openFilePanel()" title="文件" style="font-size:0.7rem;color:var(--muted)">文件</button>
|
|
408
407
|
<button class="top-btn" onclick="openSwitchSheet()" title="切换会话" style="font-size:0.7rem;color:var(--muted)">切换</button>
|
|
409
408
|
<button class="top-btn" onclick="goBack()" title="返回">
|
|
@@ -604,6 +603,16 @@
|
|
|
604
603
|
<button id="new-msg-btn" onclick="jumpToBottom()">↓ 新消息</button>
|
|
605
604
|
|
|
606
605
|
<!-- 模型选择面板 -->
|
|
606
|
+
<!-- 会话数据面板:上下文水位 + 本会话成本/token 明细(点顶栏水位 chip 打开)-->
|
|
607
|
+
<div id="ctx-sheet" class="action-sheet">
|
|
608
|
+
<div class="action-sheet-backdrop" onclick="closeCtxSheet()"></div>
|
|
609
|
+
<div class="action-sheet-box">
|
|
610
|
+
<div class="action-sheet-title">会话数据</div>
|
|
611
|
+
<div id="ctx-sheet-body" style="padding:0 0.2rem"><div style="text-align:center;color:var(--muted);font-size:0.8rem;padding:1rem">加载中...</div></div>
|
|
612
|
+
<button class="action-sheet-cancel" onclick="closeCtxSheet()">关闭</button>
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
|
|
607
616
|
<div id="model-sheet" class="action-sheet">
|
|
608
617
|
<div class="action-sheet-backdrop" onclick="closeModelSheet()"></div>
|
|
609
618
|
<div class="action-sheet-box">
|
|
@@ -2249,6 +2258,7 @@
|
|
|
2249
2258
|
const ct = (cu.input_tokens || 0) + (cu.cache_read_input_tokens || 0) + (cu.cache_creation_input_tokens || 0);
|
|
2250
2259
|
if (ct > 0) ctxUpdate(ct);
|
|
2251
2260
|
}
|
|
2261
|
+
if (/\[1m\]/i.test(msg.message?.model || '')) _ctxIs1M = true;
|
|
2252
2262
|
if (msg.message?.content) {
|
|
2253
2263
|
// 进入 loop 前快照:同一 assistant 事件里所有 text 块统一按入口时刻的 call 标志决定,
|
|
2254
2264
|
// 避免渲染完第一段 text 后置位标志,导致同事件内 [text, tool_use, text] 的第二段被跳过
|
|
@@ -2625,8 +2635,10 @@
|
|
|
2625
2635
|
// 数据源:claude 每条 assistant/result 消息的 usage(input + cache 读/写)≈ 当前上下文 token 总量。
|
|
2626
2636
|
// claude 满 ~90% 会 auto-compact;myhi 显示水位 + 过阈值提示,让用户在任务节点**主动**压缩更可控。
|
|
2627
2637
|
const CTX_WARN = 0.75, CTX_URGENT = 0.9;
|
|
2638
|
+
let _ctxIs1M = false; // stream 里 model 带 [1m] 后缀(如 claude-opus-5-5[1m])→ 精确判定 1M 窗口
|
|
2628
2639
|
function ctxLimit(tokens) {
|
|
2629
|
-
|
|
2640
|
+
if (_ctxIs1M) return 1_000_000;
|
|
2641
|
+
// 没有 [1m] 标记时的兜底:200k 窗口装不下 >200k,超过即证明是 1M
|
|
2630
2642
|
return tokens > 200_000 ? 1_000_000 : 200_000;
|
|
2631
2643
|
}
|
|
2632
2644
|
function ctxUpdate(tokens) {
|
|
@@ -2636,7 +2648,7 @@
|
|
|
2636
2648
|
const limit = ctxLimit(tokens);
|
|
2637
2649
|
const pct = Math.min(100, Math.round(tokens / limit * 100));
|
|
2638
2650
|
chip.style.display = '';
|
|
2639
|
-
chip.textContent =
|
|
2651
|
+
chip.textContent = `◈ ${pct}%`;
|
|
2640
2652
|
chip.style.color = pct >= 90 ? 'var(--red)' : pct >= 75 ? 'var(--yellow)' : 'var(--muted)';
|
|
2641
2653
|
// 压缩快捷按钮同步高亮(agent 栏是 doSlashCmd('/compact'),PTY 栏是 doCompact())
|
|
2642
2654
|
for (const sel of [
|
|
@@ -2661,6 +2673,71 @@
|
|
|
2661
2673
|
window.ctxUpdate = ctxUpdate; // 惯例挂 window(同 doClear/doCompact),便于外部/测试驱动
|
|
2662
2674
|
window.ctxMaybeNudge = ctxMaybeNudge;
|
|
2663
2675
|
|
|
2676
|
+
// ── 会话数据面板 ────────────────────────────────
|
|
2677
|
+
// 点顶栏「上下文 N%」chip 打开:水位 + 本会话成本/token 明细。
|
|
2678
|
+
// 数据每次打开时从 /api/sessions 现取(toJSON.usage 是服务端权威累计,前端不用自己维护账本)。
|
|
2679
|
+
window.openCtxSheet = async function() {
|
|
2680
|
+
document.getElementById('ctx-sheet').classList.add('open');
|
|
2681
|
+
const body = document.getElementById('ctx-sheet-body');
|
|
2682
|
+
try {
|
|
2683
|
+
const list = await (await fetch('/api/sessions', { credentials: 'same-origin' })).json();
|
|
2684
|
+
const s = (Array.isArray(list) ? list : list.sessions || []).find((x) => x.id === SESSION_ID);
|
|
2685
|
+
if (!s) { body.innerHTML = '<div style="text-align:center;color:var(--muted);font-size:0.8rem;padding:1rem">会话数据不可用</div>'; return; }
|
|
2686
|
+
body.innerHTML = ctxRenderSheet(s);
|
|
2687
|
+
} catch {
|
|
2688
|
+
body.innerHTML = '<div style="text-align:center;color:var(--red);font-size:0.8rem;padding:1rem">加载失败</div>';
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
window.closeCtxSheet = function() {
|
|
2692
|
+
document.getElementById('ctx-sheet').classList.remove('open');
|
|
2693
|
+
};
|
|
2694
|
+
function ctxRenderSheet(s) {
|
|
2695
|
+
const C = 'style="margin-bottom:0.7rem;padding:0.7rem 0.85rem;background:var(--bg);border:1px solid var(--surface2);border-radius:10px"';
|
|
2696
|
+
const H = 'style="font-size:0.78rem;font-weight:700;margin-bottom:0.45rem;color:var(--text)"';
|
|
2697
|
+
const R = 'style="display:flex;justify-content:space-between;font-size:0.78rem;color:var(--text2);line-height:1.7"';
|
|
2698
|
+
const V = 'style="color:var(--text);font-family:\'SF Mono\',Consolas,monospace"';
|
|
2699
|
+
const u = s.usage || {};
|
|
2700
|
+
const tokens = s.contextTokens || 0;
|
|
2701
|
+
let html = '';
|
|
2702
|
+
|
|
2703
|
+
// ① 上下文水位
|
|
2704
|
+
if (tokens > 0) {
|
|
2705
|
+
const limit = ctxLimit(tokens);
|
|
2706
|
+
const pct = Math.min(100, Math.round(tokens / limit * 100));
|
|
2707
|
+
const barColor = pct >= 90 ? 'var(--red)' : pct >= 75 ? 'var(--yellow)' : 'var(--blue2)';
|
|
2708
|
+
html += `<div ${C}><div ${H}>上下文水位</div>` +
|
|
2709
|
+
`<div style="background:var(--surface2);border-radius:6px;height:10px;overflow:hidden;margin-bottom:0.4rem"><div style="width:${pct}%;height:100%;background:${barColor};border-radius:6px;transition:width 0.4s"></div></div>` +
|
|
2710
|
+
`<div ${R}><span>${pct}%(${pct >= 90 ? '快满了,建议主动压缩' : pct >= 75 ? '建议任务节点压缩' : '健康'})</span><span ${V}>${(tokens / 1000).toFixed(1)}k / ${limit >= 1_000_000 ? '1M' : '200k'}</span></div></div>`;
|
|
2711
|
+
} else {
|
|
2712
|
+
html += `<div ${C}><div ${H}>上下文水位</div><div ${R}><span style="color:var(--muted)">本轮还没跑过查询</span></div></div>`;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
// ② 累计用量(服务端权威账本)
|
|
2716
|
+
html += `<div ${C}><div ${H}>本会话累计</div>` +
|
|
2717
|
+
`<div ${R}><span>查询轮数</span><span ${V}>${u.queryCount || 0}</span></div>` +
|
|
2718
|
+
`<div ${R}><span>花费</span><span ${V}>$${(u.totalCostUSD || 0).toFixed(4)}</span></div>` +
|
|
2719
|
+
`<div ${R}><span>输入 token</span><span ${V}>${fmtK(u.totalInputTokens)}</span></div>` +
|
|
2720
|
+
`<div ${R}><span>输出 token</span><span ${V}>${fmtK(u.totalOutputTokens)}</span></div>` +
|
|
2721
|
+
`<div ${R}><span>cache 读</span><span ${V}>${fmtK(u.totalCacheReadTokens)}</span></div>` +
|
|
2722
|
+
`<div ${R}><span>cache 写</span><span ${V}>${fmtK(u.totalCacheCreationTokens)}</span></div></div>`;
|
|
2723
|
+
|
|
2724
|
+
// ③ 各模型明细(切过模型的会话能看到分模型账目)
|
|
2725
|
+
const mu = u.modelUsage || {};
|
|
2726
|
+
const models = Object.entries(mu);
|
|
2727
|
+
if (models.length) {
|
|
2728
|
+
html += `<div ${C}><div ${H}>分模型</div>`;
|
|
2729
|
+
for (const [m, d] of models) {
|
|
2730
|
+
html += `<div ${R}><span style="max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${m}">${m}</span><span ${V}>${fmtK(d.inputTokens)}入/${fmtK(d.outputTokens)}出 · $${(d.costUSD || 0).toFixed(4)}</span></div>`;
|
|
2731
|
+
}
|
|
2732
|
+
html += '</div>';
|
|
2733
|
+
}
|
|
2734
|
+
return html;
|
|
2735
|
+
}
|
|
2736
|
+
function fmtK(n) {
|
|
2737
|
+
n = n || 0;
|
|
2738
|
+
return n >= 1_000_000 ? (n / 1_000_000).toFixed(2) + 'M' : n >= 1000 ? (n / 1000).toFixed(1) + 'k' : String(n);
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2664
2741
|
// 服务端本地处理的 slash 命令(agent.js 拦截后只回一条 system/info、不 spawn claude、
|
|
2665
2742
|
// 永远等不到 result)—— 这些不能进 thinking/working 态,否则没人把它清回来:
|
|
2666
2743
|
// 切模型后输入框永远「运行中」(1.3.152 用户实测)。
|
package/package.json
CHANGED