diff --git a/packages/coding-agent/src/config/model-equivalence.ts b/packages/coding-agent/src/config/model-equivalence.ts index dd8185ab4..75fedfc2b 100644 --- a/packages/coding-agent/src/config/model-equivalence.ts +++ b/packages/coding-agent/src/config/model-equivalence.ts @@ -771,7 +771,6 @@ function resolveCanonicalIdForModel( return { id: claudeFamilyAlias, source: claudeFamilyAlias === model.id ? "bundled" : "heuristic" }; } - const heuristicCandidates = getHeuristicCanonicalCandidates(model.id, referenceData.officialIds); const officialMatches = new Set(); for (const candidate of heuristicCandidates) { diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index fa4c24011..a0f7fa1a0 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -40,7 +40,6 @@ import { resolveActiveProjectRegistryPath, } from "./discovery/helpers"; import { injectOmpExtensionCliRoots } from "./discovery/omp-extension-roots"; -import { exportFromFile } from "./export/html"; import { ExtensionRunner } from "./extensibility/extensions/runner"; import type { ExtensionUIContext } from "./extensibility/extensions/types"; import { scheduleMarketplaceAutoUpdate } from "./extensibility/plugins/marketplace-auto-update"; @@ -784,6 +783,7 @@ export async function runRootCommand( let result: string; try { const outputPath = parsedArgs.messages.length > 0 ? parsedArgs.messages[0] : undefined; + const { exportFromFile } = await import("./export/html"); result = await exportFromFile(parsedArgs.export, outputPath); } catch (error: unknown) { const message = error instanceof Error ? error.message : "Failed to export session"; @@ -977,7 +977,7 @@ export async function runRootCommand( // Both are no-ops when OTEL_EXPORTER_OTLP_ENDPOINT is unset. An empty config // is enough to enable telemetry — content capture is governed by the // standard OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT env var. - initTelemetryExport(); + await initTelemetryExport(); if (isTelemetryExportEnabled()) { sessionOptions.telemetry = {}; } diff --git a/packages/coding-agent/src/memory-backend/index.ts b/packages/coding-agent/src/memory-backend/index.ts index 2c2c678a3..62f504ee4 100644 --- a/packages/coding-agent/src/memory-backend/index.ts +++ b/packages/coding-agent/src/memory-backend/index.ts @@ -1,4 +1,16 @@ -export * from "../mnemopi"; +export type { + MnemopiBackendConfig, + MnemopiLlmMode, + MnemopiProviderOptions, + MnemopiScoping, +} from "../mnemopi/config"; +export type { + MnemopiMemoryEditOperation, + MnemopiMemoryEditOptions, + MnemopiMemoryEditResult, + MnemopiSessionState, + MnemopiSessionStateOptions, +} from "../mnemopi/state"; export * from "./local-backend"; export * from "./off-backend"; export * from "./resolve"; diff --git a/packages/coding-agent/src/memory-backend/resolve.ts b/packages/coding-agent/src/memory-backend/resolve.ts index a0066d7f9..638aabec1 100644 --- a/packages/coding-agent/src/memory-backend/resolve.ts +++ b/packages/coding-agent/src/memory-backend/resolve.ts @@ -1,6 +1,4 @@ import type { Settings } from "../config/settings"; -import { hindsightBackend } from "../hindsight"; -import { mnemopiBackend } from "../mnemopi"; import { localBackend } from "./local-backend"; import { offBackend } from "./off-backend"; import type { MemoryBackend } from "./types"; @@ -18,10 +16,10 @@ import type { MemoryBackend } from "./types"; * `memories.enabled` remains accepted only as a legacy migration input. Once * a config is loaded, `memory.backend` is the sole runtime selector. */ -export function resolveMemoryBackend(settings: Settings): MemoryBackend { +export async function resolveMemoryBackend(settings: Settings): Promise { const id = settings.get("memory.backend"); - if (id === "hindsight") return hindsightBackend; - if (id === "mnemopi") return mnemopiBackend; + if (id === "hindsight") return (await import("../hindsight/backend")).hindsightBackend; + if (id === "mnemopi") return (await import("../mnemopi/backend")).mnemopiBackend; if (id === "local") return localBackend; return offBackend; } diff --git a/packages/coding-agent/src/memory-backend/types.ts b/packages/coding-agent/src/memory-backend/types.ts index 3d72976ea..8b2e5cd15 100644 --- a/packages/coding-agent/src/memory-backend/types.ts +++ b/packages/coding-agent/src/memory-backend/types.ts @@ -1,7 +1,7 @@ /** * Memory backend abstraction. * - * Backends are mutually exclusive — `resolveMemoryBackend(settings)` returns + * Backends are mutually exclusive — `await resolveMemoryBackend(settings)` resolves * exactly one. Implementations MUST be self-contained: they own the per-session * state they create in `start()` and tear it down on `clear()`. */ diff --git a/packages/coding-agent/src/modes/controllers/command-controller.ts b/packages/coding-agent/src/modes/controllers/command-controller.ts index a64a254f1..23462c9a2 100644 --- a/packages/coding-agent/src/modes/controllers/command-controller.ts +++ b/packages/coding-agent/src/modes/controllers/command-controller.ts @@ -13,7 +13,6 @@ import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi import { formatDuration, Snowflake } from "@oh-my-pi/pi-utils"; import { $ } from "bun"; import { shouldEnableAppendOnlyContext } from "../../config/append-only-context-mode"; -import { loadCustomShare } from "../../export/custom-share"; import type { CompactOptions } from "../../extensibility/extensions/types"; import { diffMentalModelContent, @@ -131,6 +130,7 @@ export class CommandController { } try { + const { loadCustomShare } = await import("../../export/custom-share"); const customShare = await loadCustomShare(); if (customShare) { const loader = new BorderedLoader(this.ctx.ui, theme, "Sharing..."); @@ -465,7 +465,7 @@ export class CommandController { const argumentText = text.slice(7).trim(); const action = argumentText.split(/\s+/, 1)[0]?.toLowerCase() || "view"; const agentDir = this.ctx.settings.getAgentDir(); - const backend = resolveMemoryBackend(this.ctx.settings); + const backend = await resolveMemoryBackend(this.ctx.settings); if (action === "view") { const payload = await backend.buildDeveloperInstructions(agentDir, this.ctx.settings, this.ctx.session); diff --git a/packages/coding-agent/src/modes/controllers/selector-controller.ts b/packages/coding-agent/src/modes/controllers/selector-controller.ts index df8ae8d1b..b6c7cfffe 100644 --- a/packages/coding-agent/src/modes/controllers/selector-controller.ts +++ b/packages/coding-agent/src/modes/controllers/selector-controller.ts @@ -7,7 +7,6 @@ import { getAgentDbPath, getProjectDir, normalizePathForComparison } from "@oh-m import { getRoleInfo } from "../../config/model-registry"; import { formatModelSelectorValue } from "../../config/model-resolver"; import { settings } from "../../config/settings"; -import { DebugSelectorComponent } from "../../debug"; import { disableProvider, enableProvider } from "../../discovery"; import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers"; import { @@ -1080,7 +1079,8 @@ export class SelectorController { }); } - showDebugSelector(): void { + async showDebugSelector(): Promise { + const { DebugSelectorComponent } = await import("../../debug"); this.showSelector(done => { const selector = new DebugSelectorComponent(this.ctx, done); return { component: selector, focus: selector }; diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index 009ef43e1..1166097df 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -2844,8 +2844,8 @@ export class InteractiveMode implements InteractiveModeContext { } } - showDebugSelector(): void { - this.#selectorController.showDebugSelector(); + async showDebugSelector(): Promise { + await this.#selectorController.showDebugSelector(); } showSessionObserver(): void { diff --git a/packages/coding-agent/src/modes/types.ts b/packages/coding-agent/src/modes/types.ts index 2b38238a4..de2cfa880 100644 --- a/packages/coding-agent/src/modes/types.ts +++ b/packages/coding-agent/src/modes/types.ts @@ -269,7 +269,7 @@ export interface InteractiveModeContext { handleSessionDeleteCommand(): Promise; showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise; showHookConfirm(title: string, message: string): Promise; - showDebugSelector(): void; + showDebugSelector(): Promise; showSessionObserver(): void; resetObserverRegistry(): void; diff --git a/packages/coding-agent/src/sdk.ts b/packages/coding-agent/src/sdk.ts index 70bbcb58c..46ad4553e 100644 --- a/packages/coding-agent/src/sdk.ts +++ b/packages/coding-agent/src/sdk.ts @@ -36,7 +36,6 @@ import { } from "@oh-my-pi/pi-utils"; import chalk from "chalk"; import { type AsyncJob, AsyncJobManager, isBackgroundJobSupportEnabled } from "./async"; -import { createAutoresearchExtension } from "./autoresearch"; import { loadCapability } from "./capability"; import { type Rule, ruleCapability, setActiveRules } from "./capability/rule"; import { bucketRules } from "./capability/rule-buckets"; @@ -57,7 +56,6 @@ import { resolveConfigValue } from "./config/resolve-config-value"; import { initializeWithSettings } from "./discovery"; import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor"; import { defaultEvalSessionId } from "./eval/session-id"; -import { TtsrManager } from "./export/ttsr"; import { type CustomCommandsLoadResult, type LoadedCustomCommand, @@ -90,7 +88,7 @@ import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events"; import { discoverAndLoadMCPTools, MCPManager, type MCPToolsLoadResult } from "./mcp"; import { resolveMemoryBackend } from "./memory-backend"; -import { getMnemopiSessionState, type MnemopiSessionState } from "./mnemopi/state"; +import type { MnemopiSessionState } from "./mnemopi/state"; import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" }; import { AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry"; import { @@ -1150,6 +1148,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} // Discover rules and bucket them in one pass to avoid repeated scans over large rule sets. const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => { + const { TtsrManager } = await import("./export/ttsr"); const ttsrSettings = settings.getGroup("ttsr"); const ttsrManager = new TtsrManager(ttsrSettings); const rulesResult = @@ -1295,7 +1294,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} session ? session.trackEvalExecution(execution, abortController) : execution, getSessionId: () => sessionManager.getSessionId?.() ?? null, getHindsightSessionState: () => session?.getHindsightSessionState(), - getMnemopiSessionState: () => getMnemopiSessionState(session), + getMnemopiSessionState: () => session?.getMnemopiSessionState(), getAgentId: () => resolvedAgentId, getToolByName: name => session?.getToolByName(name), agentRegistry, @@ -1472,7 +1471,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} } const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : []; - inlineExtensions.push(createAutoresearchExtension); + inlineExtensions.push((await import("./autoresearch")).createAutoresearchExtension); if (customTools.length > 0) { inlineExtensions.push(createCustomToolsExtension(customTools)); } @@ -1607,9 +1606,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} // `ExtensionToolWrapper` installed below is the only place the per-tool approval gate runs. // A conditional runner means the approval system silently disappears for users with no // extensions, contradicting non-yolo `tools.approvalMode` settings without feedback. - // (Today `createAutoresearchExtension` is unconditionally pushed below, so this scenario - // is unreachable; the unconditional construction makes that invariant explicit instead of - // implicit, so a future change to make autoresearch optional cannot silently re-open the hole.) + // (The builtin autoresearch extension is unconditionally loaded above, so this scenario + // is unreachable; unconditional runner construction keeps that invariant explicit and + // prevents future optional extensions from silently re-opening the hole.) const extensionRunner: ExtensionRunner = new ExtensionRunner( extensionsResult.extensions, extensionsResult.runtime, @@ -1749,7 +1748,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} const promptTools = buildSystemPromptToolMetadata(tools, { search_tool_bm25: { description: renderSearchToolBm25Description(discoverableToolsForDesc) }, }); - const memoryBackend = resolveMemoryBackend(settings); + const memoryBackend = await resolveMemoryBackend(settings); const memoryInstructions = await memoryBackend.buildDeveloperInstructions(agentDir, settings, session); // Build combined append prompt: memory instructions + MCP server instructions @@ -2267,19 +2266,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} } } - logger.time("startMemoryStartupTask", () => - Promise.resolve( - resolveMemoryBackend(settings).start({ - session, - settings, - modelRegistry, - agentDir, - taskDepth, - parentHindsightSessionState: options.parentHindsightSessionState, - parentMnemopiSessionState: options.parentMnemopiSessionState, - }), - ), - ); + logger.time("startMemoryStartupTask", async () => { + const memoryBackend = await resolveMemoryBackend(settings); + await memoryBackend.start({ + session, + settings, + modelRegistry, + agentDir, + taskDepth, + parentHindsightSessionState: options.parentHindsightSessionState, + parentMnemopiSessionState: options.parentMnemopiSessionState, + }); + }); // Wire MCP manager callbacks to session for reactive tool updates. // Skip when reusing a parent's manager — the parent owns the callbacks. diff --git a/packages/coding-agent/src/session/agent-session.ts b/packages/coding-agent/src/session/agent-session.ts index eca983671..746ef86e0 100644 --- a/packages/coding-agent/src/session/agent-session.ts +++ b/packages/coding-agent/src/session/agent-session.ts @@ -128,7 +128,6 @@ import { } from "../eval/py/executor"; import { defaultEvalSessionId } from "../eval/session-id"; import { type BashResult, executeBash as executeBashCommand } from "../exec/bash-executor"; -import { exportSessionToHtml } from "../export/html"; import type { TtsrManager, TtsrMatchContext } from "../export/ttsr"; import type { LoadedCustomCommand } from "../extensibility/custom-commands"; import type { CustomTool, CustomToolContext } from "../extensibility/custom-tools/types"; @@ -2967,14 +2966,14 @@ export class AgentSession { } #rekeyHindsightMemoryForCurrentSessionId(): void { - if (resolveMemoryBackend(this.settings).id !== "hindsight") return; + if (this.settings.get("memory.backend") !== "hindsight") return; const sid = this.agent.sessionId; if (!sid) return; this.getHindsightSessionState()?.setSessionId(sid); } #rekeyMnemopiMemoryForCurrentSessionId(): void { - if (resolveMemoryBackend(this.settings).id !== "mnemopi") return; + if (this.settings.get("memory.backend") !== "mnemopi") return; const sid = this.agent.sessionId; if (!sid) return; this.getMnemopiSessionState()?.setSessionId(sid); @@ -2982,14 +2981,14 @@ export class AgentSession { /** New session file: reset auto-recall / retain-threshold counters for the new transcript. */ #resetHindsightConversationTrackingIfHindsight(): void { - if (resolveMemoryBackend(this.settings).id !== "hindsight") return; + if (this.settings.get("memory.backend") !== "hindsight") return; const state = this.getHindsightSessionState(); if (!state || state.aliasOf) return; state.resetConversationTracking(); } #resetMnemopiConversationTrackingIfMnemopi(): void { - if (resolveMemoryBackend(this.settings).id !== "mnemopi") return; + if (this.settings.get("memory.backend") !== "mnemopi") return; const state = this.getMnemopiSessionState(); if (!state || state.aliasOf) return; state.resetConversationTracking(); @@ -3670,7 +3669,7 @@ export class AgentSession { } async #buildSystemPromptForAgentStart(promptText: string): Promise { - const backend = resolveMemoryBackend(this.settings); + const backend = await resolveMemoryBackend(this.settings); if (!backend.beforeAgentStartPrompt) return this.#baseSystemPrompt; try { @@ -6096,7 +6095,7 @@ export class AgentSession { messagesToSummarize: AgentMessage[]; turnPrefixMessages: AgentMessage[]; }): Promise { - const backend = resolveMemoryBackend(this.settings); + const backend = await resolveMemoryBackend(this.settings); if (!backend.preCompactionContext) return undefined; const messages = preparation.messagesToSummarize.concat(preparation.turnPrefixMessages); try { @@ -9588,6 +9587,7 @@ export class AgentSession { */ async exportToHtml(outputPath?: string): Promise { const themeName = getCurrentThemeName(); + const { exportSessionToHtml } = await import("../export/html"); return exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName }); } diff --git a/packages/coding-agent/src/slash-commands/builtin-registry.ts b/packages/coding-agent/src/slash-commands/builtin-registry.ts index 394491f8b..bfb059a70 100644 --- a/packages/coding-agent/src/slash-commands/builtin-registry.ts +++ b/packages/coding-agent/src/slash-commands/builtin-registry.ts @@ -934,7 +934,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray = [ allowArgs: true, handle: async (command, runtime) => { const verb = (command.args.trim().split(/\s+/)[0] ?? "").toLowerCase() || "view"; - const backend = resolveMemoryBackend(runtime.settings); + const backend = await resolveMemoryBackend(runtime.settings); switch (verb) { case "view": { const payload = await backend.buildDeveloperInstructions( diff --git a/packages/coding-agent/src/telemetry-export.ts b/packages/coding-agent/src/telemetry-export.ts index fbb5b3a62..234d43cf3 100644 --- a/packages/coding-agent/src/telemetry-export.ts +++ b/packages/coding-agent/src/telemetry-export.ts @@ -23,11 +23,7 @@ * `sdk-trace-base@2.7` exports cleanly on Bun. */ import { logger, postmortem } from "@oh-my-pi/pi-utils"; -import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks"; -import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto"; -import { resourceFromAttributes } from "@opentelemetry/resources"; -import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"; -import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node"; +import type * as TraceNode from "@opentelemetry/sdk-trace-node"; /** * Periodic flush interval. A long-lived `omp` process (the ACP server is @@ -36,7 +32,8 @@ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node"; */ const FLUSH_INTERVAL_MS = 30_000; -let provider: NodeTracerProvider | undefined; +let provider: TraceNode.NodeTracerProvider | undefined; +let initPromise: Promise | undefined; /** * Whether {@link initTelemetryExport} registered a real provider. The CLI uses @@ -53,8 +50,10 @@ export function isTelemetryExportEnabled(): boolean { * the OTEL kill-switches are engaged), so it is safe to call unconditionally at * startup. */ -export function initTelemetryExport(): void { +export async function initTelemetryExport(): Promise { if (provider) return; + if (initPromise) return initPromise; + // The OTEL env contract parses booleans and enum lists case-insensitively, so // OTEL_SDK_DISABLED=TRUE and OTEL_TRACES_EXPORTER=None must also disable export. if (process.env.OTEL_SDK_DISABLED?.trim().toLowerCase() === "true") return; @@ -77,6 +76,25 @@ export function initTelemetryExport(): void { return; } + initPromise = registerProvider(); + return initPromise; +} + +async function registerProvider(): Promise { + const [ + { AsyncLocalStorageContextManager }, + { OTLPTraceExporter }, + { resourceFromAttributes }, + { BatchSpanProcessor }, + { NodeTracerProvider }, + ] = await Promise.all([ + import("@opentelemetry/context-async-hooks"), + import("@opentelemetry/exporter-trace-otlp-proto"), + import("@opentelemetry/resources"), + import("@opentelemetry/sdk-trace-base"), + import("@opentelemetry/sdk-trace-node"), + ]); + // The exporter reads endpoint/headers/timeout from OTEL_EXPORTER_OTLP_* itself, // so there is nothing to thread through here. const exporter = new OTLPTraceExporter(); diff --git a/packages/coding-agent/test/memory-backend-resolve.test.ts b/packages/coding-agent/test/memory-backend-resolve.test.ts index 075f05e8f..46845e103 100644 --- a/packages/coding-agent/test/memory-backend-resolve.test.ts +++ b/packages/coding-agent/test/memory-backend-resolve.test.ts @@ -11,10 +11,10 @@ describe("resolveMemoryBackend", () => { resetSettingsForTest(); }); - it("returns the hindsight backend when memory.backend is hindsight, regardless of legacy memories.enabled", () => { + it("returns the hindsight backend when memory.backend is hindsight, regardless of legacy memories.enabled", async () => { const a = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": false }); const b = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": true }); - expect(resolveMemoryBackend(a).id).toBe("hindsight"); - expect(resolveMemoryBackend(b).id).toBe("hindsight"); + expect((await resolveMemoryBackend(a)).id).toBe("hindsight"); + expect((await resolveMemoryBackend(b)).id).toBe("hindsight"); }); }); diff --git a/packages/coding-agent/test/otel-export-probe.ts b/packages/coding-agent/test/otel-export-probe.ts index 2ada60550..2b285bcf8 100644 --- a/packages/coding-agent/test/otel-export-probe.ts +++ b/packages/coding-agent/test/otel-export-probe.ts @@ -35,7 +35,7 @@ const server = Bun.serve({ process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = `http://localhost:${server.port}/v1/traces`; process.env.OTEL_SERVICE_NAME = "oh-my-pi-export-probe"; -initTelemetryExport(); +await initTelemetryExport(); if (!isTelemetryExportEnabled()) { console.error("PROBE: provider did not register"); await server.stop(true); diff --git a/packages/coding-agent/test/telemetry-export.test.ts b/packages/coding-agent/test/telemetry-export.test.ts index ecdaf86e8..fa0238b04 100644 --- a/packages/coding-agent/test/telemetry-export.test.ts +++ b/packages/coding-agent/test/telemetry-export.test.ts @@ -33,45 +33,45 @@ afterEach(() => { }); describe("initTelemetryExport gating", () => { - it("stays disabled when no OTLP endpoint is configured", () => { - initTelemetryExport(); + it("stays disabled when no OTLP endpoint is configured", async () => { + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); }); - it("stays disabled when OTEL_SDK_DISABLED=true even with an endpoint", () => { + it("stays disabled when OTEL_SDK_DISABLED=true even with an endpoint", async () => { process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"; process.env.OTEL_SDK_DISABLED = "true"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); }); - it("stays disabled when OTEL_TRACES_EXPORTER=none even with an endpoint", () => { + it("stays disabled when OTEL_TRACES_EXPORTER=none even with an endpoint", async () => { process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"; process.env.OTEL_TRACES_EXPORTER = "none"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); }); - it("declines unsupported OTLP protocols instead of misrouting spans", () => { + it("declines unsupported OTLP protocols instead of misrouting spans", async () => { process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4317"; process.env.OTEL_EXPORTER_OTLP_PROTOCOL = "grpc"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "http/json"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); }); - it("honors the kill-switches case-insensitively per the OTEL env contract", () => { + it("honors the kill-switches case-insensitively per the OTEL env contract", async () => { process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"; process.env.OTEL_SDK_DISABLED = "TRUE"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); delete process.env.OTEL_SDK_DISABLED; process.env.OTEL_TRACES_EXPORTER = "otlp,None"; - initTelemetryExport(); + await initTelemetryExport(); expect(isTelemetryExportEnabled()).toBe(false); }); });