import * as Cause from "effect/Cause"; import * as Exit from "effect/Exit"; export type MetricAttributeValue = string; export type MetricAttributes = Readonly>; export type ObservabilityOutcome = "success" | "failure" | "interrupt"; export function compactMetricAttributes( attributes: Readonly>, ): MetricAttributes { return Object.fromEntries( Object.entries(attributes).flatMap(([key, value]) => { if (value === undefined || value === null) { return []; } if (typeof value === "string") { return [[key, value]]; } if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") { return [[key, String(value)]]; } return []; }), ); } export function outcomeFromExit(exit: Exit.Exit): ObservabilityOutcome { if (Exit.isSuccess(exit)) { return "success"; } return Cause.hasInterruptsOnly(exit.cause) ? "interrupt" : "failure"; } export function normalizeModelMetricLabel(model: string | null | undefined): string | undefined { const normalized = model?.trim().toLowerCase(); if (!normalized) { return undefined; } if (normalized.includes("gpt")) { return "gpt"; } if (normalized.includes("claude")) { return "claude"; } if (normalized.includes("gemini")) { return "gemini"; } return "other"; }