
























@@ -217,7 +217,7 @@ function positiveFiniteNumber(value: number | undefined): number | undefined {
217217}
218218219219function assignPositiveNumberAttr(
220-attrs: Record<string, string | number>,
220+attrs: Record<string, string | number | boolean>,
221221key: string,
222222value: number | undefined,
223223): void {
@@ -227,6 +227,23 @@ function assignPositiveNumberAttr(
227227}
228228}
229229230+function assignModelCallSizeTimingAttrs(
231+attrs: Record<string, string | number | boolean>,
232+evt: {
233+requestPayloadBytes?: number;
234+responseStreamBytes?: number;
235+timeToFirstByteMs?: number;
236+},
237+): void {
238+assignPositiveNumberAttr(attrs, "openclaw.model_call.request_bytes", evt.requestPayloadBytes);
239+assignPositiveNumberAttr(attrs, "openclaw.model_call.response_bytes", evt.responseStreamBytes);
240+assignPositiveNumberAttr(
241+attrs,
242+"openclaw.model_call.time_to_first_byte_ms",
243+evt.timeToFirstByteMs,
244+);
245+}
246+230247function assignGenAiSpanIdentityAttrs(
231248attrs: Record<string, string | number | boolean>,
232249input: { api?: string; model?: string; provider?: string },
@@ -812,6 +829,27 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
812829unit: "ms",
813830description: "Model call duration",
814831});
832+const modelCallRequestBytesHistogram = meter.createHistogram(
833+"openclaw.model_call.request_bytes",
834+{
835+unit: "By",
836+description: "UTF-8 byte size of sanitized model request payloads",
837+},
838+);
839+const modelCallResponseBytesHistogram = meter.createHistogram(
840+"openclaw.model_call.response_bytes",
841+{
842+unit: "By",
843+description: "UTF-8 byte size of streamed model response events",
844+},
845+);
846+const modelCallTimeToFirstByteHistogram = meter.createHistogram(
847+"openclaw.model_call.time_to_first_byte_ms",
848+{
849+unit: "ms",
850+description: "Elapsed time before the first streamed model response event",
851+},
852+);
815853const toolExecutionDurationHistogram = meter.createHistogram(
816854"openclaw.tool.execution.duration_ms",
817855{
@@ -1700,6 +1738,23 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
17001738"gen_ai.request.model": lowCardinalityAttr(evt.model),
17011739 ...(errorType ? { "error.type": errorType } : {}),
17021740});
1741+const recordModelCallSizeTimingMetrics = (
1742+evt: Extract<DiagnosticEventPayload, { type: "model.call.completed" | "model.call.error" }>,
1743+attrs: ReturnType<typeof modelCallMetricAttrs>,
1744+) => {
1745+const requestPayloadBytes = positiveFiniteNumber(evt.requestPayloadBytes);
1746+if (requestPayloadBytes !== undefined) {
1747+modelCallRequestBytesHistogram.record(requestPayloadBytes, attrs);
1748+}
1749+const responseStreamBytes = positiveFiniteNumber(evt.responseStreamBytes);
1750+if (responseStreamBytes !== undefined) {
1751+modelCallResponseBytesHistogram.record(responseStreamBytes, attrs);
1752+}
1753+const timeToFirstByteMs = positiveFiniteNumber(evt.timeToFirstByteMs);
1754+if (timeToFirstByteMs !== undefined) {
1755+modelCallTimeToFirstByteHistogram.record(timeToFirstByteMs, attrs);
1756+}
1757+};
1703175817041759const recordModelCallStarted = (
17051760evt: Extract<DiagnosticEventPayload, { type: "model.call.started" }>,
@@ -1733,7 +1788,9 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
17331788evt: Extract<DiagnosticEventPayload, { type: "model.call.completed" }>,
17341789metadata: DiagnosticEventMetadata,
17351790) => {
1736-modelCallDurationHistogram.record(evt.durationMs, modelCallMetricAttrs(evt));
1791+const metricAttrs = modelCallMetricAttrs(evt);
1792+modelCallDurationHistogram.record(evt.durationMs, metricAttrs);
1793+recordModelCallSizeTimingMetrics(evt, metricAttrs);
17371794genAiOperationDurationHistogram.record(
17381795evt.durationMs / 1000,
17391796genAiModelCallMetricAttrs(evt),
@@ -1752,6 +1809,7 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
17521809if (evt.transport) {
17531810spanAttrs["openclaw.transport"] = evt.transport;
17541811}
1812+assignModelCallSizeTimingAttrs(spanAttrs, evt);
17551813assignOtelModelContentAttributes(
17561814spanAttrs,
17571815evt as unknown as Record<string, unknown>,
@@ -1773,10 +1831,12 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
17731831metadata: DiagnosticEventMetadata,
17741832) => {
17751833const errorType = lowCardinalityAttr(evt.errorCategory, "other");
1776-modelCallDurationHistogram.record(evt.durationMs, {
1834+const metricAttrs = {
17771835 ...modelCallMetricAttrs(evt),
17781836"openclaw.errorCategory": errorType,
1779-});
1837+};
1838+modelCallDurationHistogram.record(evt.durationMs, metricAttrs);
1839+recordModelCallSizeTimingMetrics(evt, metricAttrs);
17801840genAiOperationDurationHistogram.record(
17811841evt.durationMs / 1000,
17821842genAiModelCallMetricAttrs(evt, errorType),
@@ -1797,6 +1857,7 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
17971857if (evt.transport) {
17981858spanAttrs["openclaw.transport"] = evt.transport;
17991859}
1860+assignModelCallSizeTimingAttrs(spanAttrs, evt);
18001861assignOtelModelContentAttributes(
18011862spanAttrs,
18021863evt as unknown as Record<string, unknown>,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。