refactor(x): shared lazyResolve for the no-static-DI-edge pattern

Four modules hand-rolled the same lazy container-import-and-resolve
dance (agent registry, spawn-agent, background-task runner, notifier),
each restating the rationale. di/lazy-resolve.ts holds the pattern and
the reasoning once; all four sites migrate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ramnique Singh 2026-07-10 08:50:39 +05:30
parent 8dd5a2b49f
commit ca077faa95
4 changed files with 10 additions and 11 deletions

View file

@ -10,6 +10,7 @@ import { getRaw as getLabelingAgentRaw } from "../knowledge/labeling_agent.js";
import { getRaw as getNoteTaggingAgentRaw } from "../knowledge/note_tagging_agent.js";
import { getRaw as getInlineTaskAgentRaw } from "../knowledge/inline_task_agent.js";
import { getRaw as getAgentNotesAgentRaw } from "../knowledge/agent_notes_agent.js";
import { lazyResolve } from "../di/lazy-resolve.js";
import type { IAgentsRepo } from "./repo.js";
// The registry of built-in agents: one table instead of the historical
@ -89,9 +90,7 @@ export async function loadAgent(id: string): Promise<z.infer<typeof Agent>> {
if (builtin) {
return builtin.build();
}
// User-defined agents. The container is imported lazily so this module
// adds no static edge into the DI graph (mirrors spawn-agent).
const { default: container } = await import("../di/container.js");
const repo = container.resolve<IAgentsRepo>("agentsRepo");
// User-defined agents (lazyResolve: no static DI edge from this module).
const repo = await lazyResolve<IAgentsRepo>("agentsRepo");
return repo.fetch(id);
}

View file

@ -219,13 +219,13 @@ export async function runSpawnedAgent(
async function resolveServices(): Promise<
NonNullable<SpawnedAgentCallbacks["services"]>
> {
const { default: container } = await import("../di/container.js");
const { lazyResolve } = await import("../di/lazy-resolve.js");
return {
turnRuntime:
container.resolve<import("../turns/api.js").ITurnRuntime>(
await lazyResolve<import("../turns/api.js").ITurnRuntime>(
"turnRuntime",
),
headlessRunner: container.resolve<
headlessRunner: await lazyResolve<
import("./headless.js").IHeadlessAgentRunner
>("headlessAgentRunner"),
};

View file

@ -19,8 +19,8 @@ export async function notifyIfEnabled(
): Promise<void> {
try {
if (!isNotificationCategoryEnabled(category)) return;
const { default: container } = await import('../../di/container.js');
const service = container.resolve<INotificationService>('notificationService');
const { lazyResolve } = await import('../../di/lazy-resolve.js');
const service = await lazyResolve<INotificationService>('notificationService');
if (!service.isSupported()) return;
service.notify(input);
} catch (err) {

View file

@ -128,8 +128,8 @@ export async function runBackgroundTask(
let codeProject: { id: string; path: string; name: string } | undefined;
if (task.projectId) {
try {
const { default: container } = await import('../di/container.js');
const projectsRepo = container.resolve<import('../code-mode/projects/repo.js').ICodeProjectsRepo>('codeProjectsRepo');
const { lazyResolve } = await import('../di/lazy-resolve.js');
const projectsRepo = await lazyResolve<import('../code-mode/projects/repo.js').ICodeProjectsRepo>('codeProjectsRepo');
const project = await projectsRepo.get(task.projectId);
if (project) codeProject = { id: project.id, path: project.path, name: project.name };
} catch (err) {