Skip to content

fix(core): auto-compact subagent context to prevent overflow#3735

Merged
tanzhenxin merged 4 commits into
mainfrom
fix/3664-subagent-context-compaction
May 6, 2026
Merged

fix(core): auto-compact subagent context to prevent overflow#3735
tanzhenxin merged 4 commits into
mainfrom
fix/3664-subagent-context-compaction

Conversation

@tanzhenxin

@tanzhenxin tanzhenxin commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • What changed: subagent chats now auto-compact at the configured threshold, the same way the main agent has always done.
  • Why it changed: long multi-turn subagent runs (e.g., the Explore subagent on smaller-context models) grew history past the model limit and 400'd with maximum context length exceeded instead of compacting first.
  • Reviewer focus: compaction now lives in the chat layer so both main agent and subagent share one trigger; the eager pre-call in the main session loop was removed to avoid duplication, and the manual /compress reset path is unchanged.

Validation

  • Prompts used: Use the Explore subagent to map out the project structure. (subagent path) and Search this repo and report what you find. (main-agent control).
  • Expected: subagent compresses at threshold instead of 400-ing; main agent compaction unchanged.
  • Observed:
Test Pre-fix Post-fix
Subagent compression calls 0 665
Subagent rounds before 400 5 (~32 884 tokens) none — ran until session ended naturally
Main agent compression calls n/a 772 (alternating with sends, expected)
  • Reviewer verification: launch a long-running Explore task against a small-context model and watch it run past the previous failure point.

Known Limitations

Two trade-offs reviewers should be aware of — both are intentional, not oversights:

  1. sessionTokenLimit gate ordering. The gate now reads the previous turn's prompt count instead of the post-compaction count, so a session that sat just over the limit may trip one turn earlier than before. Acceptable because the feature is slated for removal; not worth re-introducing the eager compression pre-call in the main session loop just to preserve it.
  2. No first-send compaction for subagents with oversized inherited history. A subagent's per-chat token counter starts at 0, so the first send doesn't trigger compaction even when the inherited parent history is already over the model limit. Subsequent sends compact normally once the first response populates the counter. We deliberately did not seed the counter from the parent: the plumbing would touch fork/speculation/btw paths that don't need compaction at all, and the worst case (first-send overflow) is rare in practice — most parents that big have already compacted themselves.

Scope / Risk

  • Breaking changes: none.
  • Coverage: main-agent compaction (control) and subagent compaction (the bug) verified end-to-end against the documented mock-server reproduction.

Testing Matrix

🍏 🪟 🐧
npm run ⚠️ ⚠️
npx ⚠️ ⚠️ ⚠️
Docker ⚠️ ⚠️ ⚠️
Podman ⚠️ N/A N/A
Seatbelt ⚠️ N/A N/A

Verified macOS via npm run build && npm run bundle and the headless e2e plan above; other platforms unchanged.

Linked Issues / Bugs

Closes #3664

Subagent chats accumulated history without ever compacting, so a long
multi-turn run could hit "max context length exceeded" before the
compaction logic the main session uses had a chance to fire.

Move compaction down into the chat layer so both main agent and subagent
auto-compress at the configured threshold, and surface the result via a
new chat stream event that bridges into the existing ChatCompressed UI
path. The main-session wrapper still owns full /compress reset.

Closes #3664
@tanzhenxin

Copy link
Copy Markdown
Collaborator Author

E2E Test Report

Ran the plan at knowledge/qwen-code/e2e-tests/issue-3664-subagent-context-overflow.md against the bundled fix (node dist/cli.js) using the documented mock server. Subagent path is the bug; main agent path is the control verifying the refactor didn't regress existing compaction.

Test 1 — Subagent path (the bug)

Prompt: Use the Explore subagent to map out the project structure.
Knobs: MOCK_CTX_LIMIT=30000, FILLER_CHARS=20000.

Metric Pre-fix Post-fix
Compression calls (isCompression:true) 0 665
Total mock requests 385 1335
Subagent 400 rejections 1 (round 5, ~32 884 tokens) 0
Outcome 400 from mock, retry loop session ended naturally (mock closed)

Compression first fires on round 5 (~27–28k tokens against the 30k limit), then continues throughout the run as the subagent keeps adding filler. Decisive contrast vs. pre-fix.

Test 2 — Main agent path (control)

Prompt: Search this repo and report what you find.
Knobs: MOCK_CTX_LIMIT=30000, FILLER_CHARS=3000, FORCE_FILLER=1, contextPercentageThreshold=0.05 in ~/.qwen/settings.json.

Metric Post-fix
Compression calls 772
Sends over threshold without intervening compaction 0
Pattern strict alternation: send (over threshold) → compress → send (over) → compress …

Mock-log excerpt (input tokens / isCompression):

Entry inputTokens isCompression
1 21 197 false
2 969 true
3 21 972 false
4 906 true
5 22 811 false
6 23 649 false
7 1 745 true

Behavior matches pre-refactor: every time inputTokens crosses the threshold, the very next request is a compression call.

Verdict

Both paths pass. The fix delivers compaction for subagents end-to-end and preserves the main-agent compaction behavior unchanged.

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 55.35% 55.35% 70.82% 79.45%
Core 76.46% 76.46% 78.85% 82.07%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   55.35 |    79.45 |   70.82 |   55.35 |                   
 src               |   67.99 |    62.34 |   74.19 |   67.99 |                   
  gemini.tsx       |   59.52 |    58.88 |   66.66 |   59.52 | ...62,770-773,781 
  ...ractiveCli.ts |   69.53 |    57.42 |   72.72 |   69.53 | ...21-768,776-783 
  ...liCommands.ts |   73.92 |     72.5 |     100 |   73.92 | ...40-264,289,389 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |    46.3 |    63.01 |   55.88 |    46.3 |                   
  acpAgent.ts      |   48.12 |    63.38 |   62.06 |   48.12 | ...91-793,807-815 
  authMethods.ts   |   12.19 |      100 |       0 |   12.19 | 11-31,34-38,41-50 
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   74.77 |    68.36 |    82.6 |   74.77 |                   
  ...ryReplayer.ts |   64.83 |    72.97 |   81.81 |   64.83 | ...68-269,277-278 
  Session.ts       |   73.52 |    66.12 |   82.92 |   73.52 | ...2322,2328-2331 
  ...entTracker.ts |   90.85 |    84.84 |      90 |   90.85 | ...35,199,251-260 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    77.77 |     100 |   84.21 | ...37-153,209-211 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |    95.9 |    90.43 |    92.3 |    95.9 |                   
  BaseEmitter.ts   |   76.92 |    66.66 |      80 |   76.92 | 23-24,39-40,55-56 
  ...ageEmitter.ts |     100 |    89.47 |     100 |     100 | 109,111           
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   97.96 |     91.8 |     100 |   97.96 | 226-227,316,324   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   89.69 |    85.89 |   94.11 |   89.69 |                   
  LlmRewriter.ts   |   80.53 |    79.31 |     100 |   80.53 | ...17-119,170-174 
  ...Middleware.ts |   95.83 |    85.71 |     100 |   95.83 | 119,127-129       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/commands      |   62.18 |      100 |    9.52 |   62.18 |                   
  auth.ts          |   46.91 |      100 |       0 |   46.91 | ...,91-98,101-102 
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   94.73 |      100 |      50 |   94.73 | 28                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
 src/commands/auth |   66.16 |    79.82 |   78.94 |   66.16 |                   
  handler.ts       |   47.07 |    74.68 |   35.29 |   47.07 | ...-968,1058-1068 
  ...veSelector.ts |     100 |    96.66 |     100 |     100 | 58                
  ...outerOAuth.ts |   89.02 |    78.99 |   96.87 |   89.02 | ...18-622,716-718 
 ...mmands/channel |    39.2 |    79.45 |      50 |    39.2 |                   
  ...l-registry.ts |    8.57 |      100 |       0 |    8.57 | 6-21,24-42        
  config-utils.ts  |   91.89 |      100 |   66.66 |   91.89 | 20-25             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   31.15 |       52 |   69.23 |   31.15 | ...73-476,485-487 
  status.ts        |   17.54 |      100 |       0 |   17.54 | 15-26,32-77       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   84.53 |    88.95 |   81.81 |   84.53 |                   
  consent.ts       |   71.65 |    89.28 |   42.85 |   71.65 | ...85-141,156-162 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |    75.6 |    66.66 |   66.66 |    75.6 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   60.24 |    28.57 |     100 |   60.24 | ...81,83-87,89-93 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 src/commands/mcp  |   92.29 |    86.08 |   88.88 |   92.29 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  list.ts          |   91.22 |    80.76 |      80 |   91.22 | ...19-121,146-147 
  reconnect.ts     |   76.72 |    71.42 |   85.71 |   76.72 | 35-48,153-175     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |   92.04 |    82.54 |   84.72 |   92.04 |                   
  auth.ts          |   87.87 |    81.35 |     100 |   87.87 | ...20-221,237-238 
  config.ts        |   86.36 |    82.53 |   72.72 |   86.36 | ...1339,1361-1362 
  keyBindings.ts   |   95.95 |       50 |     100 |   95.95 | 160-163           
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |    58.9 |    61.53 |   66.66 |    58.9 | ...54-68,73,77-89 
  settings.ts      |   83.13 |    82.55 |   85.71 |   83.13 | ...35-936,941-944 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.29 |       94 |     100 |   96.29 | ...88-190,205-206 
 ...nfig/migration |   94.56 |    78.94 |   83.33 |   94.56 |                   
  index.ts         |   93.93 |    88.88 |     100 |   93.93 | 85-86             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   93.63 |     94.5 |     100 |   93.63 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
 src/constants     |   11.97 |     87.5 |   16.66 |   11.97 |                   
  ...dardApiKey.ts |     100 |      100 |     100 |     100 |                   
  codingPlan.ts    |    8.75 |     87.5 |   16.66 |    8.75 | ...22-327,335-347 
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   63.09 |    64.51 |   55.55 |   63.09 |                   
  ...tputBridge.ts |   62.94 |    65.51 |   56.25 |   62.94 | ...22-323,331-334 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   48.26 |    76.19 |   38.88 |   48.26 |                   
  index.ts         |   26.92 |    76.92 |   26.66 |   26.92 | ...38-239,249-260 
  languages.ts     |    98.7 |       75 |     100 |    98.7 | 110               
 src/i18n/locales  |       0 |        0 |       0 |       0 |                   
  ca.js            |       0 |        0 |       0 |       0 | 1-2146            
  de.js            |       0 |        0 |       0 |       0 | 1-2069            
  en.js            |       0 |        0 |       0 |       0 | 1-2119            
  fr.js            |       0 |        0 |       0 |       0 | 1-2102            
  ja.js            |       0 |        0 |       0 |       0 | 1-1560            
  pt.js            |       0 |        0 |       0 |       0 | 1-2060            
  ru.js            |       0 |        0 |       0 |       0 | 1-2065            
  zh-TW.js         |       0 |        0 |       0 |       0 | 1-1681            
  zh.js            |       0 |        0 |       0 |       0 | 1-1920            
 ...nonInteractive |   72.67 |    72.14 |   74.07 |   72.67 |                   
  session.ts       |   76.86 |    70.45 |   85.71 |   76.86 | ...78-779,787-797 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...80-581,584-585 
 ...active/control |   77.55 |    88.23 |      80 |   77.55 |                   
  ...rolContext.ts |    7.69 |        0 |       0 |    7.69 | 47-79             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |        0 |       0 |       8 | 46-179            
 ...ol/controllers |    7.04 |       80 |   13.33 |    7.04 |                   
  ...Controller.ts |   19.32 |      100 |      60 |   19.32 | 81-118,127-210    
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    3.96 |      100 |   11.11 |    3.96 | ...61-379,389-494 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    5.21 |      100 |       0 |    5.21 | ...21-433,442-471 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   97.59 |    93.06 |   95.18 |   97.59 |                   
  ...putAdapter.ts |   97.33 |    91.89 |   98.07 |   97.33 | ...1343,1368-1369 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.28 |      100 |      90 |   98.28 | 81-82,122-123     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/services      |   90.37 |    89.75 |   94.28 |   90.37 |                   
  ...mandLoader.ts |     100 |     92.3 |     100 |     100 | 89                
  ...killLoader.ts |     100 |    96.29 |     100 |     100 | 44                
  ...andService.ts |    93.5 |      100 |      80 |    93.5 | 107,150-153       
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.32 |    80.64 |   83.33 |   75.32 | ...05-206,272-273 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...nd-factory.ts |      91 |     90.9 |     100 |      91 | 123,132-139       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  commandUtils.ts  |      96 |       90 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   85.95 |    86.42 |   90.47 |   85.95 |                   
  DataProcessor.ts |   85.68 |    86.46 |   92.85 |   85.68 | ...1110,1114-1121 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   92.38 |    84.12 |     100 |   92.38 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |    78.3 |    71.42 |     100 |    78.3 | ...33-148,151,160 
  tipRegistry.ts   |     100 |    95.23 |     100 |     100 | 33                
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/test-utils    |   93.75 |    83.33 |      80 |   93.75 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   63.21 |    68.42 |   51.28 |   63.21 |                   
  App.tsx          |     100 |      100 |     100 |     100 |                   
  AppContainer.tsx |   65.87 |    62.67 |   66.66 |   65.87 | ...2279,2283-2287 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |   52.72 |      100 |   23.52 |   52.72 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   91.83 |       90 |     100 |   91.83 | 25-26,54-55       
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   53.26 |    65.51 |      68 |   53.26 |                   
  AuthDialog.tsx   |   67.75 |    64.95 |    65.9 |   67.75 | ...1271,1273,1275 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  useAuth.ts       |    34.3 |    70.37 |     100 |    34.3 | ...14-920,922-937 
 src/ui/commands   |   59.85 |    77.91 |   60.78 |   59.85 |                   
  aboutCommand.ts  |     100 |    85.71 |     100 |     100 | 36                
  agentsCommand.ts |   72.97 |      100 |      20 |   72.97 | ...32,37-38,42-44 
  ...odeCommand.ts |     100 |      100 |     100 |     100 |                   
  arenaCommand.ts  |   33.13 |    67.64 |    37.5 |   33.13 | ...60-565,644-649 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   95.59 |    71.42 |     100 |   95.59 | 72,154-159        
  bugCommand.ts    |   77.35 |    66.66 |      50 |   77.35 | 21-22,60-69       
  clearCommand.ts  |   90.58 |    73.68 |      50 |   90.58 | ...46,74-75,93-94 
  ...essCommand.ts |   63.39 |       48 |      50 |   63.39 | ...48-149,163-166 
  ...extCommand.ts |    6.17 |      100 |      10 |    6.17 | ...21-522,527-528 
  copyCommand.ts   |     100 |      100 |     100 |     100 |                   
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  ...ryCommand.tsx |   66.11 |    76.74 |   55.55 |   66.11 | ...05-306,315-323 
  docsCommand.ts   |   96.07 |     87.5 |      50 |   96.07 | 20-21             
  doctorCommand.ts |     100 |    93.33 |     100 |     100 | 21                
  dreamCommand.ts  |      75 |    66.66 |   66.66 |      75 | 22-27,44-47       
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   56.93 |    91.66 |   33.33 |   56.93 | ...52-353,361-362 
  ...onsCommand.ts |   45.08 |    85.71 |   27.27 |   45.08 | ...37-238,247-248 
  forgetCommand.ts |   26.82 |      100 |      50 |   26.82 | 18-51             
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   19.04 |       25 |      20 |   19.04 | ...86-187,204-205 
  ideCommand.ts    |   57.33 |    57.69 |   35.29 |   57.33 | ...05-306,310-324 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |    72.8 |    66.66 |   83.33 |    72.8 | ...31-245,250-273 
  ...ageCommand.ts |   89.39 |    82.35 |   76.92 |   89.39 | ...22-325,348-349 
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  mcpCommand.ts    |   86.66 |      100 |      50 |   86.66 | 14-15             
  memoryCommand.ts |   86.66 |      100 |      50 |   86.66 | 14-15             
  modelCommand.ts  |   42.19 |       65 |      50 |   42.19 | ...35-168,175-193 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |   93.93 |      100 |      50 |   93.93 | 15-16             
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.61 |    78.18 |     100 |   85.61 | ...15-322,329-334 
  ...oreCommand.ts |    92.3 |     87.5 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   15.04 |      100 |      25 |   15.04 | ...90-106,109-136 
  statsCommand.ts  |   83.91 |    81.25 |      50 |   83.91 | ...31-132,142-145 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.51 |      100 |      50 |    6.51 | 28-323            
  tasksCommand.ts  |   77.45 |    73.43 |     100 |   77.45 | ...55-159,181-186 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |   95.23 |      100 |      50 |   95.23 | 18-19             
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
 src/ui/components |    59.4 |    73.36 |   61.53 |    59.4 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |   18.91 |      100 |       0 |   18.91 | 30-95             
  AppHeader.tsx    |   86.79 |    42.85 |     100 |   86.79 | 32-38,40          
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   14.63 |      100 |       0 |   14.63 | 18-56             
  ...TextInput.tsx |   67.83 |    72.09 |      50 |   67.83 | ...30-232,250,259 
  Composer.tsx     |   79.31 |    57.14 |     100 |   79.31 | ...-77,95,133,146 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |    12.4 |      100 |       0 |    12.4 | 61-457            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   79.67 |    58.06 |     100 |   79.67 | ...98-102,104-108 
  ...ngSpinner.tsx |   54.28 |       50 |      50 |   54.28 | 31-48,61          
  Header.tsx       |   98.14 |    85.71 |     100 |   98.14 | 97,99             
  Help.tsx         |   98.74 |    68.75 |     100 |   98.74 | 74,129            
  ...emDisplay.tsx |   62.55 |     37.5 |     100 |   62.55 | ...17-326,329,332 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   81.63 |    76.68 |   83.33 |   81.63 | ...1339,1404,1454 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |    91.42 |     100 |     100 | 65,74             
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   57.66 |    54.54 |     100 |   57.66 | ...89-200,209-223 
  ...elsDialog.tsx |   16.07 |    89.18 |      50 |   16.07 | ...58-159,162-648 
  MemoryDialog.tsx |   53.35 |    51.21 |   57.14 |   53.35 | ...55,367,380-382 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   76.59 |    54.54 |     100 |   76.59 | ...60-476,533-537 
  ...tsDisplay.tsx |     100 |    96.96 |     100 |     100 | 234               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   88.14 |    83.87 |     100 |   88.14 | ...01-105,133-138 
  PrepareLabel.tsx |   91.66 |    76.19 |     100 |   91.66 | 73-75,77-79,110   
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |    4.45 |      100 |       0 |    4.45 | 28-92,100-328     
  ...ionPicker.tsx |   94.76 |    87.17 |     100 |   94.76 | 99,132,253-261    
  ...onPreview.tsx |   91.73 |    78.26 |     100 |   91.73 | ...,70-71,126-128 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...ngsDialog.tsx |   66.88 |    73.52 |     100 |   66.88 | ...11-819,825-826 
  ...ionDialog.tsx |    87.8 |      100 |   33.33 |    87.8 | 36-39,44-51       
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...yTodoList.tsx |   94.17 |       80 |     100 |   94.17 | 56-57,131-134     
  ...nsDisplay.tsx |   84.09 |    57.14 |     100 |   84.09 | ...16-118,125-127 
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   21.87 |      100 |       0 |   21.87 | 22-40,43-53       
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
 ...nts/agent-view |    25.2 |       90 |      10 |    25.2 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |    9.95 |      100 |       0 |    9.95 | 57-308            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    8.13 |      100 |       0 |    8.13 | 39-59,64-187      
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.72 |    70.53 |   60.86 |   45.72 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |   10.15 |      100 |       0 |   10.15 | 27-161            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |    70.1 |     77.6 |   77.77 |    70.1 |                   
  ...sksDialog.tsx |   70.03 |    76.33 |   71.42 |   70.03 | ...1003,1067-1069 
  ...TasksPill.tsx |   70.83 |    86.95 |     100 |   70.83 | 44,77-89,97-105   
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.77 |    94.23 |   66.66 |   54.77 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 17-128            
  ...nListStep.tsx |   88.35 |    94.73 |      80 |   88.35 | 51-52,58-71,105   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   72.24 |    70.52 |      80 |   72.24 |                   
  ...etailStep.tsx |   96.52 |       75 |     100 |   96.52 | 33,37,50,59       
  ...etailStep.tsx |   93.27 |    73.68 |     100 |   93.27 | 41-42,99-104,110  
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   36.09 |    47.05 |      50 |   36.09 | ...49,453-466,470 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |    20.2 |    84.61 |   81.81 |    20.2 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.64 |      100 |       0 |    3.64 | 41-717            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   96.42 |    87.09 |     100 |   96.42 | 21,96-97          
 ...ents/mcp/steps |    6.65 |      100 |       0 |    6.65 |                   
  ...icateStep.tsx |     5.1 |      100 |       0 |     5.1 | 34-95,98-334      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |    5.88 |      100 |       0 |    5.88 | 20-176            
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |    7.14 |      100 |       0 |    7.14 | 16-146            
 ...nents/messages |   79.51 |    79.39 |   69.84 |   79.51 |                   
  ...ionDialog.tsx |   77.35 |    74.54 |    62.5 |   77.35 | ...90,508,526-528 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.33 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   77.35 |      100 |      70 |   77.35 | ...31-244,248-260 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   12.82 |      100 |       0 |   12.82 | 22-59             
  ...onMessage.tsx |   73.55 |    55.81 |   33.33 |   73.55 | ...41-443,450-452 
  ...upMessage.tsx |   76.76 |    82.08 |     100 |   76.76 | ...15-242,264-279 
  ToolMessage.tsx  |   90.16 |     83.8 |   91.66 |   90.16 | ...62-567,594-596 
 ...ponents/shared |    82.5 |    77.29 |   92.64 |    82.5 |                   
  ...ctionList.tsx |   99.03 |    95.65 |     100 |   99.03 | 85                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |    6.29 |      100 |       0 |    6.29 | 35-42,45-176      
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  TextInput.tsx    |   74.84 |    57.14 |      75 |   74.84 | ...90-194,206-212 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  text-buffer.ts   |   83.62 |    75.62 |   97.61 |   83.62 | ...2272,2300,2368 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...ents/subagents |   32.77 |    33.33 |    12.5 |   32.77 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   13.69 |    33.33 |   16.66 |   13.69 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |    8.39 |      100 |       0 |    8.39 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |    2.29 |      100 |       0 |    2.29 | 28-449            
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...agents/runtime |   81.76 |    58.24 |   92.85 |   81.76 |                   
  ...onDisplay.tsx |   81.76 |    58.24 |   92.85 |   81.76 | ...14-716,719-722 
 ...mponents/views |   42.16 |    69.23 |   21.42 |   42.16 |                   
  ContextUsage.tsx |     4.7 |      100 |       0 |     4.7 | ...52-167,170-456 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   76.84 |    78.03 |   84.31 |   76.84 |                   
  ...ewContext.tsx |   65.77 |      100 |      75 |   65.77 | ...22-225,231-241 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.37 |    68.57 |      50 |   93.37 | ...94-195,222-226 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   81.88 |    82.26 |     100 |   81.88 | ...1153,1159-1161 
  ...owContext.tsx |   89.28 |       80 |   66.66 |   89.28 | 34,47-48,60-62    
  ...onContext.tsx |   43.28 |     62.5 |    62.5 |   43.28 | ...56-259,263-266 
  ...gsContext.tsx |   83.33 |       50 |     100 |   83.33 | 17-18             
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 145-146           
  ...teContext.tsx |   85.71 |       50 |     100 |   85.71 | 175-176           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |    80.8 |    81.36 |   85.56 |    80.8 |                   
  ...dProcessor.ts |   83.12 |    82.56 |     100 |   83.12 | ...88-389,408-435 
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |    94.8 |    70.58 |     100 |    94.8 | ...76-277,282-283 
  ...dProcessor.ts |   72.73 |    56.77 |   61.53 |   72.73 | ...78,802,821-825 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-158            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   19.81 |    66.66 |      25 |   19.81 | 57-175            
  ...Completion.ts |   92.77 |    89.09 |     100 |   92.77 | ...86-187,220-223 
  ...ifications.ts |   92.07 |    96.29 |     100 |   92.07 | 116-124           
  ...tIndicator.ts |     100 |    93.75 |     100 |     100 | 63                
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   94.11 |    76.92 |     100 |   94.11 | 119-123,216,222   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...lanUpdates.ts |     100 |       92 |     100 |     100 | 59,158            
  ...ompletion.tsx |   91.28 |    79.59 |     100 |   91.28 | ...20-221,259-269 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   76.92 |       50 |     100 |   76.92 | 55,68,71-75,88-96 
  ...eteCommand.ts |   33.33 |       50 |     100 |   33.33 | 30,34,41-90       
  ...ialogClose.ts |   18.18 |      100 |     100 |   18.18 | 75-130            
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |     97.7 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |   54.88 |       50 |   33.33 |   54.88 | ...71-173,195-196 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   67.46 |       90 |      50 |   67.46 | ...09-130,149-150 
  ...miniStream.ts |   75.84 |    72.89 |   91.66 |   75.84 | ...2293,2306-2314 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   93.15 |    93.75 |     100 |   93.15 | 44,107-110        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   70.58 |       75 |      50 |   70.58 | 42-47,59-62       
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   84.52 |    93.33 |     100 |   84.52 | ...27-232,328-338 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   97.24 |    76.92 |     100 |   97.24 | 104-105,145       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.96 |    95.69 |     100 |   96.96 | ...82-183,237-240 
  ...sionPicker.ts |   90.23 |    71.69 |     100 |   90.23 | ...78-279,283-284 
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |   78.99 |    81.48 |   94.11 |   78.99 | ...77-579,587-624 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |     100 |    98.79 |     100 |     100 | 257               
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...tification.ts |     100 |    85.71 |     100 |     100 | 47                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   89.51 |    86.95 |     100 |   89.51 |                   
  ...AppLayout.tsx |   89.53 |    86.66 |     100 |   89.53 | 50-52,92-97       
  ...AppLayout.tsx |   89.47 |     87.5 |     100 |   89.47 | 58-63             
 ...i/manageModels |   93.61 |       48 |     100 |   93.61 |                   
  manageModels.ts  |   93.61 |       48 |     100 |   93.61 | ...63-166,179,209 
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |    7.14 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    7.14 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.53 |    70.31 |     100 |   98.53 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |     100 |      100 |     100 |     100 |                   
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.45 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   76.98 |    86.27 |   85.51 |   76.98 |                   
  ...Colorizer.tsx |   82.78 |    88.23 |     100 |   82.78 | ...10-111,197-223 
  ...nRenderer.tsx |   52.41 |    36.36 |      50 |   52.41 | ...49-151,171-180 
  ...wnDisplay.tsx |   86.79 |    88.88 |     100 |   86.79 | ...06-315,348-373 
  ...eRenderer.tsx |   94.45 |    81.25 |   94.11 |   94.45 | ...65,477,480-483 
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |   83.95 |    88.88 |    87.5 |   83.95 | ...50-151,247-266 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.27 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |   98.63 |       95 |     100 |   98.63 | 93                
  ...oryMapping.ts |     100 |    94.28 |     100 |     100 | 33,55             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |    98.3 |    95.65 |     100 |    98.3 | 48-49             
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   57.81 |    67.14 |      90 |   57.81 | ...64,412,417-439 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   96.47 |    93.18 |   91.66 |   96.47 | ...46-247,382-383 
  todoSnapshot.ts  |   89.11 |    93.18 |     100 |   89.11 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |    2.36 |        0 |       0 |    2.36 |                   
  collect.ts       |    0.87 |        0 |       0 |    0.87 | 40-394,401-697    
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |     1.2 |      100 |       0 |     1.2 | 17-346            
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   73.68 |    89.56 |   94.52 |   73.68 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.52 |    97.05 |     100 |   96.52 | 166-169           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   85.29 |    89.47 |     100 |   85.29 | 48-57             
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   68.59 |    64.28 |     100 |   68.59 | ...63-269,293-309 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   94.28 |    88.46 |     100 |   94.28 | 28-29,125-126     
  errors.ts        |   98.63 |    96.15 |     100 |   98.63 | 67-68             
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |   90.76 |    93.33 |   88.88 |   90.76 | 103-114           
  ...lationInfo.ts |     100 |      100 |     100 |     100 |                   
  languageUtils.ts |   97.89 |    96.42 |     100 |   97.89 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.79 |    93.28 |     100 |   96.79 | ...76-477,575,588 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   98.07 |    76.92 |     100 |   98.07 | 70                
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-980             
  settingsUtils.ts |   86.32 |    90.59 |   94.44 |   86.32 | ...38,569,632-644 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |     100 |    95.83 |     100 |     100 | 110               
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   92.52 |     90.9 |   83.33 |   92.52 | 63-69,184         
  ...InfoFields.ts |   86.91 |    65.78 |     100 |   86.91 | ...16-117,138-139 
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |    62.1 |    77.77 |     100 |    62.1 | 93,107,118-157    
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   76.46 |    82.07 |   78.85 |   76.46 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |    83.5 |    75.49 |   88.15 |    83.5 |                   
  ...transcript.ts |   88.76 |    75.43 |     100 |   88.76 | ...82,306-307,434 
  ...ent-resume.ts |   78.75 |       70 |      75 |   78.75 | ...78-982,985-987 
  ...ound-tasks.ts |   91.83 |    85.18 |      96 |   91.83 | ...51-552,569-570 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |    76.9 |    66.66 |   78.94 |    76.9 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.84 |     62.9 |   78.57 |   75.84 | ...1889,1895-1896 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    73.46 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |    76.3 |    86.23 |   72.41 |    76.3 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.06 |     90.9 |   82.35 |   91.06 | ...51-271,330,430 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   79.81 |    75.21 |      66 |   79.81 |                   
  agent-core.ts    |   73.97 |    69.03 |   48.48 |   73.97 | ...1299,1326-1372 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   79.09 |    69.76 |   52.38 |   79.09 | ...78-379,382-383 
  ...nteractive.ts |   79.71 |    79.62 |      75 |   79.71 | ...54,456,458,461 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   74.26 |     75.8 |   60.77 |   74.26 |                   
  config.ts        |   71.86 |    72.91 |    55.1 |   71.86 | ...2888,2892-2904 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.72 |     93.1 |   91.66 |   95.72 | ...06-207,241-242 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/constants     |    4.95 |      100 |       0 |    4.95 |                   
  codingPlan.ts    |    4.95 |      100 |       0 |    4.95 | ...79-291,299-309 
 src/core          |   82.61 |    82.28 |   87.91 |   82.61 |                   
  baseLlmClient.ts |   96.77 |    96.42 |      80 |   96.77 | 123-126           
  client.ts        |   77.17 |    77.88 |    86.2 |   77.17 | ...1264,1268-1284 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...63,365,372-375 
  ...lScheduler.ts |   76.75 |    80.91 |   92.68 |   76.75 | ...2191,2243-2247 
  geminiChat.ts    |   88.73 |    84.23 |   83.33 |   88.73 | ...1113,1180-1181 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   82.25 |    81.81 |     100 |   82.25 | ...57-361,407-421 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   85.71 |    70.58 |     100 |   85.71 | ...90-191,205-214 
  ...issionFlow.ts |   98.59 |    94.73 |     100 |   98.59 | 93                
  prompts.ts       |    88.8 |    88.05 |      75 |    88.8 | ...-898,1101-1102 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...okTriggers.ts |   99.31 |    91.02 |     100 |   99.31 | 124,135           
  turn.ts          |   96.42 |    88.88 |     100 |   96.42 | ...00,413-414,462 
 ...ntentGenerator |    94.6 |    79.35 |   92.68 |    94.6 |                   
  ...tGenerator.ts |   96.49 |    79.35 |      90 |   96.49 | ...24,481,637,693 
  converter.ts     |   94.38 |    79.78 |     100 |   94.38 | ...40-541,551,734 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   91.08 |    76.14 |   85.71 |   91.08 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   91.04 |    76.14 |   85.71 |   91.04 | ...23,533-534,562 
 ...ntentGenerator |   79.48 |    83.73 |   89.47 |   79.48 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   74.92 |    80.85 |   86.95 |   74.92 | ...1410,1431-1437 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   43.85 |    14.28 |      50 |   43.85 | ...,87-91,102-103 
  ...tGenerator.ts |   48.78 |    91.66 |   77.77 |   48.78 | ...10-163,166-167 
  pipeline.ts      |   93.62 |    84.76 |     100 |   93.62 | ...78-479,487,547 
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   90.66 |     88.4 |     100 |   90.66 | ...15-319,349-350 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.67 |    89.74 |   94.87 |   96.67 |                   
  dashscope.ts     |   97.22 |    87.69 |   93.33 |   97.22 | ...10-211,287-288 
  deepseek.ts      |   95.55 |    90.56 |     100 |   95.55 | ...31-132,145-146 
  default.ts       |   94.62 |    86.36 |   85.71 |   94.62 | 85-86,156-158     
  index.ts         |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/extension     |   60.62 |    79.43 |   79.03 |   60.62 |                   
  ...-converter.ts |   62.35 |    47.82 |      90 |   62.35 | ...90-791,800-832 
  ...ionManager.ts |   46.92 |    82.19 |   67.44 |   46.92 | ...1386,1396-1415 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   44.94 |    88.52 |      60 |   44.94 | ...53-359,398-451 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.29 |    93.75 |     100 |   97.29 | ...64,184-185,274 
  npm.ts           |   48.66 |    76.08 |      75 |   48.66 | ...18-420,427-431 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-108,143-149    
  storage.ts       |   94.73 |       90 |     100 |   94.73 | 41-42             
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   46.35 |     92.3 |   71.87 |   46.35 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   95.06 |       84 |     100 |   95.06 | 78,108,122,133    
  speculation.ts   |   13.22 |      100 |   16.66 |   13.22 | 88-458,518-568    
  ...onToolGate.ts |     100 |    96.29 |     100 |     100 | 93                
  ...nGenerator.ts |   36.67 |    95.12 |   33.33 |   36.67 | ...24-326,361-391 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/hooks         |    80.6 |    84.37 |   84.16 |    80.6 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.37 |    90.54 |     100 |   96.37 | ...89,291-292,365 
  ...entHandler.ts |   95.58 |    84.37 |   92.59 |   95.58 | ...29,682-683,693 
  hookPlanner.ts   |   84.13 |    76.59 |      90 |   84.13 | ...38,144,162-173 
  hookRegistry.ts  |   88.83 |    86.36 |     100 |   88.83 | ...21,326,330,334 
  hookRunner.ts    |   53.63 |    72.22 |   61.11 |   53.63 | ...23-724,733-734 
  hookSystem.ts    |   75.47 |      100 |   56.41 |   75.47 | ...75-576,582-583 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |    96.5 |     91.8 |     100 |    96.5 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   90.15 |    91.02 |   85.18 |   90.15 | ...91-392,452-456 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   74.28 |    83.39 |   78.33 |   74.28 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |    64.2 |    81.48 |   66.66 |    64.2 | ...9-970,999-1007 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   33.92 |    45.16 |   45.76 |   33.92 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |    4.29 |      100 |       0 |    4.29 | ...20-371,377-394 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   13.52 |    81.25 |   29.16 |   13.52 | ...75-694,700-730 
  ...eLspClient.ts |   17.89 |      100 |       0 |   17.89 | ...37-244,254-258 
  ...LspService.ts |   45.87 |    62.13 |   66.66 |   45.87 | ...1282,1299-1309 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.69 |    75.34 |   75.92 |   78.69 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.62 |    97.72 |     100 |   98.62 | 87-88             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |    95.83 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.48 |    86.66 |   86.36 |   79.48 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.75 |    82.35 |   92.85 |   82.75 | ...62-172,180-181 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   61.53 |    75.06 |   65.77 |   61.53 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |   65.65 |    73.33 |      50 |   65.65 | 50,107-148        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   59.84 |       70 |      50 |   59.84 | ...72-180,183-189 
  extract.ts       |    95.2 |    79.16 |     100 |    95.2 | 81-86,125         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |    8.04 |      100 |       0 |    8.04 | 67-342            
  governance.ts    |       0 |        0 |       0 |       0 | 1-352             
  indexer.ts       |   83.87 |    45.45 |     100 |   83.87 | ...50,56-57,69-70 
  manager.ts       |   73.32 |    78.94 |   74.35 |   73.32 | ...1163,1176-1178 
  memoryAge.ts     |   80.95 |     87.5 |      75 |   80.95 | 48-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,88-89,105-113 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  recall.ts        |   79.56 |    69.38 |   88.88 |   79.56 | ...40-245,269-280 
  ...ceSelector.ts |   91.86 |    77.27 |     100 |   91.86 | ...04,106-107,115 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   94.44 |    83.33 |     100 |   94.44 | 56-57,92-93       
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.49 |    85.58 |   87.14 |   89.49 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   88.67 |     90.9 |     100 |   88.67 | 112,118,121-130   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.63 |    92.53 |     100 |   98.63 | 161,323,329       
  modelRegistry.ts |     100 |    98.21 |     100 |     100 | 182               
  modelsConfig.ts  |   85.37 |    83.54 |   81.57 |   85.37 | ...1210,1239-1240 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/output        |     100 |      100 |     100 |     100 |                   
  ...-formatter.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/permissions   |   71.18 |    88.73 |   48.57 |   71.18 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   81.42 |    86.66 |      80 |   81.42 | ...19-820,827-836 
  rule-parser.ts   |   95.99 |    93.18 |     100 |   95.99 | ...-864,1013-1015 
  ...-semantics.ts |   58.28 |    85.27 |    30.2 |   58.28 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/qwen          |   86.03 |    79.48 |   97.18 |   86.03 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   85.01 |    74.81 |   93.33 |   85.01 | ...,986-1002,1032 
  ...kenManager.ts |   83.79 |    76.22 |     100 |   83.79 | ...63-768,789-794 
 src/services      |   84.46 |    83.94 |   88.33 |   84.46 |                   
  ...llRegistry.ts |   97.82 |    94.73 |     100 |   97.82 | 172-173           
  ...ionService.ts |   95.42 |       94 |     100 |   95.42 | ...79,336,338-342 
  ...ingService.ts |   72.04 |    78.88 |   73.07 |   72.04 | ...35-936,953-954 
  cronScheduler.ts |   97.56 |    92.98 |     100 |   97.56 | 62-63,77,155      
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   89.76 |     85.1 |   88.88 |   89.76 | ...89,191,266-273 
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |   71.83 |    68.47 |    91.3 |   71.83 | ...89-790,806,822 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...orRegistry.ts |   96.76 |    92.15 |     100 |   96.76 | ...95-396,449-450 
  sessionRecap.ts  |   10.71 |      100 |       0 |   10.71 | 48-161            
  ...ionService.ts |   85.48 |    71.62 |      96 |   85.48 | ...73-983,987-988 
  sessionTitle.ts  |   93.95 |    70.37 |     100 |   93.95 | ...36-239,270-271 
  ...ionService.ts |   83.96 |    80.97 |   83.78 |   83.96 | ...1029,1035-1040 
  ...UseSummary.ts |    94.7 |    88.67 |     100 |    94.7 | ...69-171,221-222 
 ...icrocompaction |   98.62 |    86.44 |     100 |   98.62 |                   
  microcompact.ts  |   98.62 |    86.44 |     100 |   98.62 | 138,142           
 src/skills        |    86.7 |    83.88 |   93.61 |    86.7 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |   89.72 |    80.76 |     100 |   89.72 | ...28,248,260-262 
  skill-manager.ts |   82.68 |    79.32 |   90.32 |   82.68 | ...1135,1142-1146 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   82.65 |    79.74 |   91.11 |   82.65 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   76.48 |    71.42 |   87.09 |   76.48 | ...1129,1151-1152 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 51-56,69-74,78-83 
 src/telemetry     |   70.05 |       83 |   75.11 |   70.05 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   91.28 |    83.67 |   92.85 |   91.28 | ...66-171,186-187 
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |    51.9 |       64 |   57.77 |    51.9 | ...1214,1231-1251 
  metrics.ts       |    74.9 |    82.95 |   74.54 |    74.9 | ...58-978,981-992 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   88.97 |    77.77 |     100 |   88.97 | ...80-281,300-304 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |   79.09 |    85.59 |   83.33 |   79.09 | ...1134,1137-1166 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...ry/qwen-logger |   68.01 |    80.21 |   64.91 |   68.01 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.01 |       80 |   64.28 |   68.01 | ...1042,1080-1081 
 src/test-utils    |   93.07 |    95.55 |   73.52 |   93.07 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.02 |    96.77 |   68.96 |   91.02 | ...32,196-197,210 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   76.52 |    80.56 |   81.28 |   76.52 |                   
  ...erQuestion.ts |    88.8 |    76.74 |    90.9 |    88.8 | ...36-337,344-345 
  cron-create.ts   |   97.61 |    88.88 |   83.33 |   97.61 | 30-31             
  cron-delete.ts   |   96.55 |      100 |   83.33 |   96.55 | 26-27             
  cron-list.ts     |   96.36 |      100 |   83.33 |   96.36 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   80.83 |    84.09 |   73.33 |   80.83 | ...28-529,616-666 
  exitPlanMode.ts  |   84.61 |    85.71 |     100 |   84.61 | ...60-163,177-189 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.19 |    85.71 |   78.94 |   79.19 | ...20,560,569-576 
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.69 |    60.09 |   90.32 |   72.69 | ...1208,1210-1211 
  ...nt-manager.ts |   52.09 |     65.9 |   47.36 |   52.09 | ...02-520,523-560 
  mcp-client.ts    |   29.65 |    71.05 |   46.87 |   29.65 | ...1434,1438-1441 
  mcp-tool.ts      |   90.92 |    88.88 |   96.42 |   90.92 | ...89-590,640-641 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-48              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   92.16 |    83.45 |      92 |   92.16 | ...15,544-547,560 
  read-file.ts     |   93.28 |    89.33 |      90 |   93.28 | ...99,240,262-271 
  ripGrep.ts       |   94.59 |    85.71 |   93.33 |   94.59 | ...60,463,541-542 
  ...-transport.ts |    6.34 |        0 |       0 |    6.34 | 47-145            
  send-message.ts  |   88.77 |    91.66 |   83.33 |   88.77 | 44-45,68-76       
  shell.ts         |   81.42 |    80.74 |    90.9 |   81.42 | ...1243,1292-1298 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   88.11 |    91.17 |   84.61 |   88.11 | ...95,399,422-444 
  task-stop.ts     |   92.94 |    96.15 |   85.71 |   92.94 | 39-40,54-64       
  todoWrite.ts     |   85.42 |    84.09 |   84.61 |   85.42 | ...05-410,432-433 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   67.49 |    68.91 |   65.71 |   67.49 | ...59-660,668-669 
  tools.ts         |    87.6 |    89.79 |   88.23 |    87.6 | ...31-432,448-454 
  web-fetch.ts     |   88.44 |    76.92 |    92.3 |   88.44 | ...05-306,308-309 
  write-file.ts    |   83.04 |    76.27 |   83.33 |   83.04 | ...28-431,443-478 
 src/tools/agent   |   82.17 |    82.96 |      80 |   82.17 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent.ts         |   82.23 |    83.04 |   78.78 |   82.23 | ...1306,1355-1359 
  fork-subagent.ts |   78.26 |    71.42 |      80 |   78.26 | 54-72,104-105     
 src/utils         |   87.27 |    87.27 |    91.7 |   87.27 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   76.08 |    44.44 |     100 |   76.08 | 61-70,72          
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |   42.85 |    23.07 |     100 |   42.85 | 26-31,33-45,47-54 
  cronParser.ts    |   89.74 |    85.71 |     100 |   89.74 | ...,63-64,183-186 
  debugLogger.ts   |   96.12 |    93.75 |   93.75 |   96.12 | 164-168           
  editHelper.ts    |   92.67 |    82.14 |     100 |   92.67 | ...52-454,463-464 
  editor.ts        |   97.61 |    95.71 |     100 |   97.61 | ...70-271,273-274 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |    95.45 |     100 |     100 | 83                
  errorParsing.ts  |    97.7 |    96.87 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.92 |    80.39 |   53.33 |   70.92 | ...03-219,223-229 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |   89.08 |    85.06 |   94.73 |   89.08 | ...68-875,879-885 
  forkedAgent.ts   |   62.98 |    54.54 |      75 |   62.98 | ...23-432,434-447 
  formatters.ts    |   54.54 |       50 |     100 |   54.54 | 12-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   38.88 |    84.61 |      50 |   38.88 | ...2,51-74,97-148 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 26                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   59.57 |    89.74 |   45.45 |   59.57 | ...53-286,292-298 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...yDiscovery.ts |   83.85 |    79.36 |     100 |   83.85 | ...15,318,410-413 
  ...tProcessor.ts |   93.63 |       90 |     100 |   93.63 | ...96-302,384-385 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  ...kerChecker.ts |   82.55 |    78.57 |     100 |   82.55 | 68-69,79-84,92-98 
  notebook.ts      |   94.35 |    84.78 |     100 |   94.35 | ...10,122,174-176 
  openaiLogger.ts  |   86.27 |    82.14 |     100 |   86.27 | ...05-107,130-135 
  partUtils.ts     |     100 |      100 |     100 |     100 |                   
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   92.82 |    91.02 |     100 |   92.82 | ...71-372,374-376 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  ...ectSummary.ts |   89.39 |    72.41 |     100 |   89.39 | ...37-142,193-196 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   91.48 |    94.11 |     100 |   91.48 | 80,93-95          
  readManyFiles.ts |   87.96 |    86.95 |     100 |   87.96 | ...05-207,223-234 
  retry.ts         |   89.81 |    88.05 |     100 |   89.81 | ...29,350,357-358 
  ripgrepUtils.ts  |   46.53 |    83.33 |   66.66 |   46.53 | ...32-233,245-322 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...tchOptions.ts |   63.85 |    64.28 |   83.33 |   63.85 | ...29-130,187-188 
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    87.87 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   93.43 |    77.04 |     100 |   93.43 | ...46,155-158,212 
  ...r-launcher.ts |   76.92 |     91.3 |   66.66 |   76.92 | ...34,136,157-195 
  ...orageUtils.ts |   92.41 |    82.82 |     100 |   92.41 | ...39,423-430,441 
  shell-utils.ts   |   82.93 |     89.5 |     100 |   82.93 | ...1522,1529-1533 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1059-1061,1071 
  ...nlyChecker.ts |   95.75 |    92.47 |     100 |   95.75 | ...00-301,313-314 
  sideQuery.ts     |     100 |    92.85 |     100 |     100 | 43                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  truncation.ts    |     100 |       92 |     100 |     100 | 52,71             
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   93.71 |    88.88 |   93.33 |   93.71 | ...24-225,249-251 
  xml.ts           |     100 |      100 |     100 |     100 |                   
  yaml-parser.ts   |      92 |    84.31 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   96.34 |    91.66 |     100 |   96.34 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   96.87 |    94.44 |     100 |   96.87 | 83-84             
  fileSearch.ts    |   93.29 |    86.76 |     100 |   93.29 | ...40-241,243-244 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   56.63 |    74.52 |   74.19 |   56.63 |                   
  ...eTokenizer.ts |   41.86 |    76.47 |   69.23 |   41.86 | ...70-443,453-507 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

For detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run.

@tanzhenxin

tanzhenxin commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator Author

E2E Test Summary — UI Compression Display

Goal: verify the on-screen compression UI is intact after moving auto-compaction into the chat layer.

Method: interactive (tmux) against the issue-3664 mock server. Threshold lowered to 0.05 via ~/.qwen/settings.json so compression fires after one turn. FORCE_FILLER=1 to grow the main agent's context.

# Path Trigger Expected UI Observed UI Result
A Auto-compaction (new path) Send a regular prompt; mock returns filler that pushes context over the 5% threshold Info bullet: ● IMPORTANT: This conversation approached the input token limit for {model}. A compressed context will be sent for future messages (compressed from: X to Y tokens). ● IMPORTANT: This conversation approached the input token limit for mock-model. A compressed context will be sent for future messages (compressed from: 24472 to 20509 tokens). ✅ PASS
B Manual /compress (control) Type /compress after chat has accumulated history Rich line with accent glyph: ✦ Chat history compressed from X to Y tokens. ✦ Chat history compressed from 24472 to 20509 tokens. ✅ PASS

Verdict: both UI surfaces display correctly. Token counts (24472 → 20509) propagate end-to-end through the new event chain. No visual regression introduced by the refactor.

Environment: macOS 25.3.0, Node v20.18.1

// GeminiChat already mutated its own history; surface to the debug
// log so subagent compactions show up alongside the main session's.
if (streamEvent.type === 'compressed') {
this.runtimeContext

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] Subagent lastPromptTokenCount never seeded — auto-compression silently skipped on first send.

GeminiChat.setLastPromptTokenCount() is designed for "chats created with inherited history (forks, subagents, speculation)" per its JSDoc, but createChat() never calls it. As a result lastPromptTokenCount defaults to 0, the threshold check 0 < threshold * contextWindow always passes, and tryCompress returns NOOP on the first sendMessageStream. For fork subagents with large inherited history, the first API call can 400.

This debug log (the only subagent compression surface) will never fire because compression never triggers. AgentCore already tracks lastPromptTokenCount (field at L216); seed it in createChat():

Suggested change
this.runtimeContext
// In createChat(), after `new GeminiChat(...)` returns:
chat.setLastPromptTokenCount(this.lastPromptTokenCount);
return chat;

— deepseek-v4-pro via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 3239bbecreateChat now seeds the new chat with this.lastPromptTokenCount so the threshold gate sees the inherited size on first send. Agreed the realistic blast radius is small (the 40-entry truncation in forkedAgent.ts defangs the fork case in practice), but a one-line seed is cheap insurance against future call sites that pass large extraHistory/initialMessages.

// Re-enable auto-compaction so a forced /compress recovers a chat
// that an earlier auto-attempt latched off.
this.hasFailedCompressionAttempt = false;
} else if (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] COMPRESSION_FAILED_TOKEN_COUNT_ERROR missing from else-if — hasFailedCompressionAttempt never set, causing infinite retry.

The else-if chain checks for FAILED_INFLATED_TOKEN_COUNT and FAILED_EMPTY_SUMMARY but omits FAILED_TOKEN_COUNT_ERROR. When a token counting error occurs, the sticky hasFailedCompressionAttempt flag is never set, so every subsequent sendMessageStream wastes an API call retrying compression that will never succeed. No log or event is emitted either.

Suggested change
} else if (
} else if (
info.compressionStatus ===
CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT ||
info.compressionStatus ===
CompressionStatus.COMPRESSION_FAILED_EMPTY_SUMMARY ||
info.compressionStatus ===
CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR
) {

— deepseek-v4-pro via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 3239bbe — added COMPRESSION_FAILED_TOKEN_COUNT_ERROR to the else-if so token-counting failures now latch hasFailedCompressionAttempt and stop retrying compression every send.

Comment thread packages/core/src/core/turn.ts Outdated
// Surface auto-compaction that fired inside the chat stream as the
// top-level ChatCompressed event so existing UI handlers stay
// connected. GeminiClient.sendMessageStream typically runs the
// compression pass earlier and emits this event itself; this branch

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] Turn.run() compressed → ChatCompressed event bridge has zero test coverage.

This is the sole path for auto-compression events to surface from the chat layer to the client layer. If the bridge breaks (e.g., type mismatch after rename), sendMessageStream never receives ChatCompressed, forceFullIdeContext is never flipped, and IDE context is lost after auto-compress. turn.test.ts should cover this:

Suggested change
// compression pass earlier and emits this event itself; this branch
// In turn.test.ts: construct a StreamEvent with type 'compressed',
// verify run() yields GeminiEventType.ChatCompressed with the same info payload.

— deepseek-v4-pro via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Test added in 3239bbeturn.test.ts now feeds a compressed StreamEvent through Turn.run() and asserts the yielded ChatCompressed event carries the same info payload.

// via the `compressed → ChatCompressed` bridge in turn.ts. Manual /compress
// still calls tryCompressChat directly for the full reset (env refresh +
// forceFullIdeContext flip).
const sessionTokenLimit = this.config.getSessionTokenLimit();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] sessionTokenLimit check now fires before auto-compression runs — behavioral regression.

The old code called tryCompressChat first, then checked sessionTokenLimit with the (potentially reduced) post-compression count. The new code checks the limit at L726 before the Turn starts; auto-compression only happens later inside chat.sendMessageStream(). If the context grew past the session limit on the previous turn, the new code terminates the session immediately, whereas the old code would have attempted compression first and might have reduced the context below the limit.

Suggested change
const sessionTokenLimit = this.config.getSessionTokenLimit();
// Auto-compaction happens inside GeminiChat.sendMessageStream and surfaces
// via the `compressed → ChatCompressed` bridge in turn.ts. Manual /compress
// still calls tryCompressChat directly for the full reset (env refresh +
// forceFullIdeContext flip).
//
// NOTE: sessionTokenLimit check moved after Turn completes so that
// auto-compression inside sendMessageStream has a chance to reduce
// the token count before we decide to terminate the session.

The check should be moved to after the Turn's stream is fully consumed (after the for await loop in sendMessageStream), or a pre-turn compression attempt should be added before the limit check.

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Acknowledged trade-off — the PR description calls this out: sessionTokenLimit is being deprecated in favor of the auto-compaction path, so reading the pre-compaction count here is intentional. In the new model, auto-compaction lives inside chat.sendMessageStream and runs during the Turn, not as a pre-call gate; the sessionTokenLimit check is best-effort safety for the legacy code path. Leaving as-is.

// immediately after this event still triggers the finally below;
// otherwise `streamDoneResolver` never fires and the next send hangs.
if (
compressionInfo.compressionStatus === CompressionStatus.COMPRESSED

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] COMPRESSED stream event emission has zero test coverage.

This yield is the sole path for auto-compression results to propagate from the chat layer to callers. The old client.test.ts tests for ChatCompressed events (deleted in this diff) had no replacement added. If this yield path breaks (e.g., compressionInfo checked before tryCompress resolves, or generator short-circuits), the main agent UI won't display compression feedback and subagents won't see the debug log in agent-core.ts:547.

// Suggested test in geminiChat.test.ts:
// Mock ChatCompressionService.prototype.compress to return COMPRESSED,
// call sendMessageStream, consume stream events, and assert the first
// event has type === StreamEventType.COMPRESSED with correct info payload.

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Test added in 3239bbegeminiChat.test.ts now mocks ChatCompressionService.compress to return COMPRESSED, runs chat.sendMessageStream, consumes the stream, and asserts the first event has type === StreamEventType.COMPRESSED with the expected info payload.

this.hasFailedCompressionAttempt = true;
}
const compressedHistory = this.getChat().getHistory();
await this.startChat(compressedHistory);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] getFileReadCache().clear() call silently lost — reverts the fix from PR (3717).

PR (3717) added this.config.getFileReadCache().clear() to the old tryCompressChat after startChat to prevent stale file_unchanged placeholders after compression. This rewrite (based on an earlier merge base) never included it, and the new auto-compression path in GeminiChat.tryCompress() (L396-404) also has no cache clearing. After compression, FileReadCache retains entries for files whose content was summarized away — subsequent ReadFile hits the cache and returns stale file_unchanged pointing at content the model can no longer retrieve.

Suggested change
await this.startChat(compressedHistory);
await this.startChat(compressedHistory);
this.config.getFileReadCache()?.clear();
this.getChat().setLastPromptTokenCount(info.newTokenCount);

The same fix is needed in geminiChat.ts tryCompress after this.setHistory(newHistory) at L401.

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch — the clear was lost during the merge resolution from main. Restored in 3239bbe at both sites:

  • client.tryCompressChat: clears after startChat(compressedHistory). Note that startChat constructs a fresh GeminiChat and does NOT route through client.setHistory (which would also clear), so the explicit clear here is necessary.
  • GeminiChat.tryCompress: clears after this.setHistory(newHistory). The chat-layer setHistory is a plain history assignment — only the GeminiClient wrapper clears the cache — so this path also needs the explicit clear.

Both paths now log [FILE_READ_CACHE] clear so it shows up in debug traces.

}
});

it('NOOPs when the keep slice has too few tool rounds to absorb', async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Test "NOOPs when the keep slice has too few tool rounds to absorb" exits at the threshold gate — never reaches findCompressSplitPoint.

The test sets originalTokenCount=20000 with contextWindowSize=30000. Since 20000 < 0.7 * 30000 = 21000, the threshold check at compress() L203 returns NOOP before reaching findCompressSplitPoint or MIN_COMPRESSION_FRACTION. The test passes for the wrong reason.

Suggested change
it('NOOPs when the keep slice has too few tool rounds to absorb', async () => {
// Raise originalTokenCount above the threshold so the test actually
// exercises the findCompressSplitPoint + MIN_COMPRESSION_FRACTION path:
const originalTokenCount = 22_000; // 22000 > 0.7 * 30000 = 21000

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 3239bbe — bumped originalTokenCount to 22000 (above the cheap-gate threshold of 0.7 × 30000 = 21000) so the test now exercises findCompressSplitPoint and the MIN_COMPRESSION_FRACTION decision instead of short-circuiting.


// Re-send a full IDE context blob on the next regular message — auto
// compaction inside chat.sendMessageStream may have summarized away
// the previous IDE-context turn.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] forceFullIdeContext flip on auto-compression path has no test.

The forceFullIdeContext = true flip on ChatCompressed at L866-867 only has tests for the manual /compress path (via tryCompressChat). The auto-compression path goes through the event loop here, but in tests tryCompressChat is mocked to NOOP so no ChatCompressed event is ever yielded through this path. A test should verify that when a ChatCompressed event flows through sendMessageStream, forceFullIdeContext becomes true.

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Test added in 3239bbeclient.test.ts now mocks Turn.run to yield a ChatCompressed event, runs sendMessageStream through to completion, and asserts forceFullIdeContext is true after the loop. Covers the auto-compaction path that the manual tryCompressChat tests missed.

info,
compressedHistory: newHistory,
});
this.setHistory(newHistory);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Auto-compression no longer refreshes environment context — setHistory replaces in-place without startChat.

The old auto-compression path called tryCompressChatstartChatgetInitialChatHistory() which prepended a fresh environment snapshot (file tree, git status, working directory). The new in-place setHistory at L401 does not call startChat, so environment context is lost into the compression summary (a lossy representation). The comment at client.ts:724 acknowledges this is intentional for the auto path, but it should be documented as an accepted trade-off in the code here.

— glm-5.1 via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Comment added in 03ed878 — pointer at the setHistory call site directs readers to GeminiClient for the env-refresh trade-off, so the layering decision is discoverable from geminiChat.ts without duplicating the rationale across files.

@wenshao

wenshao commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Overview

This PR moves automatic chat compaction from GeminiClient (the main session coordinator) down into GeminiChat.sendMessageStream. The motivation is that subagents (e.g., the Explore subagent) bypassed the compaction step entirely and would 400 with maximum context length exceeded once their per-run history grew. Now any chat — main agent or subagent — auto-compacts on the same threshold, surfaced via a new COMPRESSED stream event that bridges to the existing ChatCompressed UI event in turn.ts.

Additional collateral changes:

  • ChatCompressionService.compress switches from positional args to an options object and no longer reads/writes uiTelemetryService directly.
  • findCompressSplitPoint's in-flight fallback (last entry is model+functionCall) is rewritten to retain only the last N complete tool-round pairs plus the trailing call, biasing toward more compression.
  • A keepNeedsContinuationBridge user message is injected when the kept slice starts with model+functionCall, preserving role alternation.
  • hasFailedCompressionAttempt and lastPromptTokenCount move from GeminiClient onto GeminiChat itself.

Correctness

The split-point fallback rewrite is the riskiest part, and it is well-tested. splitPointRetainingTrailingPairs walks back two-at-a-time and stops cleanly on the first non-pair; the keepNeedsContinuationBridge flag correctly fires only when the kept slice starts with model, and the new test at chatCompressionService.test.ts:1726 verifies strict role alternation across the rebuilt history. Overall correctness story looks solid.

A few smaller things worth flagging:

  • Stale comment in turn.ts:309-313. The new comment says "GeminiClient.sendMessageStream typically runs the compression pass earlier and emits this event itself; this branch catches the case where the chat compressed without a pre-call." That is no longer true — the eager pre-call in client.ts was removed by this PR (client.ts:719), so this compressed → ChatCompressed bridge is now the primary path, not a fallback. Suggest rewording to make clear this is the path for auto-compaction emitted by chat.sendMessageStream.

  • Stream event order vs. IDE context block. In client.sendMessageStream, the IDE context block (client.ts:757-769) appends a user turn to the chat history before turn.run is invoked. Inside chat.sendMessageStream, tryCompress runs and may compress that just-appended IDE turn into the summary. The PR mitigates this by flipping forceFullIdeContext = true on ChatCompressed (client.ts:867-869), so the next turn re-sends. For the current turn the IDE block is summary-only — typically fine, but worth calling out in a comment near the IDE-block addition so future readers know the block can vanish mid-turn.

  • as StreamEvent cast in geminiChat.ts:503 is redundant — the literal { type: StreamEventType.COMPRESSED, info: compressionInfo } is already a member of the StreamEvent union as updated at geminiChat.ts:67. Drop the cast.

  • Pre-existing sendPromise leak unchanged. The new try/catch around tryCompress (geminiChat.ts:469-480) correctly releases the lock on a thrown compression. However, if a caller awaits sendMessageStream and never iterates the returned generator, the generator's finally (which resolves streamDoneResolver) never runs. This is pre-existing behavior, not introduced here, but worth noting that the new internal-state mutations in tryCompress (history, token count, fail-latch) now happen even if the caller abandons the generator. Probably fine; just be aware.

  • hasFailedCompressionAttempt reset semantics (geminiChat.ts:407-409) are fine but worth a closer look. The flag is cleared on a successful COMPRESSED. In normal operation the flag would already block auto-compaction at the cheap-gate (chatCompressionService.ts:187), so this branch only realistically clears the flag after a forced /compress succeeds — which is what the test at geminiChat.test.ts:1155 exercises. Effectively the same end-state as the old startChat-based reset. OK.

Code Quality / Style

  • The CompressOptions interface (chatCompressionService.ts:148-166) is a clear improvement over the old 7-positional signature, and the JSDoc on originalTokenCount and hasFailedCompressionAttempt is exactly the kind of "why" worth keeping.
  • The reorder of cheap gates in compress() to defer getHistory(true) (chatCompressionService.ts:186-227) is a sensible optimization, and the explicit comment explains it.
  • The two added per-chat fields (lastPromptTokenCount, hasFailedCompressionAttempt) on GeminiChat carry good docstrings explaining the per-chat-vs-global rationale.
  • The continuation-bridge text "Continue with the prior task using the context above." (chatCompressionService.ts:368) is hardcoded English. Minor — most agent prompts are English-coded — but worth a thought if the repo localizes any of these strings elsewhere.
  • splitPointRetainingTrailingPairs is a private helper that only handles the in-flight fallback; the name is fine but // Used by the splitter's in-flight fallback path. in the docstring is the actual reader-facing hint. Good.

Test Coverage

Strong overall:

  • New findCompressSplitPoint cases for the in-flight fallback (chatCompressionService.test.ts:1691-1772) cover 0/1/N pairs and retainCount overrides.
  • tool-loop subagent absorption (chatCompressionService.test.ts:1726-1832) verifies the full integration: split decision, summary, continuation bridge, role alternation, trailing fc preservation.
  • auto-compression integration in geminiChat.test.ts:1059-1232 covers the deadlock case (compression throws → lock released), the seeded-token-count path, and the latch-clearing semantics — all good.
  • tryCompressChat (delegation) in client.test.ts:145 cleanly tests the new wrapper without recreating the full compression machinery.

Test churn in chatCompressionService.test.ts is heavy because every existing call site migrates to the new options-object signature, but I didn't see tests removed without an equivalent — the deleted suites in client.test.ts (positional API + setup helper) move down into chatCompressionService.test.ts with the new shape.

Risks

  • Behavioral regression acknowledged in PR description: the sessionTokenLimit gate now reads pre-compaction prompt count (client.ts:728), so a session that sat just over the limit may trip one turn earlier than it did before. The PR justifies this by the feature being slated for removal — fine if that's still true, otherwise reconsider.
  • First-send overflow on forked/inherited subagents: lastPromptTokenCount = 0 on a freshly-constructed chat means the first auto-compaction gate sees 0 < threshold * contextLimit and NOOPs, even when the inherited history is already huge. Acknowledged in the PR description; for forks specifically the existing 40-entry truncation in forkedAgent.ts:138 defangs this in practice. Subagents constructed via agent-core.ts:320 only inherit env bootstrap unless the caller passes extraHistory/initialMessages, so the realistic blast radius is small.
  • Hooks now fire from subagent compactions too (chatCompressionService.ts:230-238, :439-467). PreCompact / PostCompact / SessionStart hooks were previously fired only from main-session compactions (since subagents bypassed compaction entirely). Hook authors that assumed "one compaction per main turn" will see more events. Worth a heads-up in release notes.
  • new ChatCompressionService() per tryCompress call (geminiChat.ts:385). Service is stateless, so this is harmless allocation, but a single shared instance would be cleaner. Trivial.

Summary

The fix correctly addresses the documented bug (subagent overflow) by relocating compaction to the layer that already owns the conversation state, with thoughtful handling of edge cases (in-flight tool calls, role alternation, send-lock leakage on compression failure, latch reset). Two small follow-ups worth taking before merging: refresh the stale comment in turn.ts:309-313 and drop the unnecessary as StreamEvent cast at geminiChat.ts:503. The known limitations are deliberate trade-offs and clearly documented. Overall this looks ready.

…text-compaction

# Conflicts:
#	packages/core/src/core/client.test.ts
#	packages/core/src/core/client.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overview

Moves the auto-compaction trigger from GeminiClient.sendMessageStream (main-agent only) into GeminiChat.sendMessageStream, so subagents — which use GeminiChat directly via AgentCore — get the same threshold-driven compaction as the main session. Adds a per-chat lastPromptTokenCount and hasFailedCompressionAttempt, switches ChatCompressionService.compress to a single options-object signature, and surfaces the new StreamEventType.COMPRESSED up through Turn to GeminiEventType.ChatCompressed so existing UI handlers stay wired. Also extends findCompressSplitPoint with an in-flight model+functionCall fallback that compresses-most rather than NOOPing when the trailing entry is an unmatched tool call (the dominant subagent-loop shape).


Issues

1. Bug — FileReadCache.clear() is dropped on both compaction paths (regression)

The pre-PR client.ts cleared the file-read cache after every successful compaction with this comment, which still applies:

Compaction rewrites the prompt history: prior full-Read tool results may have been summarised away, but the FileReadCache still believes those reads are "in this conversation". A follow-up Read could then return the file_unchanged placeholder pointing at content the model can no longer retrieve.

After the PR:

  • Manual /compress pathclient.ts:1397-1417 (tryCompressChat) no longer calls getFileReadCache().clear(). Neither does the new GeminiChat.tryCompress it now delegates to.
  • Auto-compaction path — the ChatCompressed event handler in client.ts:997-999 only flips forceFullIdeContext. Same gap.

Compare with surrounding code that does clear correctly: truncateHistory (client.ts:295), resetChat (client.ts:320), and microcompaction (client.ts:814 — its comment explicitly references "mirroring the post-compaction clear in tryCompressChat", which no longer exists). The same `file_unchanged`-pointing-at-summarized-bytes scenario the original comment described will reappear after every compaction, including the new auto-path you're enabling for subagents (where Read tools are common).

Suggested fix: clear the cache inside GeminiChat.tryCompress on COMPRESSED (centralizes for both main + subagent), or — if you'd rather not pull Config.getFileReadCache into the chat layer — add it to both client-side handlers (tryCompressChat after the startChat call, and the ChatCompressed event branch in the iterator).

2. Hard-coded English continuation bridge text

chatCompressionService.ts:355-364:

```ts
text: 'Continue with the prior task using the context above.',
```

When keepNeedsContinuationBridge is true, this synthetic user turn is injected into history. Other prompt strings in the surrounding compaction code (getCompressionPrompt, the 'Got it. Thanks…' ack) are equally hardcoded English, so this matches existing style — but it is a new model-visible synthetic instruction whose phrasing affects what the model thinks it was told to do. Worth at least a constant near the other compression strings, for the same reason COMPRESSION_TOKEN_THRESHOLD lives at the top of the file.

3. Scope creep — unrelated formatting churn

About 10 of 21 files are pure whitespace/formatting (docs/users/features/code-review.md, packages/cli/src/commands/review/*.ts, packages/core/src/skills/{skill-manager,symlinkScope}.{ts,test.ts}, monitorRegistry.ts). They have nothing to do with subagent compaction and bloat the review surface. Recommend splitting into a separate "prettier sweep" PR — keeps git blame clean and lets this PR be cherry-picked safely.


Minor

  • agent-core.ts:540-552 — the streamEvent.type === 'compressed' string-literal check works because StreamEventType.COMPRESSED = 'compressed', but the surrounding code in turn.ts:311 does the same check without importing the enum. Fine as-is, but inconsistent with the discriminated-union style elsewhere; using StreamEventType.COMPRESSED would survive an enum value rename.
  • Per-chat lastPromptTokenCount = 0 for subagents on first send — explicitly acknowledged in "Known Limitations" as accepted. Worth adding a TODO on GeminiChat.setLastPromptTokenCount pointing at the agent-core construction site so a future fix is discoverable.
  • tryCompress clears hasFailedCompressionAttempt = false on every successful COMPRESSED, including auto-compactions (geminiChat.ts:1791). The comment justifies this only for forced compactions ("a forced /compress recovers a chat that an earlier auto-attempt latched off"), but the code applies to both. That is actually the correct behavior — an auto-success means the state changed enough that a retry is now reasonable — but the comment undersells it.

Strengths

  • Send-lock release on tryCompress throw (geminiChat.ts:1819-1830) — exactly the kind of finicky bug that would deadlock production sessions weeks later. Test in geminiChat.test.ts:1369-1409 is a clear regression guard.
  • originalTokenCount is now an explicit parameter rather than a hidden global read — makes the service unit-testable per-chat and is the right abstraction for the subagent case.
  • In-flight fallback in findCompressSplitPoint — clean two-phase doc comment, the splitPointRetainingTrailingPairs helper is small and focused, and the four new test cases cover (default retain, fewer-than-retain, zero-pairs, override) thoroughly.
  • Test coveragechatCompressionService.test.ts adds the realistic "tool-loop subagent absorption" scenario including assertions on strict role alternation in the joined history; geminiChat.test.ts covers per-chat state in isolation from the service.

Risk Assessment

  • The FileReadCache regression is the only blocking concern — easy to fix but real (will cause stale-read confusion for users after every /compress or auto-compaction).
  • The sessionTokenLimit ordering shift is correctly called out as accepted; the feature is on its way out.
  • Subagent first-send overflow is a known and bounded edge case.
  • Manual /compress semantics are preserved (forced compaction still bypasses the failed-attempt latch and resets it on success).

tanzhenxin added 2 commits May 6, 2026 11:28
Code fixes:
- Seed `lastPromptTokenCount` on subagent chats so the first-send
  threshold gate sees the inherited history's true size.
- Add `COMPRESSION_FAILED_TOKEN_COUNT_ERROR` to the fail-latch chain
  so token-counting failures stop retrying compression every send.
- Restore `FileReadCache.clear()` after compaction in both the manual
  /compress wrapper and the auto-compaction path inside GeminiChat,
  preventing post-summary `file_unchanged` placeholders from pointing
  at content the model can no longer retrieve.
- Refresh stale comment on the `compressed → ChatCompressed` bridge
  in turn.ts now that this path is the primary route, not a fallback.

Tests:
- turn.test.ts asserts the compressed → ChatCompressed bridge.
- geminiChat.test.ts asserts COMPRESSED yields as the first stream
  event after auto-compaction succeeds.
- chatCompressionService.test.ts bumps originalTokenCount above the
  cheap-gate so the NOOP test exercises findCompressSplitPoint.
- client.test.ts asserts forceFullIdeContext flips when a
  ChatCompressed event flows through sendMessageStream's loop.
…tion trade-off

- Remove the `as StreamEvent` cast at the COMPRESSED yield site — the
  literal already matches the union member.
- Add a 4-line comment at the auto-compaction setHistory point that
  points readers to GeminiClient for the env-refresh trade-off rationale,
  so readers don't have to chase the layering decision back across files.
@tanzhenxin

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review @wenshao. Pushed two follow-up commits (3239bbe + 03ed878) addressing the points raised:

Code fixes

  • 🔴 FileReadCache.clear() was lost from the manual /compress path during the merge from main — restored, plus added the same clear in the auto-compaction path inside GeminiChat.tryCompress. Both sites log [FILE_READ_CACHE] clear for traceability.
  • 🔴 Subagent lastPromptTokenCount is now seeded in AgentCore.createChat so the threshold gate sees inherited history size on first send.
  • 🔴 COMPRESSION_FAILED_TOKEN_COUNT_ERROR added to the fail-latch else-if so token-counting failures stop retrying compression every send.
  • Refreshed the stale turn.ts:309-313 bridge comment — this path is now the primary route for auto-compaction events, not a fallback.
  • Dropped the redundant as StreamEvent cast at the COMPRESSED yield site.
  • Added a 4-line pointer comment at geminiChat.ts:401 directing readers to GeminiClient for the env-refresh trade-off rationale.

Test additions

  • turn.test.tscompressed → ChatCompressed bridge.
  • geminiChat.test.tsCOMPRESSED is yielded as the first stream event after auto-compaction.
  • client.test.tsforceFullIdeContext flips when ChatCompressed flows through sendMessageStream.
  • chatCompressionService.test.ts — bumped originalTokenCount above the cheap-gate so the NOOP test exercises findCompressSplitPoint rather than short-circuiting.

Acknowledged trade-offs (not changing)

  • sessionTokenLimit pre-compaction read at client.ts:849 — intentional. The limit is being deprecated in favor of auto-compaction, and the new model runs compaction during the Turn rather than as a pre-call gate.
  • The smaller items in your summary (IDE-block-vanishing FYI, sendPromise leak FYI, hooks-fire-from-subagents heads-up, per-call new ChatCompressionService) are observations rather than asks; happy to revisit if you'd like any of them turned into changes.

@wenshao

wenshao commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Code Review

Overview

The PR fixes #3664 by moving auto-compaction from GeminiClient.sendMessageStream (main-agent only) down into GeminiChat.sendMessageStream so subagent chats — which talk directly to GeminiChat — share the same trigger and stop 400'ing on oversized history. The compaction event is surfaced via a new StreamEventType.COMPRESSED and bridged in Turn to the existing ChatCompressed UI event. A per-chat token counter (getLastPromptTokenCount / setLastPromptTokenCount) decouples compaction decisions from the main-session telemetry singleton, and findCompressSplitPoint learns an in-flight-functionCall fallback so tool-loop-dominated histories actually compress instead of NOOPing.

Strengths

  • Architecturally correct: putting compaction at the chat layer is the natural fix; both call sites (main / subagent) now share one trigger, no duplication.
  • Send-lock safety: the catch around tryCompress manually fires streamDoneResolver so the lock doesn't leak. The releases the send-lock when auto-compression throws test pins this behavior.
  • Failed-attempt latch hardening: COMPRESSION_FAILED_TOKEN_COUNT_ERROR is now part of the latch chain (was missing before), and a successful forced compression clears the latch on the chat (hasFailedCompressionAttempt = false), so a recovered chat can auto-compact again.
  • Cheap-gate ordering in chatCompressionService.ts: threshold/latch checks now run before the curated-history clone, saving work on every steady-state send.
  • Test coverage: extensive — split-point fallback paths, tool-loop absorption, deadlock prevention, latch reset, telemetry mirroring with/without service. client.test.ts correctly shrunk because the logic moved.
  • Good comments where it matters: the in-flight fallback rationale, the env-refresh split between GeminiClient.tryCompressChat (manual) and GeminiChat.tryCompress (auto), and the "must be inside the try" note on the COMPRESSED yield are all genuinely useful.

Issues / Suggestions

Correctness

  • PR description "Known Limitation Where is the config saved? #2" is stale. The third commit (Seed lastPromptTokenCount on subagent chats…) actually fixes the first-send-overflow case for forks via agent-core.ts. The "we deliberately did not seed the counter" paragraph contradicts what the merged code does. Update the description before merge so reviewers/users aren't misled.
  • forceFullIdeContext is set in two places (the stream-bridge path inside sendMessageStream's for-await loop, and the manual /compress path inside tryCompressChat). That's intentional, but worth a comment noting the two paths are disjoint — a manual /compress does not surface a ChatCompressed event through sendMessageStream, so the manual flip is not redundant.
  • splitPointRetainingTrailingPairs returns contents.length - 1 when pairsFound = 0. That keeps only the trailing model+fc, forcing keepNeedsContinuationBridge = true. The synthetic Continue with the prior task using the context above. prompt is hardcoded English. Probably fine in practice (system prompt + rendered context are typically English too), but if the project ever localizes, this string is a candidate.

Scope / Noise

  • Unrelated reformatting noise. Roughly half the diff (packages/cli/src/commands/review/*.ts, monitorRegistry.ts, skill-manager.ts, symlinkScope.test.ts, docs/users/features/code-review.md, DESIGN.md, SKILL.md) is pure prettier reformatting that has nothing to do with subagent compaction. These should be split into a separate chore: prettier sweep PR — they make the real diff harder to review and inflate the line count substantially. Not blocking, but if it can be split before merge, please do.

Testing

  • The new tool-loop subagent absorption tests in chatCompressionService.test.ts are excellent — they exercise the exact subagent-shaped history that motivated the bug.
  • Consider adding one end-to-end-ish test (or a comment pointing at one) that exercises the full path from chat.sendMessageStream → tryCompress → COMPRESSED yield → Turn bridge → ChatCompressed. Right now each leg is tested individually, but a single "long subagent run compacts and continues" integration test would document the contract.

Minor

  • geminiChat.ts comment // Re-enable auto-compaction so a forced /compress recovers a chat that an earlier auto-attempt latched off. reads a bit oddly. The reset happens on any successful compression, not just forced. Suggest: // Clear the latch so a chat that recovered (any successful compression) can be auto-compacted again.
  • client.tryCompressChat and GeminiChat.tryCompress both clear FileReadCache after success. On the manual path that is two clears (auto-path clears via chat, manual-path clears again after startChat rebuilds). Not a correctness bug (clear is idempotent) but worth noting — could let the manual path skip its own clear if you want a single source of truth.
  • For fresh (non-fork) subagents the seed in agent-core.ts createChat is a no-op (parent's lastPromptTokenCount is 0). The seed is only load-bearing for forks; consider noting that in the comment.

Risk Assessment

  • Behavioral change: findCompressSplitPoint is now more aggressive when the trailing entry is in-flight. Pre-fix this returned lastSplitPoint (often 0 = NOOP); post-fix it compresses. This is intentional and tests are updated, but main-agent users on chats that happen to land mid-tool-call at threshold may see compaction one turn earlier than before. Acceptable for the fix.
  • Breaking-ish API change: ChatCompressionService.compress signature changed from positional → (chat, opts). Internal-only, but downstream forks/integrations would break.
  • sessionTokenLimit gate ordering: as noted in the PR description, the gate now reads pre-compaction count instead of post-compaction count. Acceptable trade-off given the feature is being removed.

Verdict

Solid fix for a real bug, with thoughtful architectural cleanup and good test coverage. Two requests before merge:

  1. Split out the prettier-only changes (review/*, docs, skill-manager.ts, symlinkScope.test.ts, monitorRegistry.ts) into a separate PR — the substantive change is buried under formatting noise.
  2. Update the "Known Limitations Where is the config saved? #2" in the PR description; the third commit makes that paragraph wrong.

Otherwise LGTM — the in-flight fallback design, the deadlock-safety dance, and the per-chat-counter decoupling are all the right calls.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Solid fix — moving compaction to the chat layer is the right call, the send-lock release on throw is well-covered, and the in-flight fallback in findCompressSplitPoint handles the subagent tool-loop case cleanly. Two non-blocking nits in the review comment (split out prettier noise, refresh the stale Known Limitation #2).

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: CI still running. New review with deepseek-v4-pro — builder focused on gaps not covered by the existing review comments.

Two new Suggestion-level findings below. No new Critical issues that aren't already captured in existing Qwen Code comments.

force = false,
signal?: AbortSignal,
): Promise<ChatCompressionInfo> {
const service = new ChatCompressionService();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] new ChatCompressionService() allocated on the hot path — every sendMessageStream call (main + subagent, every turn).

The service is stateless (single method, no instance fields), so this allocation is pure GC pressure. Consider making compress a static method or using a module-level singleton.

Suggested change
const service = new ChatCompressionService();
- const service = new ChatCompressionService();
- const { newHistory, info } = await service.compress(this, {
+ const { newHistory, info } = await ChatCompressionService.compress(this, {

— deepseek-v4-pro via Qwen Code /review

!lastContent?.parts?.some((part) => part.functionCall)
) {
return contents.length;
if (lastContent?.role === 'model') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] No debug logging when the new in-flight functionCall fallback triggers (splitPointRetainingTrailingPairs path).

The regular scan path also has no logging at the split decision point. This makes it impossible to distinguish at runtime which path was taken without instrumenting and redeploying — critical for debugging "model lost context" reports after compression.

Suggested change
if (lastContent?.role === 'model') {
const lastContent = contents[contents.length - 1];
if (lastContent?.role === 'model') {
if (!hasFunctionCall(lastContent)) return contents.length;
- return splitPointRetainingTrailingPairs(contents, retainCount);
+ const splitPoint = splitPointRetainingTrailingPairs(contents, retainCount);
+ debugLogger.debug(
+ `[COMPRESS-SPLIT] in-flight-fc fallback: splitPoint=${splitPoint}, total=${contents.length}`
+ );
+ return splitPoint;

— deepseek-v4-pro via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] ACP session now triggers double compression per turn.

packages/cli/src/acp-integration/session/Session.ts (#sendMessageStreamWithAutoCompression) calls geminiClient.tryCompressChat() before each turn AND then calls chat.sendMessageStream(), which now internally runs this.tryCompress after this PR. Each ACP turn gets two tryCompress calls — the first from the wrapper, the second from inside sendMessageStream. The second call usually NOOPs (token count already updated), but still incurs unnecessary CompressOptions allocation and threshold checks.

More subtly: if the first call succeeds via startChat (replacing the chat object), the second tryCompress runs on the new GeminiChat whose lastPromptTokenCount = 0 — so the threshold comparison uses the wrong value.

The CLI/TUI path removed its manual pre-call in this PR. Recommend the ACP path follow suit.

— deepseek-v4-pro via Qwen Code /review

@tanzhenxin tanzhenxin merged commit 8a1ed56 into main May 6, 2026
13 checks passed
DragonnZhang pushed a commit that referenced this pull request May 8, 2026
* fix(core): auto-compact subagent context to prevent overflow

Subagent chats accumulated history without ever compacting, so a long
multi-turn run could hit "max context length exceeded" before the
compaction logic the main session uses had a chance to fire.

Move compaction down into the chat layer so both main agent and subagent
auto-compress at the configured threshold, and surface the result via a
new chat stream event that bridges into the existing ChatCompressed UI
path. The main-session wrapper still owns full /compress reset.

Closes #3664

* fix(core): address subagent compaction review feedback

Code fixes:
- Seed `lastPromptTokenCount` on subagent chats so the first-send
  threshold gate sees the inherited history's true size.
- Add `COMPRESSION_FAILED_TOKEN_COUNT_ERROR` to the fail-latch chain
  so token-counting failures stop retrying compression every send.
- Restore `FileReadCache.clear()` after compaction in both the manual
  /compress wrapper and the auto-compaction path inside GeminiChat,
  preventing post-summary `file_unchanged` placeholders from pointing
  at content the model can no longer retrieve.
- Refresh stale comment on the `compressed → ChatCompressed` bridge
  in turn.ts now that this path is the primary route, not a fallback.

Tests:
- turn.test.ts asserts the compressed → ChatCompressed bridge.
- geminiChat.test.ts asserts COMPRESSED yields as the first stream
  event after auto-compaction succeeds.
- chatCompressionService.test.ts bumps originalTokenCount above the
  cheap-gate so the NOOP test exercises findCompressSplitPoint.
- client.test.ts asserts forceFullIdeContext flips when a
  ChatCompressed event flows through sendMessageStream's loop.

* chore(core): drop redundant StreamEvent cast and document auto-compaction trade-off

- Remove the `as StreamEvent` cast at the COMPRESSED yield site — the
  literal already matches the union member.
- Add a 4-line comment at the auto-compaction setHistory point that
  points readers to GeminiClient for the env-refresh trade-off rationale,
  so readers don't have to chase the layering decision back across files.
yiliang114 added a commit that referenced this pull request May 19, 2026
… auto-compaction redesign

- OOM reproduction report: root cause confirmed as structuredClone()
  positive feedback loop during auto-compaction (#3735, #3879), with
  real debug log evidence from crash session.
- Runtime diagnostics benchmark: process-tree RSS sampling results
  comparing installed CLI vs local rebuilt bundle.
- Auto-compaction threshold redesign: proposal for replacing the
  fixed 70% token threshold with RSS-aware graduated strategy.
yiliang114 added a commit that referenced this pull request May 20, 2026
… auto-compaction redesign

- OOM reproduction report: root cause confirmed as structuredClone()
  positive feedback loop during auto-compaction (#3735, #3879), with
  real debug log evidence from crash session.
- Runtime diagnostics benchmark: process-tree RSS sampling results
  comparing installed CLI vs local rebuilt bundle.
- Auto-compaction threshold redesign: proposal for replacing the
  fixed 70% token threshold with RSS-aware graduated strategy.
xaelistic pushed a commit to xaelistic/qwen-code that referenced this pull request Jun 7, 2026
…3735)

* fix(core): auto-compact subagent context to prevent overflow

Subagent chats accumulated history without ever compacting, so a long
multi-turn run could hit "max context length exceeded" before the
compaction logic the main session uses had a chance to fire.

Move compaction down into the chat layer so both main agent and subagent
auto-compress at the configured threshold, and surface the result via a
new chat stream event that bridges into the existing ChatCompressed UI
path. The main-session wrapper still owns full /compress reset.

Closes QwenLM#3664

* fix(core): address subagent compaction review feedback

Code fixes:
- Seed `lastPromptTokenCount` on subagent chats so the first-send
  threshold gate sees the inherited history's true size.
- Add `COMPRESSION_FAILED_TOKEN_COUNT_ERROR` to the fail-latch chain
  so token-counting failures stop retrying compression every send.
- Restore `FileReadCache.clear()` after compaction in both the manual
  /compress wrapper and the auto-compaction path inside GeminiChat,
  preventing post-summary `file_unchanged` placeholders from pointing
  at content the model can no longer retrieve.
- Refresh stale comment on the `compressed → ChatCompressed` bridge
  in turn.ts now that this path is the primary route, not a fallback.

Tests:
- turn.test.ts asserts the compressed → ChatCompressed bridge.
- geminiChat.test.ts asserts COMPRESSED yields as the first stream
  event after auto-compaction succeeds.
- chatCompressionService.test.ts bumps originalTokenCount above the
  cheap-gate so the NOOP test exercises findCompressSplitPoint.
- client.test.ts asserts forceFullIdeContext flips when a
  ChatCompressed event flows through sendMessageStream's loop.

* chore(core): drop redundant StreamEvent cast and document auto-compaction trade-off

- Remove the `as StreamEvent` cast at the COMPRESSED yield site — the
  literal already matches the union member.
- Add a 4-line comment at the auto-compaction setHistory point that
  points readers to GeminiClient for the env-refresh trade-off rationale,
  so readers don't have to chase the layering decision back across files.
@tanzhenxin tanzhenxin deleted the fix/3664-subagent-context-compaction branch June 13, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants