79 lines · 3.2 KB · TypeScript
RawDownload
/** * ProviderEventLoggers — single observability service that owns the two * shared NDJSON streams the provider runtime writes: * *   - `native`    — provider-protocol events as the SDK emits them, written *                   from inside each `<X>Adapter` factory. *   - `canonical` — runtime events after `ProviderService` has normalized *                   them onto `ProviderRuntimeEvent`. * * Why a service tag and not constructor options? * *   - Adapters are now constructed *inside* drivers (`<X>Driver.create()`), *     not at the boot Layer. There is no longer a single `make<X>AdapterLive(options)` *     call site where we can hand an `EventNdjsonLogger` in by hand. *   - Multiple driver instances per kind (`codex_personal`, `codex_work`) *     should share one underlying log writer per stream — opening N writers *     against the same rotating file would race the rotation logic. Owning *     the loggers on a single tag keeps that invariant intact. *   - Tests can swap one (or both) loggers with in-memory recorders by *     `Layer.succeed(ProviderEventLoggers, { native, canonical })` instead of *     juggling per-Layer option threading. * * Both fields are optional. `makeEventNdjsonLogger` returns `undefined` when * the target directory cannot be created; we forward that as `undefined` * rather than failing the boot Layer, matching the previous best-effort * behavior of `server.ts`. * * @module provider/ProviderEventLoggers */import * as Context from "effect/Context";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer"; import * as Config from "../config.ts";import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./Layers/EventNdjsonLogger.ts"; /** * Shared logger pair for native + canonical provider event streams. * * Service value is intentionally a struct of two optional loggers rather * than two parallel tags. Construction site is one place * (`layer`); consumers (drivers, `ProviderService`) read * one tag and pluck the field they need. */export class ProviderEventLoggers extends Context.Service<  ProviderEventLoggers,  {    readonly native: EventNdjsonLogger | undefined;    readonly canonical: EventNdjsonLogger | undefined;  }>()("t3/provider/ProviderEventLoggers") {} /** * Constant value used by tests / boot layers that want to opt out of native * + canonical logging entirely. Keeps the tag non-optional in the type * system while letting the runtime treat absence as a no-op. */export const NoOpProviderEventLoggers: ProviderEventLoggers["Service"] = {  native: undefined,  canonical: undefined,}; /** * Live Layer that builds both loggers from `ServerConfig.providerEventLogPath`. * If the directory create fails for either stream, the corresponding field * is `undefined` and writes from that stream become no-ops downstream. */export const make = Effect.gen(function* () {  const { providerEventLogPath } = yield* Config.ServerConfig;  const native = yield* makeEventNdjsonLogger(providerEventLogPath, {    stream: "native",  });  const canonical = yield* makeEventNdjsonLogger(providerEventLogPath, {    stream: "canonical",  });  return ProviderEventLoggers.of({ native, canonical });}); export const layer = Layer.effect(ProviderEventLoggers, make);