qwen-code/packages/cli/src/config
jinye 9f4734e84d
fix(tool-registry): add lazy factory registration with inflight concurrency dedup (#3297)
Closes #3221.

Introduces a lazy factory API on ToolRegistry (registerFactory,
ensureTool, warmAll, getAllToolNames) as infrastructure for future
esbuild code-splitting (#3226). With the current single-bundle build,
the lazy API does not change startup time on its own — the primary
immediate value is fixing three pre-existing bugs uncovered while
designing it.

Bug fixes:

- Concurrent instantiation (P0): the original ensureTool had no
  concurrency protection around `await factory()` — two concurrent
  calls for the same tool both passed the cache check and each ran the
  factory, producing two instances. AgentTool and SkillTool register
  SubagentManager listeners in their constructors, so the extra
  instance leaked listeners. Fix: a per-name `inflight: Map<string,
  Promise<Tool>>` so concurrent ensureTool() calls share a single
  promise. On factory rejection the inflight entry is cleared so a
  subsequent call can retry.

- stop() resource leak: stop() only disposed tools already in
  `this.tools`; tools still loading in `inflight` when stop() ran
  finished afterward and were never disposed. Fix: await
  Promise.allSettled(inflight.values()) before the dispose loop.

- Cache hit left stale factory: ensureTool's cache-hit branch did not
  delete the factory entry, so warmAll() would re-invoke the factory
  for an already-loaded tool. Fix: delete the factory on cache hit.

Additional hardening in response to review feedback:

- warmAll({ strict?: boolean }): strict mode re-throws the first
  factory failure rather than swallowing it. Config.initialize() uses
  strict: true so a broken built-in tool fails startup fast instead of
  silently leaving a partially initialized registry; runtime-path
  callers (GeminiChat, agent runtime, etc.) continue to use the
  non-strict default and log failures via debugLogger.
- getAllTools() and getFunctionDeclarationsFiltered() emit a debug
  warning when called while unloaded factories remain, nudging callers
  toward warmAll() without hard-breaking existing code paths.
- copyDiscoveredToolsFrom() now iterates source.tools.values()
  directly instead of source.getAllTools() — the copy path deals only
  with already-discovered MCP/command tools and should not trigger the
  unloaded-factory warning.
- MemoryTool and SkillTool config parsing was extracted into
  memory-config.ts and skill-utils.ts so a factory can resolve tool
  metadata without importing the tool module.

Tests:

- tool-registry.test.ts adds 128 lines covering: concurrent ensureTool
  runs the factory exactly once, warmAll and ensureTool overlap,
  retries succeed after a prior factory failure, stop() disposes tools
  that finish loading after stop was called, and warmAll strict vs
  default behavior.
- 33 existing call sites across cli, core, agents, and subagents were
  updated to await warmAll() before bulk tool access.
2026-04-18 10:31:50 +08:00
..
migration refactor: remove summarizeToolOutput feature 2026-03-15 13:51:32 +08:00
auth.test.ts feat(auth): discontinue Qwen OAuth free tier (2026-04-15 cutoff) (#3291) 2026-04-15 22:30:20 +08:00
auth.ts feat(auth): discontinue Qwen OAuth free tier (2026-04-15 cutoff) (#3291) 2026-04-15 22:30:20 +08:00
config.integration.test.ts chore: update tests for parseArguments signature change 2026-02-06 13:05:49 +08:00
config.test.ts fix(tool-registry): add lazy factory registration with inflight concurrency dedup (#3297) 2026-04-18 10:31:50 +08:00
config.ts fix(tool-registry): add lazy factory registration with inflight concurrency dedup (#3297) 2026-04-18 10:31:50 +08:00
keyBindings.test.ts Explict imports & exports with type modifier (#3774) 2025-08-25 22:04:53 +00:00
keyBindings.ts refactor: rename verboseMode to compactMode for better UX clarity (#3075) 2026-04-10 11:55:50 +08:00
modelProvidersScope.test.ts fix: lint & ci issues 2026-01-07 22:58:09 +08:00
modelProvidersScope.ts feat(cli): warn when workspace overrides global modelProviders (#3148) 2026-04-13 10:43:16 +08:00
sandboxConfig.ts feat(cli): support tools.sandboxImage in settings (#3146) 2026-04-13 09:43:34 +08:00
settings.test.ts feat(cli): warn when workspace overrides global modelProviders (#3148) 2026-04-13 10:43:16 +08:00
settings.ts feat(hooks): Add HTTP Hook, Function Hook and Async Hook support (#2827) 2026-04-16 10:10:33 +08:00
settingsSchema.test.ts feat(cli): support tools.sandboxImage in settings (#3146) 2026-04-13 09:43:34 +08:00
settingsSchema.ts feat(cli): add dual-output sidecar mode for TUI (#3352) 2026-04-18 02:14:53 +08:00
trustedFolders.test.ts refactor: unify sandbox configuration naming and improve telemetry config 2026-02-11 11:08:15 +08:00
trustedFolders.ts refactor: unify sandbox configuration naming and improve telemetry config 2026-02-11 11:08:15 +08:00
webSearch.ts feat(auth): discontinue Qwen OAuth free tier (2026-04-15 cutoff) (#3291) 2026-04-15 22:30:20 +08:00