Skip to content

perf: parallel indexing, embedding cache, HNSW ANN, lazy imports#100

Merged
hellodk merged 3 commits into
masterfrom
optimize/perf-improvements
Jul 17, 2026
Merged

perf: parallel indexing, embedding cache, HNSW ANN, lazy imports#100
hellodk merged 3 commits into
masterfrom
optimize/perf-improvements

Conversation

@hellodk

@hellodk hellodk commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Addresses 6 performance bottlenecks in the Champ VS Code extension codebase, plus a full review pass fixing 9 additional issues (race conditions, CSP violations, OOM risks).

Changes

Core optimizations (commit dccd00b)

  • Parallel indexingPromise.allSettled() with 6-concurrency limiter in indexing-service.ts
  • Embedding content-hash cacheMap<sha256, Float32Array> + disk persistence in embedding-service.ts
  • Tool result truncation 500→3000 — first/last preservation with truncateForMetrics() in tool-calling-loop.ts
  • Parallel independent tool callsPromise.allSettled() for read-only tools
  • Lazy imports — dynamic import() for IndexingService, MultiAgentRunner, TeamMarketplaceClient in extension.ts
  • HNSW ANN vector index — optional hnswlib-node with brute-force fallback for >10K entries in vector-store.ts
  • Smart router dedup — 3 dedup passes→1 mergeModels() in smart-router.ts
  • Response cache wired into ToolCallingLoop for team-agent flows

Review fixes (commit dd37293)

Issue Severity Fix
Fire-and-forget void this.saveIndex() / saveCache() Critical await Promise.allSettled() before return
Embedding cache unbounded growth (OOM) High LRU eviction at 10K entries
readFileSync blocks event loop in parallel workers High await fsp.readFile() + async readdir
HNSW label↔entry desync during async build High Version counter with stale-build retry
Function() constructor violates CSP High Standard import("hnswlib-node")
No dimension validation on disk cache load Medium Skip entries with mismatched vec.length
Rapid onChange orphans IndexingService Medium Generation counter
Binary cache format to avoid OOM on save Medium JSON header + raw Float32 bytes
Cache namespace collision (tool-loop/default) Medium Actual provider.name + config.model

Verification

  • Typecheck: 0 errors
  • Lint: 0 errors (10 pre-existing warnings)
  • Tests: 1506 passed, 5 skipped

Checklist

  • No readFileSync in async code paths
  • No Function() constructor (CSP-safe)
  • All saves awaited (no fire-and-forget)
  • LRU eviction on unbounded caches
  • Version counters on async index builds
  • Generation counters on lazy instantiation

hellodk added 3 commits July 17, 2026 07:59
- Parallel file indexing with concurrency-limited embedding (Fix 1)
- Content-hash embedding cache (persists to ~/.champ/embed-cache/) (Fix 2)
- Tool result truncation 500→3000 chars with first/last preservation (Fix 3)
- Parallel independent (read-only) tool calls in tool-calling loop (Fix 4)
- Lazy dynamic imports for IndexingService, MultiAgentRunner, TeamMarketplaceClient (Fix 5)
- HNSW ANN vector index for stores >10K entries (Fix 6)
- Smart router dedup: array→Map, eliminates 3 redundant passes (Fix 7)
- Response cache wired into ToolCallingLoop for team-agent flows (Fix 8)
- Documented tree-sitter chunking path (Fix 9)
…itions

Critical fixes:
- Embedding cache: add LRU eviction (10K cap) to prevent OOM on large workspaces
- Embedding cache: binary disk format with dimension validation
- VectorStore: replace Function() constructor with standard import() (CSP-safe)
- VectorStore: add version counter to prevent HNSW label desync during async build
- IndexingService: await saveIndex/saveCache to prevent races with dispose()
- IndexingService: convert collectFiles to async (remove readFileSync)
- Extension: add generation counter to prevent orphaned IndexingService
- ToolCallingLoop: use actual provider/model names in response cache namespace
)

- Wrap background init block in 10s Promise.race to prevent indefinite hangs
- Broadcast state: 'error' on timeout so webview shows feedback
- Add providerLoadInFlight mutex to deduplicate concurrent loadProvider calls
- Parallelize 3 sequential context.secrets.get() calls via Promise.all
- Add 'reloadProvider' message type and handler in ChatViewProvider
- Add retry button in header error state (main.js + main.css)
@hellodk
hellodk merged commit d1a2a54 into master Jul 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant