summaryrefslogtreecommitdiffhomepage
path: root/packages/session-orchestrator/src/metrics.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/session-orchestrator/src/metrics.ts')
-rw-r--r--packages/session-orchestrator/src/metrics.ts226
1 files changed, 113 insertions, 113 deletions
diff --git a/packages/session-orchestrator/src/metrics.ts b/packages/session-orchestrator/src/metrics.ts
index 2dfa533..c0f9566 100644
--- a/packages/session-orchestrator/src/metrics.ts
+++ b/packages/session-orchestrator/src/metrics.ts
@@ -1,138 +1,138 @@
import type {
- AgentEvent,
- StepId,
- StepMetrics,
- TurnDoneEvent,
- TurnMetrics,
- TurnStepCompleteEvent,
- TurnUsageEvent,
- Usage,
+ AgentEvent,
+ StepId,
+ StepMetrics,
+ TurnDoneEvent,
+ TurnMetrics,
+ TurnStepCompleteEvent,
+ TurnUsageEvent,
+ Usage,
} from "@dispatch/kernel";
const zeroUsage: Usage = { inputTokens: 0, outputTokens: 0 };
interface StepAccumulator {
- readonly stepId: StepId;
- usage: Usage | undefined;
- ttftMs: number | undefined;
- decodeMs: number | undefined;
- genTotalMs: number | undefined;
+ readonly stepId: StepId;
+ usage: Usage | undefined;
+ ttftMs: number | undefined;
+ decodeMs: number | undefined;
+ genTotalMs: number | undefined;
}
export interface MetricsAccumulator {
- readonly ingest: (event: AgentEvent) => void;
- readonly build: (turnId: string) => TurnMetrics;
- readonly reset: () => void;
+ readonly ingest: (event: AgentEvent) => void;
+ readonly build: (turnId: string) => TurnMetrics;
+ readonly reset: () => void;
}
export function createMetricsAccumulator(): MetricsAccumulator {
- const steps = new Map<StepId, StepAccumulator>();
- const stepOrder: StepId[] = [];
- let doneUsage: Usage | undefined;
- let doneDurationMs: number | undefined;
+ const steps = new Map<StepId, StepAccumulator>();
+ const stepOrder: StepId[] = [];
+ let doneUsage: Usage | undefined;
+ let doneDurationMs: number | undefined;
- function getOrCreateStep(stepId: StepId): StepAccumulator {
- let acc = steps.get(stepId);
- if (acc === undefined) {
- acc = {
- stepId,
- usage: undefined,
- ttftMs: undefined,
- decodeMs: undefined,
- genTotalMs: undefined,
- };
- steps.set(stepId, acc);
- stepOrder.push(stepId);
- }
- return acc;
- }
+ function getOrCreateStep(stepId: StepId): StepAccumulator {
+ let acc = steps.get(stepId);
+ if (acc === undefined) {
+ acc = {
+ stepId,
+ usage: undefined,
+ ttftMs: undefined,
+ decodeMs: undefined,
+ genTotalMs: undefined,
+ };
+ steps.set(stepId, acc);
+ stepOrder.push(stepId);
+ }
+ return acc;
+ }
- function ingest(event: AgentEvent): void {
- switch (event.type) {
- case "usage": {
- const e = event as TurnUsageEvent;
- if (e.stepId !== undefined) {
- const acc = getOrCreateStep(e.stepId);
- acc.usage = e.usage;
- }
- break;
- }
- case "step-complete": {
- const e = event as TurnStepCompleteEvent;
- const acc = getOrCreateStep(e.stepId);
- acc.ttftMs = e.ttftMs;
- acc.decodeMs = e.decodeMs;
- acc.genTotalMs = e.genTotalMs;
- break;
- }
- case "done": {
- const e = event as TurnDoneEvent;
- doneUsage = e.usage;
- doneDurationMs = e.durationMs;
- break;
- }
- }
- }
+ function ingest(event: AgentEvent): void {
+ switch (event.type) {
+ case "usage": {
+ const e = event as TurnUsageEvent;
+ if (e.stepId !== undefined) {
+ const acc = getOrCreateStep(e.stepId);
+ acc.usage = e.usage;
+ }
+ break;
+ }
+ case "step-complete": {
+ const e = event as TurnStepCompleteEvent;
+ const acc = getOrCreateStep(e.stepId);
+ acc.ttftMs = e.ttftMs;
+ acc.decodeMs = e.decodeMs;
+ acc.genTotalMs = e.genTotalMs;
+ break;
+ }
+ case "done": {
+ const e = event as TurnDoneEvent;
+ doneUsage = e.usage;
+ doneDurationMs = e.durationMs;
+ break;
+ }
+ }
+ }
- function build(turnId: string): TurnMetrics {
- const stepMetrics: StepMetrics[] = stepOrder.map((stepId) => {
- const acc = steps.get(stepId);
- if (acc === undefined) {
- return { stepId, usage: zeroUsage };
- }
- const usage = acc.usage ?? zeroUsage;
- const sm: StepMetrics = { stepId, usage };
- if (acc.ttftMs !== undefined) {
- (sm as { ttftMs?: number }).ttftMs = acc.ttftMs;
- }
- if (acc.decodeMs !== undefined) {
- (sm as { decodeMs?: number }).decodeMs = acc.decodeMs;
- }
- if (acc.genTotalMs !== undefined) {
- (sm as { genTotalMs?: number }).genTotalMs = acc.genTotalMs;
- }
- return sm;
- });
+ function build(turnId: string): TurnMetrics {
+ const stepMetrics: StepMetrics[] = stepOrder.map((stepId) => {
+ const acc = steps.get(stepId);
+ if (acc === undefined) {
+ return { stepId, usage: zeroUsage };
+ }
+ const usage = acc.usage ?? zeroUsage;
+ const sm: StepMetrics = { stepId, usage };
+ if (acc.ttftMs !== undefined) {
+ (sm as { ttftMs?: number }).ttftMs = acc.ttftMs;
+ }
+ if (acc.decodeMs !== undefined) {
+ (sm as { decodeMs?: number }).decodeMs = acc.decodeMs;
+ }
+ if (acc.genTotalMs !== undefined) {
+ (sm as { genTotalMs?: number }).genTotalMs = acc.genTotalMs;
+ }
+ return sm;
+ });
- const aggregateUsage = doneUsage ?? sumStepUsage(stepMetrics);
+ const aggregateUsage = doneUsage ?? sumStepUsage(stepMetrics);
- const tm: TurnMetrics = { turnId, usage: aggregateUsage, steps: stepMetrics };
- if (doneDurationMs !== undefined) {
- (tm as { durationMs?: number }).durationMs = doneDurationMs;
- }
+ const tm: TurnMetrics = { turnId, usage: aggregateUsage, steps: stepMetrics };
+ if (doneDurationMs !== undefined) {
+ (tm as { durationMs?: number }).durationMs = doneDurationMs;
+ }
- // contextSize = final step's inputTokens + outputTokens (true context occupancy).
- // Omit when no steps or the last step had no usable per-step usage event.
- if (stepMetrics.length > 0) {
- const lastStep = stepMetrics[stepMetrics.length - 1];
- if (lastStep !== undefined) {
- const lastAcc = steps.get(lastStep.stepId);
- if (lastAcc?.usage !== undefined) {
- (tm as { contextSize?: number }).contextSize =
- lastStep.usage.inputTokens + lastStep.usage.outputTokens;
- }
- }
- }
+ // contextSize = final step's inputTokens + outputTokens (true context occupancy).
+ // Omit when no steps or the last step had no usable per-step usage event.
+ if (stepMetrics.length > 0) {
+ const lastStep = stepMetrics[stepMetrics.length - 1];
+ if (lastStep !== undefined) {
+ const lastAcc = steps.get(lastStep.stepId);
+ if (lastAcc?.usage !== undefined) {
+ (tm as { contextSize?: number }).contextSize =
+ lastStep.usage.inputTokens + lastStep.usage.outputTokens;
+ }
+ }
+ }
- return tm;
- }
+ return tm;
+ }
- function reset(): void {
- steps.clear();
- stepOrder.length = 0;
- doneUsage = undefined;
- doneDurationMs = undefined;
- }
+ function reset(): void {
+ steps.clear();
+ stepOrder.length = 0;
+ doneUsage = undefined;
+ doneDurationMs = undefined;
+ }
- return { ingest, build, reset };
+ return { ingest, build, reset };
}
function sumStepUsage(steps: readonly StepMetrics[]): Usage {
- let inputTokens = 0;
- let outputTokens = 0;
- for (const s of steps) {
- inputTokens += s.usage.inputTokens;
- outputTokens += s.usage.outputTokens;
- }
- return { inputTokens, outputTokens };
+ let inputTokens = 0;
+ let outputTokens = 0;
+ for (const s of steps) {
+ inputTokens += s.usage.inputTokens;
+ outputTokens += s.usage.outputTokens;
+ }
+ return { inputTokens, outputTokens };
}