import { Duration, Effect, Exit, Metric } from "effect"; import { dual } from "effect/Function"; import { compactMetricAttributes, normalizeModelMetricLabel, outcomeFromExit, } from "./Attributes.ts"; export const rpcRequestsTotal = Metric.counter("t3_rpc_requests_total", { description: "Total RPC requests handled by the websocket RPC server.", }); export const rpcRequestDuration = Metric.timer("t3_rpc_request_duration", { description: "RPC request handling duration.", }); export const orchestrationCommandsTotal = Metric.counter("t3_orchestration_commands_total", { description: "Total orchestration commands dispatched.", }); export const orchestrationCommandDuration = Metric.timer("t3_orchestration_command_duration", { description: "Orchestration command dispatch duration.", }); export const orchestrationCommandAckDuration = Metric.timer( "t3_orchestration_command_ack_duration", { description: "Time from orchestration command dispatch to the first committed domain event emitted for that command.", }, ); export const orchestrationEventsProcessedTotal = Metric.counter( "t3_orchestration_events_processed_total", { description: "Total orchestration intent events processed by runtime reactors.", }, ); export const providerSessionsTotal = Metric.counter("t3_provider_sessions_total", { description: "Total provider session lifecycle operations.", }); export const providerTurnsTotal = Metric.counter("t3_provider_turns_total", { description: "Total provider turn lifecycle operations.", }); export const providerTurnDuration = Metric.timer("t3_provider_turn_duration", { description: "Provider turn request duration.", }); export const providerRuntimeEventsTotal = Metric.counter("t3_provider_runtime_events_total", { description: "Total canonical provider runtime events processed.", }); export const gitCommandsTotal = Metric.counter("t3_git_commands_total", { description: "Total git commands executed by the server runtime.", }); export const gitCommandDuration = Metric.timer("t3_git_command_duration", { description: "Git command execution duration.", }); export const terminalSessionsTotal = Metric.counter("t3_terminal_sessions_total", { description: "Total terminal sessions started.", }); export const terminalRestartsTotal = Metric.counter("t3_terminal_restarts_total", { description: "Total terminal restart requests handled.", }); export const metricAttributes = ( attributes: Readonly>, ): ReadonlyArray<[string, string]> => Object.entries(compactMetricAttributes(attributes)); export const increment = ( metric: Metric.Metric, attributes: Readonly>, amount = 1, ) => Metric.update(Metric.withAttributes(metric, metricAttributes(attributes)), amount); export interface WithMetricsOptions { readonly counter?: Metric.Metric; readonly timer?: Metric.Metric; readonly attributes?: | Readonly> | (() => Readonly>); readonly outcomeAttributes?: ( outcome: ReturnType, ) => Readonly>; } const withMetricsImpl = ( effect: Effect.Effect, options: WithMetricsOptions, ): Effect.Effect => Effect.gen(function* () { const startedAt = Date.now(); const exit = yield* Effect.exit(effect); const duration = Duration.millis(Math.max(0, Date.now() - startedAt)); const baseAttributes = typeof options.attributes === "function" ? options.attributes() : (options.attributes ?? {}); if (options.timer) { yield* Metric.update( Metric.withAttributes(options.timer, metricAttributes(baseAttributes)), duration, ); } if (options.counter) { const outcome = outcomeFromExit(exit); yield* Metric.update( Metric.withAttributes( options.counter, metricAttributes({ ...baseAttributes, outcome, ...(options.outcomeAttributes ? options.outcomeAttributes(outcome) : {}), }), ), 1, ); } if (Exit.isSuccess(exit)) { return exit.value; } return yield* Effect.failCause(exit.cause); }); export const withMetrics: { ( options: WithMetricsOptions, ): (effect: Effect.Effect) => Effect.Effect; (effect: Effect.Effect, options: WithMetricsOptions): Effect.Effect; } = dual(2, withMetricsImpl); export const providerMetricAttributes = ( provider: string, extra?: Readonly>, ) => compactMetricAttributes({ provider, ...extra, }); export const providerTurnMetricAttributes = (input: { readonly provider: string; readonly model: string | null | undefined; readonly extra?: Readonly>; }) => { const modelFamily = normalizeModelMetricLabel(input.model); return compactMetricAttributes({ provider: input.provider, ...(modelFamily ? { modelFamily } : {}), ...input.extra, }); };