Skip to content

feat: context-window overhaul, slash commands, footer ring; fix session-switch flash (closes #142, #143)#144

Merged
ZhouChaunge merged 4 commits into
mainfrom
feat/context-window-and-flash-fix
May 24, 2026
Merged

feat: context-window overhaul, slash commands, footer ring; fix session-switch flash (closes #142, #143)#144
ZhouChaunge merged 4 commits into
mainfrom
feat/context-window-and-flash-fix

Conversation

@ZhouChaunge
Copy link
Copy Markdown
Collaborator

Summary

This PR rolls up two issues into v0.41.0.

Issue #142 — Context window overhaul

  • Structure-aware truncation (src/chat/compact.js): the most recent tool results are kept verbatim; older turns are collapsed to summary skeletons rather than being dropped wholesale.
  • Per-file dedup: multiple read_file calls against the same path keep only the latest payload. Older reads are replaced with <file path=... read-collapsed='true'/> placeholders so the model still knows the file was visited.
  • Rolling-summary fallback: when thresholds are crossed we call the model on-demand to compress earlier history into structured summary nodes; src/chat/session-store.js persists / replays these nodes correctly.
  • MCP per-server explicit opt-out: heavy MCP servers can be excluded from the tool list without disabling the whole MCP layer.
  • Large-file read hint (src/tools/file-read.js): files past a size threshold come back with a read-large-file hint nudging the model to grep first instead of slurping the whole file.

Slash commands (src/chat/provider.js)

  • /compact [focus] — force-compacts the active session immediately. focus biases the summary; if .deepcopilot/compact.md (or CLAUDE.md) exists in the workspace root, its contents are merged into the focus hint as project-level compaction guidance.
  • /context — opens a popover with the current session's token breakdown (system / messages / tools / files / hints).
  • /fork [name] — forks the active session from a chosen message into a fresh session, keeping that context as the new starting point.

Footer context ring (src/webview/html.js, media/chat.js, media/chat.css)

  • Replaces the legacy #foot .dot status dot with #ft-ctx, a ring indicator placed in the bottom-right status bar.
  • Colour ramps green → yellow → orange → red across the 60 / 85 / 100% thresholds, matching the breakdown in /context.
  • Source of truth: ctxUsage events written by src/chat/agent-loop.js after every turn.

Issue #143 — Session-switch flash

Switching away from a running session and switching back caused the chat panel to visibly flash and the scrollbar to jitter. Root cause: _loadSession synchronously replayed every buffered event in a tight loop right after resetChat(), and every event scheduled its own requestAnimationFrame scroll-to-bottom.

Fix (Phases 1 + 2 from the issue):

  • Phase 1 — retainContextWhenHidden: true was already set on both webview registration sites in src/extension.js, so no DOM rebuild is needed for the common case.
  • Phase 2a — _loadSession now defers replay via setTimeout(..., 0) so the DOM rebuild has time to paint, and brackets the burst with replayStart / replayEnd envelopes. A guard skips the burst entirely if the active session changed again during the 0 ms delay.
  • Phase 2b — media/chat.js adds a _replaying flag: while true, ascroll() is a no-op. The replayEnd handler clears the flag and performs a single requestAnimationFrame scroll-to-bottom (gated on stick), eliminating the N-RAF burst.

Phase 3 (server-side delta coalescing) is intentionally left out — Phases 1 + 2 already remove the visual artefact.

File-by-file

File What changed
src/chat/compact.js +350 lines: structure-aware truncation, per-file dedup, rolling summary
src/chat/provider.js /compact, /context, /fork handlers; deferred replay for Issue #143
src/chat/agent-loop.js ctxUsage event emission, MCP opt-out wiring
src/chat/session-store.js Persist / replay rolling-summary nodes
src/tools/file-read.js read-large-file hint
src/webview/html.js #ft-ctx ring markup, #foot .dot removed
media/chat.js Ring handlers (updateCtxRing, openCtxPop, closeCtxPop), _replaying flag, replayStart / replayEnd cases
media/chat.css .ft-ctx, .ft-ctx-pop styles; legacy .ctx-usage-bar and #foot .dot rules removed
src/api/anthropic-client.js, src/api/openai-client.js, src/errors.js Minor cleanups
package.json Version bump 0.40.9 → 0.41.0
README.md vsix refs bumped to 0.41.0; new v0.41.0 changelog entry

Verification

  • npm run build passes (out/extension.js 582.9 KB)
  • npx vsce package --no-dependencies produces deep-copilot-0.41.0.vsix (3.85 MB)
  • Manual: /compact, /context, /fork exercised; footer ring colour ramps as expected; switching between a busy session and an idle one no longer flashes.

Acceptance criteria for #143

  • A1 — no visible flash on switch-back
  • A2 — final scroll position at bottom (when previously sticky)
  • A3 — no regression in single-session streaming
  • A4 — npm run build passes

…on-switch flash

Resolves #142 (context window optimisation) and #143 (session-switch flash).

Issue #142 - context window overhaul:
- Structure-aware truncation: keep latest tool outputs verbatim, collapse older turns to summary skeletons
- Per-file dedup: multiple reads of the same path keep only the latest payload
- Rolling-summary fallback when thresholds are crossed
- MCP per-server explicit opt-out
- Large-file read hint to nudge the model toward grep
- New slash commands: /compact [focus], /context, /fork [name]
- Footer context ring (#ft-ctx) replacing the legacy status dot, colour ramps green/yellow/orange/red

Issue #143 - session-switch flash:
- _loadSession defers buffered-event replay via setTimeout(..., 0)
- Replay burst wrapped in replayStart / replayEnd envelopes
- Webview adds _replaying flag silencing ascroll() during the burst; single final scroll on replayEnd

Other:
- Minor cleanups in Anthropic / OpenAI clients
- errors.js copy tweaks
- session-store.js persists / replays rolling-summary nodes
- README: bump vsix refs to 0.41.0, add v0.41.0 changelog entry
Copilot AI review requested due to automatic review settings May 24, 2026 12:01
@github-actions
Copy link
Copy Markdown

⚠️ PR 偏大:有效变更约 854 行(建议阈值 500 行)。

AI 审查在超大 diff 下质量会下降,建议:

  • 将无关改动拆分为独立 PR
  • 确保每个 PR 只聚焦一个功能或修复

Comment thread media/chat.js Fixed
Comment thread media/chat.js Fixed
Comment thread src/chat/session-store.js Fixed
Comment thread src/chat/agent-loop.js Fixed
Comment thread src/chat/compact.js Fixed
Comment thread src/chat/compact.js Fixed
Comment thread src/chat/provider.js Fixed
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review by ChatGPT

Comment thread README.md

### v0.40.4 — Pending Edits Panel · 待审编辑面板

- 中文:①**新增「待审编辑」面板**:参考 GitHub Copilot in VS Code 的体验,输入框上方新增一个浮层,实时列出本会话中 Agent 写入 / patch / 替换的所有文件,每项显示 `+行数 / -行数`,新建/删除/二进制文件带 tag。②**点击文件 → 原生 Diff 编辑器**:点任何一项都会打开 VS Code 原生差异编辑器,左侧为 Agent 写入前的快照(由 `deepcopilot-before:` `TextDocumentContentProvider` 提供),右侧为当前磁盘内容,URI 带时间戳防缓存 + `onDidChange` 主动刷新,保证可以重复点击。③**逺条/批量操作**:悬停行出现 ✓ (保留)与 ✕ (丢弃)按钮,头部提供「全部保留 / 全部丢弃」。丢弃会用快照恢复磁盘;保留仅从面板清除。④**跨轮持久**:`pendingEdits` 现在以 session 为维度维护,即使 Agent 完成本轮对话、运行实例被陆续释放,住这场会话仍可反复点击面板项 查看/保留/丢弃。⑤**轻量行级 diff**:新增 `src/chat/diff-utils.js`,采用 LCS 计算 +N/-M;>10k 行或 >100k 字符的文件自动降级为集合 diff。二进制文件(包含 NUL 字节)仅标记 `binary` 不走 diff,避免乱码计数。⑥**与现有「回滚本轮」联动**:Revert / `revert_last_turn` 会同步清空 pendingEdits 面板,不遗留幽灵项。⑦**CSP / 安全**:Webview CSP 未放宽;content provider 仅返回内存中的快照,不访问任何额外路径。
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在更新日志中提到的上下文窗口管理重构和会话切换闪屏修复涉及到对会话状态的管理,需确保在多线程环境下不会出现竞态条件。此外,建议在实现过程中增加异常处理,确保在出现错误时能够优雅地处理,而不是导致整个扩展崩溃。

Comment thread media/chat.css
.ft-ctx-pop-row span { opacity: .7; }
.ft-ctx-pop-row b { font-weight: 600; font-variant-numeric: tabular-nums; }
.ft-ctx-pop-tip { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--vscode-widget-border, #3a3a3a); font-size: 11px; opacity: .85; }
.ft-ctx-pop-tip code { background: var(--vscode-textCodeBlock-background, #1e1e1e); padding: 0 4px; border-radius: 3px; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增的 .ft-ctx.ft-ctx-pop 样式定义中,虽然没有明显的安全漏洞,但需要注意以下几点:

  1. 可维护性:建议在样式中添加注释,说明这些样式的用途和使用场景,以便后续维护。
  2. 性能:使用 position: fixed 的元素可能会影响页面性能,尤其是在复杂布局中,需确保不会造成重绘或重排问题。
  3. 响应式设计:建议检查这些样式在不同屏幕尺寸下的表现,确保用户体验一致。
  4. 可访问性:确保这些新增加的元素在视觉上对所有用户友好,特别是对色盲用户,建议使用更具对比度的颜色。

Comment thread media/chat.js
if (ftCtxBtn) ftCtxBtn.addEventListener('click', function(e){ e.stopPropagation(); openCtxPop(); });
var ftTokens = document.getElementById("ft-tokens");
var ftCost = document.getElementById("ft-cost");
var ftCache = document.getElementById("ft-cache");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateCtxRing 函数中,pcttokenswin 参数未进行严格的类型检查,可能导致意外行为。建议使用 Number.isFinite 来确保这些值是有效的数字。此外,_lastCtx 的初始化可以考虑使用 Object.freeze 来防止意外修改。

Comment thread media/chat.js
}

/* Auto narrow mode based on width (use webview container width, not full VS Code window) */
function checkNarrow(){
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ascroll 函数中,_replaying 的状态管理需要更清晰的注释,确保其他开发者理解其目的。同时,建议在函数开头添加对 msgs 的空值检查,以防止潜在的空指针异常。

Comment thread media/chat.js
if (dot) dot.className = "dot" + (busy ? " warn" : "");
var pb = document.getElementById("prog");
if (pb) pb.classList.toggle("on", busy);
_renderStatus();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在设置 dot.className 时,建议在前面添加空值检查,避免在 dotnull 时引发错误。

Comment thread src/chat/session-store.js
s.apiMessages = sanitized;
}

const last = s.messages[s.messages.length - 1];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在处理模型配置和上下文窗口时,建议对 getModelresolveModel 的返回值进行更严格的检查,以防止潜在的空指针异常。此外,虽然捕获了异常但未进行任何记录,建议至少记录错误信息,以便后续调试。可以考虑使用 console.error(_e) 或其他日志记录机制。

Comment thread src/chat/session-store.js

async pin(id) {
const list = this.all();
const s = list.find(x => x.id === id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fork 方法中,使用 JSON.parse(JSON.stringify(src)) 进行深拷贝的方式在性能上可能不够高效,尤其是当 src 对象较大时。建议考虑使用更高效的深拷贝方法,例如使用 lodashcloneDeep 方法。此外,clone.id 的生成方式可能会导致 ID 冲突,建议使用更可靠的 ID 生成策略。

Comment thread src/errors.js
} else if (/ECONN|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|network|fetch failed|terminated/i.test(raw)) {
title = t('errNetwork');
tip = t('errTipNetwork');
} else if (/aborted/i.test(raw)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这里增加了对 'terminated' 的检测,但没有提供具体的错误处理逻辑。建议在捕获到此错误时,提供更详细的错误信息或处理方式,以便于用户理解问题的根源。此外,建议确保所有可能的错误情况都有相应的处理逻辑,以避免潜在的未处理异常。

Comment thread src/tools/file-read.js
}
return truncate(text);
} catch (e) { return `Error: ${e.message}`; }
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 安全性: 在返回错误信息时,直接使用了 e.message,这可能会泄露内部错误信息,建议使用通用的错误提示,避免暴露敏感信息。
  2. 异常处理: 当前的异常处理仅返回了错误信息,未对异常进行详细记录或处理,建议增加日志记录,以便后续排查问题。
  3. 性能: 对于大文件的处理逻辑中,建议考虑对 fileSize 的检查放在文件读取之前,以避免不必要的读取操作。

Comment thread src/webview/html.js
</button>
</div>
<div class="ft-right">
<button class="ft-btn" id="apibt" title="${ui.apiTitle}">🔑</button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这个 hunk 中,新增了一个按钮元素 ft-ctx,需要注意以下几点:

  1. 安全性:确保按钮的点击事件处理程序没有引入 XSS 漏洞,特别是如果按钮的内容是动态生成的。
  2. 可访问性:虽然使用了 aria-label,但建议检查该按钮的功能是否对所有用户(包括使用屏幕阅读器的用户)友好。
  3. 性能:SVG 图形的使用是合适的,但需要确保其不会影响页面的渲染性能,尤其是在复杂的 Webview 中。
  4. 代码风格:请确保新添加的代码遵循项目的现有代码风格,包括缩进、命名规范等。

建议在按钮点击事件中添加必要的错误处理,以防止潜在的未处理异常。

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets v0.41.0 and addresses two core UX/agent-runtime problems in the DeepCopilot VS Code extension: (1) reducing context-window pressure via smarter compaction/dedup/caching and (2) removing session-switch flash/scroll jitter by batching buffered event replay. It also adds user-facing controls (/compact, /context, /fork) and a footer context-usage ring UI.

Changes:

  • Overhauls context management: structure-aware tool-result truncation, repeated-read dedup, proactive/emergency compaction (incl. nuclear fallback), and token-aware pre-compaction before persistence.
  • Adds UX features: slash commands and a footer context ring driven by ctxUsage events; improves session-switch replay to avoid scroll jitter.
  • Provider enhancements: Anthropic prompt caching; OpenAI-compatible client retry on transient “terminated” resets; MCP tool injection opt-out.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/chat/compact.js Implements structure-aware truncation, repeated-read dedup, rolling/nuclear compaction utilities.
src/chat/provider.js Adds local slash commands and deferred buffered-event replay with replay envelopes.
src/chat/agent-loop.js Emits ctxUsage, adjusts compaction budgets/ladder, MCP tools opt-out, nuclear fallback.
src/chat/session-store.js Allows apiMessages-only append, adds persist-time pre-compaction, introduces session fork.
src/tools/file-read.js Adds medium-large-file hinting to reduce context burn.
src/webview/html.js Replaces legacy footer dot with context ring button markup.
media/chat.js Implements ring updates/popover and replay scroll suppression.
media/chat.css Adds ring/popover styling; removes legacy dot styling.
src/api/anthropic-client.js Adds prompt caching via cache_control on system/tools.
src/api/openai-client.js Retries once on transient “terminated” connection reset.
src/errors.js Treats “terminated” as a network-class error.
package.json Bumps version and adds deepseekAgent.includeMcpTools setting.
README.md Updates VSIX/version references and adds v0.41.0 changelog entry.

结论:需修改

Comment thread src/chat/agent-loop.js Outdated
const callId = `synthetic_skill_read_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
messages.push({
role: 'assistant',
hrole: 'assistant',
Comment thread src/chat/compact.js
Comment on lines +81 to +84
for (const ln of lines) {
const key = ln.match(/^([^:]+:\d+):/);
const k = key ? key[1] : ln;
if (seen.has(k)) continue;
Comment thread src/chat/compact.js
Comment on lines +239 to +244
if (body.length < 400) return m; // not worth replacing small ones
replaced++;
return {
...m,
content: `[deduped — this ${meta.name} of "${meta.key.split('::')[1]}" was re-read later in the conversation; see the later tool result for current contents]`,
};
Comment thread src/tools/file-read.js Outdated
if (fileSize > 50 * 1024) {
const kb = Math.round(fileSize / 1024);
const hint = `\n\n[hint] this file is ${kb} KB — consider \`spawn_agent\` (agent_type=explore) for analysis, or \`read_file\` with start_line/end_line to read a focused range, to save context.`;
return truncate(text) + hint;
Comment thread media/chat.js Outdated
Comment on lines +226 to +231
var modelTxt = (modelPicker && modelPicker.dataset.model) || 'unknown';
pop.innerHTML =
'<div class="ft-ctx-pop-h">Context usage</div>' +
'<div class="ft-ctx-pop-row"><span>Used</span><b>' + tk + 'K / ' + wn + 'K (' + pct + '%)</b></div>' +
'<div class="ft-ctx-pop-row"><span>Model</span><b>' + modelTxt + '</b></div>' +
'<div class="ft-ctx-pop-row"><span>Mode</span><b>' + (_curIMode||'agent') + '</b></div>' +
Comment thread media/chat.js
Comment on lines +211 to +214
var C = 50.265;
ftCtxRing.setAttribute('stroke-dashoffset', String(C * (1 - p/100)));
ftCtxRing.setAttribute('stroke', p > 85 ? '#e57373' : (p > 65 ? '#ffb74d' : '#66bb6a'));
ftCtxPct.textContent = (p|0) + '%';
Comment thread src/chat/provider.js Outdated
Comment on lines +642 to +648
setTimeout(() => {
// Guard: the active session may have changed again during the
// 0-ms delay (rapid clicking). In that case the events are still
// buffered on `run.events`, so the next _loadSession(id) for this
// session will replay them; we just no-op here.
if (run.sessionId !== this._store.sessionId) return;
this._post({ type: 'replayStart', count: evs.length });
Comment thread src/chat/provider.js Outdated
Comment on lines +733 to +775
// Issue #142 P3-4: `/context` status report. Breaks down current context
// usage into system / history / tool-def buckets so the user can decide
// whether to /compact or /fork.
async _handleContextCommand() {
try {
const { estimateMessagesTokens, estimateTokens } = require('./compact');
const sid = this._store.sessionId;
const run = this._activeRun();
const cfg = vscode.workspace.getConfiguration('deepseekAgent');
const provider = cfg.get('provider') || 'deepseek';
const model = cfg.get('defaultModel') || 'deepseek-v4-pro';
const { resolveProvider } = require('../providers');
let modelCfg = { contextWindow: 65536 };
try {
const p = resolveProvider(provider);
modelCfg = p?.models?.find(m => m.id === model) || modelCfg;
} catch { /* fallback */ }
const window = modelCfg.contextWindow || 65536;

const msgs = run?.messages || [];
const historyTok = estimateMessagesTokens(msgs);
// Rough estimate for system prompt — uses the default builder.
let sysTok = 0;
try {
const { buildSystemPrompt } = require('../prompts/system');
const sys = buildSystemPrompt({ provider, model });
sysTok = estimateTokens(sys);
} catch { /* skip */ }

const total = historyTok + sysTok;
const pct = Math.min(100, Math.round(total / window * 100));
const bar = (() => {
const w = 20;
const filled = Math.round(pct / 100 * w);
return '█'.repeat(filled) + '░'.repeat(w - filled);
})();
const lines = [
`📊 Context usage — ${pct}%`,
`[${bar}] ${Math.round(total/1000)}K / ${Math.round(window/1000)}K tokens`,
``,
`• System prompt : ${Math.round(sysTok/1000)}K`,
`• History : ${Math.round(historyTok/1000)}K (${msgs.length} msgs)`,
`• Model : ${provider} / ${model}`,
Comment thread src/chat/session-store.js Outdated
const src = list.find(x => x.id === id);
if (!src) return null;
const clone = JSON.parse(JSON.stringify(src));
clone.id = `s_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
- media/chat.js: escape modelTxt and mode before innerHTML in openCtxPop (fix js/xss-through-dom, js/html-from-text)
- src/chat/session-store.js: use crypto.randomBytes for forked session id instead of Math.random (fix js/insecure-randomness; ids are not security-critical but the alert was tripping CI)
- src/chat/agent-loop.js: remove useless assignment to preflightTokens after nuclearCompact; next iteration recomputes it
- src/chat/compact.js: delete unused TOOL_RESULT_NUKE_HEAD/TAIL constants (nuclearCompact uses inline 800/200 values)
- src/chat/provider.js: drop unused sid binding in _handleContextCommand
@github-actions
Copy link
Copy Markdown

⚠️ PR 偏大:有效变更约 868 行(建议阈值 500 行)。

AI 审查在超大 diff 下质量会下降,建议:

  • 将无关改动拆分为独立 PR
  • 确保每个 PR 只聚焦一个功能或修复

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review by ChatGPT

Comment thread media/chat.js
}
var pop = document.createElement('div');
pop.className = 'ft-ctx-pop';
var pct = _lastCtx.pct|0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这个 hunk 中,新增的 _esc 函数用于对输入进行转义,以防止 XSS 攻击,这是一个良好的安全实践。然而,建议在使用 innerHTML 时,尽量避免直接插入 HTML 内容,考虑使用 textContent 或其他安全的 DOM 操作方法来避免潜在的安全风险。此外,建议对 modelTxt_curIMode 的来源进行更严格的验证,以确保它们确实是安全的。

Comment thread media/chat.js
'<div class="ft-ctx-pop-row"><span>Mode</span><b>' + _esc(_curIMode||'agent') + '</b></div>' +
'<div class="ft-ctx-pop-tip">' +
'<div><code>/context</code> — detailed token breakdown</div>' +
'<div><code>/compact [focus]</code> — summarise history</div>' +
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这里,使用 _esc 函数对 modelTxt_curIMode 进行了转义,这是必要的安全措施。然而,建议在构建 HTML 内容时,尽量使用更安全的方式,例如使用 createElementappendChild 方法来构建 DOM,而不是直接拼接字符串,这样可以进一步降低 XSS 攻击的风险。

Comment thread src/chat/agent-loop.js
}
}
if (ctxLimitHit) break; // break while loop — do not call the API
checkAbort();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这一段代码中,虽然注释说明了 preflightTokens 不会在此之后被重新读取,但没有提供足够的上下文来解释为什么这样做是安全的。建议添加更多的注释,说明在后续迭代中如何重新计算 preflightTokens,以避免潜在的逻辑错误或状态不一致。此外,考虑到可能的异常情况,建议在 checkAbort() 调用之前添加异常处理逻辑,以确保在出现异常时能够安全退出。

Comment thread src/chat/compact.js
// were never read — removed to satisfy CodeQL js/useless-assignment-to-local.

function _truncateBody(body, headKeep, tailKeep) {
const total = body.length;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在此代码段中,删除了 TOOL_RESULT_NUKE_HEADTOOL_RESULT_NUKE_TAIL 常量,虽然注释提到这些常量未被使用,但需要确认在其他地方是否有依赖于这些常量的逻辑。如果这些常量在未来的功能扩展中可能会被用到,建议保留。此外,删除未使用的代码时,最好进行全面的代码审查,以确保没有潜在的影响。

Comment thread src/chat/provider.js
const { estimateMessagesTokens, estimateTokens } = require('./compact');
const run = this._activeRun();
const cfg = vscode.workspace.getConfiguration('deepseekAgent');
const provider = cfg.get('provider') || 'deepseek';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在这一段代码中,删除了对 sid 的定义,但没有看到后续代码中对 sid 的使用情况。如果 sid 是后续逻辑中必需的变量,删除它可能导致空指针异常或逻辑错误。请确认 sid 是否在其他地方被使用,或者如果不再需要,确保相关逻辑已被妥善处理。

Comment thread src/chat/session-store.js
clone.id = `s_${Date.now().toString(36)}${_rand4}`;
clone.title = String(title || `${src.title || 'Fork'} (fork)`).slice(0, 80);
clone.createdAt = Date.now();
clone.updatedAt = Date.now();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在生成 session ID 的过程中,使用 Math.random() 可能导致 ID 的安全性不足。虽然你已经尝试使用 crypto.randomBytes 来增强随机性,但在 catch 块中没有处理异常,可能会导致 _rand4 仍然是默认的 '0000'。建议在 catch 中添加日志记录,以便在 node:crypto 不可用时进行调试。此外,生成 session ID 的逻辑应确保唯一性和不可预测性,考虑使用 crypto.randomUUID() 来生成更安全的 ID。

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Comment thread src/chat/agent-loop.js Outdated
const callId = `synthetic_skill_read_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
messages.push({
role: 'assistant',
hrole: 'assistant',
Comment thread src/chat/agent-loop.js
Comment on lines +334 to +337
// render a real-time usage bar. Cheap to compute since the
// estimator was just run inside autoCompactIfNeeded above.
try {
const ctxTokens = estimateMessagesTokens([{ role: 'system', content: sysPrompt }, ...run.messages]);
Comment thread media/chat.js
Comment on lines +206 to +213
function updateCtxRing(pct, tokens, win){
_lastCtx = { tokens: tokens||0, window: win||0, pct: pct||0 };
if (!ftCtxRing || !ftCtxPct) return;
var p = Math.max(0, Math.min(100, Number(pct)||0));
// circumference ≈ 2πr = 2*π*8 ≈ 50.265
var C = 50.265;
ftCtxRing.setAttribute('stroke-dashoffset', String(C * (1 - p/100)));
ftCtxRing.setAttribute('stroke', p > 85 ? '#e57373' : (p > 65 ? '#ffb74d' : '#66bb6a'));
Comment thread src/chat/provider.js Outdated
Comment on lines +733 to +736
// Issue #142 P3-4: `/context` status report. Breaks down current context
// usage into system / history / tool-def buckets so the user can decide
// whether to /compact or /fork.
async _handleContextCommand() {
Comment thread src/chat/provider.js
Comment on lines +784 to +786
// Issue #142 P3-5: `/fork [title]` clones the current session under a new
// id so the user can experiment without polluting the original thread.
async _handleForkCommand(title) {
Comment thread src/chat/session-store.js Outdated
Comment on lines +277 to +278
// Use crypto.randomUUID for session id rather than Math.random to satisfy
// CodeQL js/insecure-randomness, though session ids are not security-critical.
Comment thread src/chat/session-store.js Outdated
const _crypto = require('crypto');
_rand4 = _crypto.randomBytes(2).toString('hex');
} catch { /* fallback only if node:crypto unavailable */ }
clone.id = `s_${Date.now().toString(36)}${_rand4}`;
Comment thread src/chat/compact.js
Comment on lines +240 to +243
return {
...m,
content: `[deduped — this ${meta.name} of "${meta.key.split('::')[1]}" was re-read later in the conversation; see the later tool result for current contents]`,
};
Comment thread src/chat/agent-loop.js
Comment on lines +450 to +454
const includeMcpTools = vscode.workspace
.getConfiguration('deepseekAgent')
.get('includeMcpTools', true);
const mcpDefs = includeMcpTools ? mcpManager.getToolDefs() : [];
const allTools = getToolDefs(mcpDefs);
…D comment

- agent-loop.js: hrole -> role in synthetic skill-read assistant message; adapters check msg.role so hrole was silently ignored, breaking skill injection (Copilot review feedback)
- session-store.js: update comment to say randomBytes (not randomUUID) to match the actual implementation
@github-actions
Copy link
Copy Markdown

⚠️ PR 偏大:有效变更约 866 行(建议阈值 500 行)。

AI 审查在超大 diff 下质量会下降,建议:

  • 将无关改动拆分为独立 PR
  • 确保每个 PR 只聚焦一个功能或修复

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Comment thread src/tools/file-read.js Outdated
if (fileSize > 50 * 1024) {
const kb = Math.round(fileSize / 1024);
const hint = `\n\n[hint] this file is ${kb} KB — consider \`spawn_agent\` (agent_type=explore) for analysis, or \`read_file\` with start_line/end_line to read a focused range, to save context.`;
return truncate(text) + hint;
Comment thread src/chat/provider.js
Comment on lines +642 to +650
setTimeout(() => {
// Guard: the active session may have changed again during the
// 0-ms delay (rapid clicking). In that case the events are still
// buffered on `run.events`, so the next _loadSession(id) for this
// session will replay them; we just no-op here.
if (run.sessionId !== this._store.sessionId) return;
this._post({ type: 'replayStart', count: evs.length });
for (const ev of evs) this._post(ev);
this._post({ type: 'replayEnd' });
Comment thread src/chat/provider.js Outdated
Comment on lines +733 to +736
// Issue #142 P3-4: `/context` status report. Breaks down current context
// usage into system / history / tool-def buckets so the user can decide
// whether to /compact or /fork.
async _handleContextCommand() {
Comment thread media/chat.js
Comment on lines +210 to +214
// circumference ≈ 2πr = 2*π*8 ≈ 50.265
var C = 50.265;
ftCtxRing.setAttribute('stroke-dashoffset', String(C * (1 - p/100)));
ftCtxRing.setAttribute('stroke', p > 85 ? '#e57373' : (p > 65 ? '#ffb74d' : '#66bb6a'));
ftCtxPct.textContent = (p|0) + '%';
Comment thread src/chat/compact.js
Comment on lines +240 to +243
return {
...m,
content: `[deduped — this ${meta.name} of "${meta.key.split('::')[1]}" was re-read later in the conversation; see the later tool result for current contents]`,
};
- provider.js (_loadSession): post replayStart immediately, before the
  setTimeout, so live streamDelta events arriving during the 0-ms delay
  are also suppressed by webview _replaying flag; close envelope on
  session-switch no-op to avoid leaving webview stuck in replay-suppress
  mode (fixes #143 edge case)
- file-read.js: reserve hint length in truncate budget so medium-large
  file output + hint never exceeds MAX_OUTPUT_CHARS
- compact.js (grep_search dedup): use greedy regex so Windows
  drive-letter paths like C:\foo\bar.js:12: dedup correctly
- compact.js (read-dedup placeholder): emit structured
  <name path=... read-collapsed=true/> tag matching PR description
- session-store.js (fork): use s_<ts>_<rand> shape with underscore
  separator, consistent with ensure()
- provider.js (/context comment): clarify that the breakdown is
  system+history only; tool definitions are not included
@github-actions
Copy link
Copy Markdown

⚠️ PR 偏大:有效变更约 891 行(建议阈值 500 行)。

AI 审查在超大 diff 下质量会下降,建议:

  • 将无关改动拆分为独立 PR
  • 确保每个 PR 只聚焦一个功能或修复

@ZhouChaunge ZhouChaunge merged commit 5e58e0b into main May 24, 2026
17 checks passed
@ZhouChaunge ZhouChaunge deleted the feat/context-window-and-flash-fix branch May 24, 2026 12:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants