{"version":3,"file":"agent/metrics.mjs","sources":["../../../src/agent/metrics.ts"],"sourcesContent":["import type { AIUsageInfo } from '@/types';\n\n/**\n * Aggregated usage for a single grouping key (intent or model).\n */\nexport interface UsageBucket {\n  promptTokens: number;\n  completionTokens: number;\n  totalTokens: number;\n  calls: number;\n}\n\n/**\n * Instance-level snapshot of LLM usage accumulated by an Agent.\n *\n * Designed for cost observability: read it back after a logical unit of work\n * and push to tools like Langfuse. `byIntent` / `byModel` provide free\n * breakdowns derived from the usage data Midscene already records per call.\n */\nexport interface MidsceneUsageMetrics {\n  totalPromptTokens: number;\n  totalCompletionTokens: number;\n  totalTokens: number;\n  totalCachedInput: number;\n  totalTimeCostMs: number;\n  calls: number;\n  byIntent: Record<string, UsageBucket>;\n  byModel: Record<string, UsageBucket>;\n}\n\nconst emptyBucket = (): UsageBucket => ({\n  promptTokens: 0,\n  completionTokens: 0,\n  totalTokens: 0,\n  calls: 0,\n});\n\nconst addToBucket = (\n  map: Record<string, UsageBucket>,\n  key: string,\n  prompt: number,\n  completion: number,\n  total: number,\n): void => {\n  if (!map[key]) {\n    map[key] = emptyBucket();\n  }\n  const bucket = map[key];\n  bucket.promptTokens += prompt;\n  bucket.completionTokens += completion;\n  bucket.totalTokens += total;\n  bucket.calls += 1;\n};\n\n/**\n * Pure accumulator for {@link AIUsageInfo}. Deduplication of calls is the\n * caller's responsibility; every `add` counts as one call.\n */\nexport class MetricsCollector {\n  private totalPromptTokens = 0;\n  private totalCompletionTokens = 0;\n  private totalTokens = 0;\n  private totalCachedInput = 0;\n  private totalTimeCostMs = 0;\n  private calls = 0;\n  private byIntent: Record<string, UsageBucket> = {};\n  private byModel: Record<string, UsageBucket> = {};\n\n  add(usage: AIUsageInfo): void {\n    const prompt = usage.prompt_tokens ?? 0;\n    const completion = usage.completion_tokens ?? 0;\n    const total = usage.total_tokens ?? 0;\n\n    this.totalPromptTokens += prompt;\n    this.totalCompletionTokens += completion;\n    this.totalTokens += total;\n    this.totalCachedInput += usage.cached_input ?? 0;\n    this.totalTimeCostMs += usage.time_cost ?? 0;\n    this.calls += 1;\n\n    addToBucket(\n      this.byIntent,\n      usage.intent ?? 'unknown',\n      prompt,\n      completion,\n      total,\n    );\n    addToBucket(\n      this.byModel,\n      usage.model_name ?? 'unknown',\n      prompt,\n      completion,\n      total,\n    );\n  }\n\n  snapshot(): MidsceneUsageMetrics {\n    const cloneBuckets = (\n      map: Record<string, UsageBucket>,\n    ): Record<string, UsageBucket> => {\n      const out: Record<string, UsageBucket> = {};\n      for (const [key, bucket] of Object.entries(map)) {\n        out[key] = { ...bucket };\n      }\n      return out;\n    };\n\n    return {\n      totalPromptTokens: this.totalPromptTokens,\n      totalCompletionTokens: this.totalCompletionTokens,\n      totalTokens: this.totalTokens,\n      totalCachedInput: this.totalCachedInput,\n      totalTimeCostMs: this.totalTimeCostMs,\n      calls: this.calls,\n      byIntent: cloneBuckets(this.byIntent),\n      byModel: cloneBuckets(this.byModel),\n    };\n  }\n\n  /**\n   * Clear all accumulated state. Not wired to a public Agent API yet; kept for\n   * a future per-unit reset (e.g. resetting metrics at the start of a spec).\n   */\n  reset(): void {\n    this.totalPromptTokens = 0;\n    this.totalCompletionTokens = 0;\n    this.totalTokens = 0;\n    this.totalCachedInput = 0;\n    this.totalTimeCostMs = 0;\n    this.calls = 0;\n    this.byIntent = {};\n    this.byModel = {};\n  }\n}\n"],"names":["emptyBucket","addToBucket","map","key","prompt","completion","total","bucket","MetricsCollector","usage","cloneBuckets","out","Object"],"mappings":";;;;;;;;;;AA8BA,MAAMA,cAAc,IAAoB;QACtC,cAAc;QACd,kBAAkB;QAClB,aAAa;QACb,OAAO;IACT;AAEA,MAAMC,cAAc,CAClBC,KACAC,KACAC,QACAC,YACAC;IAEA,IAAI,CAACJ,GAAG,CAACC,IAAI,EACXD,GAAG,CAACC,IAAI,GAAGH;IAEb,MAAMO,SAASL,GAAG,CAACC,IAAI;IACvBI,OAAO,YAAY,IAAIH;IACvBG,OAAO,gBAAgB,IAAIF;IAC3BE,OAAO,WAAW,IAAID;IACtBC,OAAO,KAAK,IAAI;AAClB;AAMO,MAAMC;IAUX,IAAIC,KAAkB,EAAQ;QAC5B,MAAML,SAASK,MAAM,aAAa,IAAI;QACtC,MAAMJ,aAAaI,MAAM,iBAAiB,IAAI;QAC9C,MAAMH,QAAQG,MAAM,YAAY,IAAI;QAEpC,IAAI,CAAC,iBAAiB,IAAIL;QAC1B,IAAI,CAAC,qBAAqB,IAAIC;QAC9B,IAAI,CAAC,WAAW,IAAIC;QACpB,IAAI,CAAC,gBAAgB,IAAIG,MAAM,YAAY,IAAI;QAC/C,IAAI,CAAC,eAAe,IAAIA,MAAM,SAAS,IAAI;QAC3C,IAAI,CAAC,KAAK,IAAI;QAEdR,YACE,IAAI,CAAC,QAAQ,EACbQ,MAAM,MAAM,IAAI,WAChBL,QACAC,YACAC;QAEFL,YACE,IAAI,CAAC,OAAO,EACZQ,MAAM,UAAU,IAAI,WACpBL,QACAC,YACAC;IAEJ;IAEA,WAAiC;QAC/B,MAAMI,eAAe,CACnBR;YAEA,MAAMS,MAAmC,CAAC;YAC1C,KAAK,MAAM,CAACR,KAAKI,OAAO,IAAIK,OAAO,OAAO,CAACV,KACzCS,GAAG,CAACR,IAAI,GAAG;gBAAE,GAAGI,MAAM;YAAC;YAEzB,OAAOI;QACT;QAEA,OAAO;YACL,mBAAmB,IAAI,CAAC,iBAAiB;YACzC,uBAAuB,IAAI,CAAC,qBAAqB;YACjD,aAAa,IAAI,CAAC,WAAW;YAC7B,kBAAkB,IAAI,CAAC,gBAAgB;YACvC,iBAAiB,IAAI,CAAC,eAAe;YACrC,OAAO,IAAI,CAAC,KAAK;YACjB,UAAUD,aAAa,IAAI,CAAC,QAAQ;YACpC,SAASA,aAAa,IAAI,CAAC,OAAO;QACpC;IACF;IAMA,QAAc;QACZ,IAAI,CAAC,iBAAiB,GAAG;QACzB,IAAI,CAAC,qBAAqB,GAAG;QAC7B,IAAI,CAAC,WAAW,GAAG;QACnB,IAAI,CAAC,gBAAgB,GAAG;QACxB,IAAI,CAAC,eAAe,GAAG;QACvB,IAAI,CAAC,KAAK,GAAG;QACb,IAAI,CAAC,QAAQ,GAAG,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,CAAC;IAClB;;QAzEA,uBAAQ,qBAAoB;QAC5B,uBAAQ,yBAAwB;QAChC,uBAAQ,eAAc;QACtB,uBAAQ,oBAAmB;QAC3B,uBAAQ,mBAAkB;QAC1B,uBAAQ,SAAQ;QAChB,uBAAQ,YAAwC,CAAC;QACjD,uBAAQ,WAAuC,CAAC;;AAmElD"}