agents
Version:
A home for your AI agents
360 lines (359 loc) • 15.9 kB
JavaScript
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
import { VoiceProviderError } from "./voice/errors.js";
//#region src/voice/diagnostics.ts
const MAX_STRING_LENGTH = 160;
const PRIVATE_KEY = /(^|_)(audio|body|contents?|exceptions?|messages?|prompts?|query|results?|stack|text|tokens?|tools?|transcripts?|arguments?)(_|$)/i;
function boundedString(value, maxLength = MAX_STRING_LENGTH) {
const normalized = value.replace(/\s+/g, " ").trim();
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1)}…`;
}
function diagnosticErrorData(error) {
const summary = {
name: boundedString(error.name || "Error"),
message: boundedString(error.message || "Unknown error")
};
if (error instanceof VoiceProviderError) {
if (error.code !== void 0) summary.code = error.code;
if (error.status !== void 0) summary.status = error.status;
if (error.closeCode !== void 0) summary.closeCode = error.closeCode;
if (error.closeReason !== void 0) summary.closeReason = boundedString(error.closeReason);
if (error.wasClean !== void 0) summary.wasClean = error.wasClean;
}
return summary;
}
/**
* Keep diagnostic metadata bounded and reject fields that could carry user or
* provider content. Instrumentation should still pass only known-safe values.
*/
function sanitizeDiagnosticData(data) {
if (!data) return void 0;
const sanitized = {};
for (const [key, value] of Object.entries(data)) {
if (PRIVATE_KEY.test(key)) continue;
sanitized[key] = value instanceof Error ? diagnosticErrorData(value) : typeof value === "string" ? boundedString(value) : value;
}
return Object.keys(sanitized).length > 0 ? sanitized : void 0;
}
function createDiagnosticEvent(event, data, timestamp = Date.now()) {
const safeData = sanitizeDiagnosticData(data);
return {
event,
timestamp,
...safeData ? { data: safeData } : {}
};
}
/** Server-only diagnostics. The sink is the reserved voice protocol message. */
var ServerDiagnostics = class {
constructor(browserConsole) {
this.browserConsole = browserConsole;
}
emit(connection, event, data) {
if (!this.browserConsole) return;
try {
connection.send(JSON.stringify({
type: "diagnostic",
...createDiagnosticEvent(event, data)
}));
} catch {}
}
turn(connection, turnId, source = "speech", now = Date.now) {
return new TurnDiagnostics(this, connection, turnId, source, now);
}
};
function safeDuration(value) {
return Math.max(0, value);
}
var _turn = /* @__PURE__ */ new WeakMap();
var _startedAt = /* @__PURE__ */ new WeakMap();
/** One sentence attempt measured by its parent turn clock. */
var TtsSentenceTracker = class {
constructor(turn, startedAt) {
_classPrivateFieldInitSpec(this, _turn, void 0);
_classPrivateFieldInitSpec(this, _startedAt, void 0);
_classPrivateFieldSet2(_turn, this, turn);
_classPrivateFieldSet2(_startedAt, this, startedAt);
}
providerStarted() {
_classPrivateFieldGet2(_turn, this).recordTtsProviderStarted();
}
settle(outcome) {
return _classPrivateFieldGet2(_turn, this).recordTtsSentence(_classPrivateFieldGet2(_startedAt, this), outcome);
}
};
var _diagnostics = /* @__PURE__ */ new WeakMap();
var _connection = /* @__PURE__ */ new WeakMap();
var _now = /* @__PURE__ */ new WeakMap();
var _startedAt2 = /* @__PURE__ */ new WeakMap();
var _speechStartedAt = /* @__PURE__ */ new WeakMap();
var _firstInterimObserved = /* @__PURE__ */ new WeakMap();
var _finalInputAt = /* @__PURE__ */ new WeakMap();
var _firstTtsProviderAt = /* @__PURE__ */ new WeakMap();
var _firstAudioAt = /* @__PURE__ */ new WeakMap();
var _ttsFinished = /* @__PURE__ */ new WeakMap();
var _hasTtsFailures = /* @__PURE__ */ new WeakMap();
var _metrics = /* @__PURE__ */ new WeakMap();
/**
* One content-free turn lifecycle. Diagnostics and stable metrics are emitted
* from the same recorded landmarks; application metrics never parse event
* names or diagnostic metadata.
*/
var TurnDiagnostics = class {
constructor(diagnostics, connection, turnId, source, now) {
_classPrivateFieldInitSpec(this, _diagnostics, void 0);
_classPrivateFieldInitSpec(this, _connection, void 0);
_classPrivateFieldInitSpec(this, _now, void 0);
_classPrivateFieldInitSpec(this, _startedAt2, void 0);
_classPrivateFieldInitSpec(this, _speechStartedAt, void 0);
_classPrivateFieldInitSpec(this, _firstInterimObserved, false);
_classPrivateFieldInitSpec(this, _finalInputAt, void 0);
_classPrivateFieldInitSpec(this, _firstTtsProviderAt, void 0);
_classPrivateFieldInitSpec(this, _firstAudioAt, void 0);
_classPrivateFieldInitSpec(this, _ttsFinished, false);
_classPrivateFieldInitSpec(this, _hasTtsFailures, false);
_classPrivateFieldInitSpec(this, _metrics, {});
_classPrivateFieldSet2(_diagnostics, this, diagnostics);
_classPrivateFieldSet2(_connection, this, connection);
_classPrivateFieldSet2(_now, this, now);
_classPrivateFieldSet2(_startedAt2, this, now());
this.turnId = turnId;
this.source = source;
}
get hasTtsFailures() {
return _classPrivateFieldGet2(_hasTtsFailures, this);
}
get ttsWorkMs() {
return _classPrivateFieldGet2(_metrics, this).ttsWorkMs ?? 0;
}
emit(event, data) {
const scopedData = {
...data,
turn_id: this.turnId
};
_classPrivateFieldGet2(_diagnostics, this).emit(_classPrivateFieldGet2(_connection, this), event, scopedData);
}
startModel() {
return new ModelDiagnosticTracker(this, _classPrivateFieldGet2(_now, this));
}
markTextInput() {
_classPrivateFieldGet2(_finalInputAt, this) ?? _classPrivateFieldSet2(_finalInputAt, this, _classPrivateFieldGet2(_startedAt2, this));
}
speechStarted() {
_classPrivateFieldGet2(_speechStartedAt, this) ?? _classPrivateFieldSet2(_speechStartedAt, this, _classPrivateFieldGet2(_now, this).call(this));
this.emit("speech.started");
}
firstInterim(characters) {
if (_classPrivateFieldGet2(_firstInterimObserved, this)) return;
_classPrivateFieldSet2(_firstInterimObserved, this, true);
const elapsed = _classPrivateFieldGet2(_speechStartedAt, this) === void 0 ? void 0 : safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_speechStartedAt, this));
if (elapsed !== void 0) _classPrivateFieldGet2(_metrics, this).speechStartToFirstInterimMs = elapsed;
this.emit("stt.interim", {
...characters === void 0 ? {} : { characters },
...elapsed === void 0 ? {} : { speech_to_interim_ms: elapsed }
});
}
finalInput(characters) {
_classPrivateFieldSet2(_finalInputAt, this, _classPrivateFieldGet2(_now, this).call(this));
const elapsed = _classPrivateFieldGet2(_speechStartedAt, this) === void 0 ? void 0 : safeDuration(_classPrivateFieldGet2(_finalInputAt, this) - _classPrivateFieldGet2(_speechStartedAt, this));
if (elapsed !== void 0) _classPrivateFieldGet2(_metrics, this).speechStartToFinalMs = elapsed;
this.emit("stt.utterance", {
...characters === void 0 ? {} : { characters },
...elapsed === void 0 ? {} : { speech_to_final_ms: elapsed }
});
}
recordAfterTranscribe(durationMs, outcome, characters) {
_classPrivateFieldGet2(_metrics, this).afterTranscribeMs = safeDuration(durationMs);
this.emit("after_transcribe.completed", {
duration_ms: safeDuration(durationMs),
outcome,
characters
});
}
beginTtsSentence() {
_classPrivateFieldGet2(_metrics, this).ttsWorkMs ??= 0;
return new TtsSentenceTracker(this, _classPrivateFieldGet2(_now, this).call(this));
}
recordTtsProviderStarted() {
_classPrivateFieldGet2(_firstTtsProviderAt, this) ?? _classPrivateFieldSet2(_firstTtsProviderAt, this, _classPrivateFieldGet2(_now, this).call(this));
}
recordTtsSentence(startedAt, outcome) {
const duration = safeDuration(_classPrivateFieldGet2(_now, this).call(this) - startedAt);
_classPrivateFieldGet2(_metrics, this).ttsWorkMs = (_classPrivateFieldGet2(_metrics, this).ttsWorkMs ?? 0) + duration;
if (outcome === "failed") _classPrivateFieldSet2(_hasTtsFailures, this, true);
return duration;
}
finishTts() {
if (_classPrivateFieldGet2(_ttsFinished, this)) return;
_classPrivateFieldSet2(_ttsFinished, this, true);
if (_classPrivateFieldGet2(_firstTtsProviderAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).ttsWallMs = safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_firstTtsProviderAt, this));
}
audioSent() {
const now = _classPrivateFieldGet2(_now, this).call(this);
if (_classPrivateFieldGet2(_firstAudioAt, this) !== void 0) return;
_classPrivateFieldSet2(_firstAudioAt, this, now);
if (_classPrivateFieldGet2(_finalInputAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).finalInputToFirstAudioMs = safeDuration(now - _classPrivateFieldGet2(_finalInputAt, this));
if (_classPrivateFieldGet2(_firstTtsProviderAt, this) !== void 0) _classPrivateFieldGet2(_metrics, this).ttsToFirstAudioMs = safeDuration(now - _classPrivateFieldGet2(_firstTtsProviderAt, this));
}
recordModelFirstText(durationMs) {
_classPrivateFieldGet2(_metrics, this).modelToFirstTextMs = safeDuration(durationMs);
}
recordReasoning(durationMs) {
_classPrivateFieldGet2(_metrics, this).exposedReasoningMs = (_classPrivateFieldGet2(_metrics, this).exposedReasoningMs ?? 0) + safeDuration(durationMs);
}
recordModelTerminal(durationMs) {
_classPrivateFieldGet2(_metrics, this).modelStreamConsumptionMs = safeDuration(durationMs);
}
finish(outcome) {
this.finishTts();
const summary = {
turnId: this.turnId,
source: this.source,
outcome,
turnTotalMs: safeDuration(_classPrivateFieldGet2(_now, this).call(this) - _classPrivateFieldGet2(_startedAt2, this)),
..._classPrivateFieldGet2(_metrics, this)
};
this.emit("turn.ended", {
outcome,
duration_ms: summary.turnTotalMs
});
try {
_classPrivateFieldGet2(_connection, this).send(JSON.stringify({
type: "turn_metrics",
...summary
}));
} catch {}
return summary;
}
};
var _turn2 = /* @__PURE__ */ new WeakMap();
var _now2 = /* @__PURE__ */ new WeakMap();
var _startedAt3 = /* @__PURE__ */ new WeakMap();
var _firstTextObserved = /* @__PURE__ */ new WeakMap();
var _reasoningActive = /* @__PURE__ */ new WeakMap();
var _reasoningStartedAt = /* @__PURE__ */ new WeakMap();
var _characters = /* @__PURE__ */ new WeakMap();
var _terminal = /* @__PURE__ */ new WeakMap();
var _ModelDiagnosticTracker_brand = /* @__PURE__ */ new WeakSet();
/**
* Tracks one model stream without retaining model or reasoning content.
* Lifecycle methods are idempotent so stale turn cleanup cannot affect a
* successor tracker.
*/
var ModelDiagnosticTracker = class {
constructor(turn, now) {
_classPrivateMethodInitSpec(this, _ModelDiagnosticTracker_brand);
_classPrivateFieldInitSpec(this, _turn2, void 0);
_classPrivateFieldInitSpec(this, _now2, void 0);
_classPrivateFieldInitSpec(this, _startedAt3, void 0);
_classPrivateFieldInitSpec(this, _firstTextObserved, false);
_classPrivateFieldInitSpec(this, _reasoningActive, false);
_classPrivateFieldInitSpec(this, _reasoningStartedAt, 0);
_classPrivateFieldInitSpec(this, _characters, 0);
_classPrivateFieldInitSpec(this, _terminal, false);
_classPrivateFieldSet2(_turn2, this, turn);
_classPrivateFieldSet2(_now2, this, now);
_classPrivateFieldSet2(_startedAt3, this, now());
_classPrivateFieldGet2(_turn2, this).emit("model.started");
}
observe(event) {
if (_classPrivateFieldGet2(_terminal, this)) return;
switch (event.type) {
case "text":
_classPrivateFieldSet2(_characters, this, _classPrivateFieldGet2(_characters, this) + event.text.length);
if (!_classPrivateFieldGet2(_firstTextObserved, this) && event.text.trim().length > 0) {
_classPrivateFieldSet2(_firstTextObserved, this, true);
const elapsed = safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_startedAt3, this));
_classPrivateFieldGet2(_turn2, this).recordModelFirstText(elapsed);
_classPrivateFieldGet2(_turn2, this).emit("model.first_text", { elapsed_ms: elapsed });
}
break;
case "reasoning-start":
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _startReasoning).call(this);
break;
case "reasoning-end":
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "completed");
break;
case "finish":
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "stream_finished");
break;
case "error": break;
case "boundary": break;
}
}
complete(outcome, finishReason) {
if (_classPrivateFieldGet2(_terminal, this)) return;
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "stream_completed");
_classPrivateFieldSet2(_terminal, this, true);
const duration = this.elapsedMs();
_classPrivateFieldGet2(_turn2, this).recordModelTerminal(duration);
_classPrivateFieldGet2(_turn2, this).emit("model.completed", {
duration_ms: duration,
outcome,
characters: _classPrivateFieldGet2(_characters, this),
...finishReason === void 0 ? {} : { finish_reason: finishReason }
});
}
fail(error) {
if (_classPrivateFieldGet2(_terminal, this)) return;
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "error");
_classPrivateFieldSet2(_terminal, this, true);
_classPrivateFieldGet2(_turn2, this).recordModelTerminal(this.elapsedMs());
_classPrivateFieldGet2(_turn2, this).emit("model.failed", { error });
}
abort() {
if (_classPrivateFieldGet2(_terminal, this)) return;
_assertClassBrand(_ModelDiagnosticTracker_brand, this, _completeReasoning).call(this, "aborted");
_classPrivateFieldSet2(_terminal, this, true);
_classPrivateFieldGet2(_turn2, this).recordModelTerminal(this.elapsedMs());
}
elapsedMs() {
return safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_startedAt3, this));
}
};
function _startReasoning() {
if (_classPrivateFieldGet2(_reasoningActive, this)) return;
_classPrivateFieldSet2(_reasoningActive, this, true);
_classPrivateFieldSet2(_reasoningStartedAt, this, _classPrivateFieldGet2(_now2, this).call(this));
_classPrivateFieldGet2(_turn2, this).emit("model.reasoning_started");
}
function _completeReasoning(outcome) {
if (!_classPrivateFieldGet2(_reasoningActive, this)) return;
_classPrivateFieldSet2(_reasoningActive, this, false);
const duration = safeDuration(_classPrivateFieldGet2(_now2, this).call(this) - _classPrivateFieldGet2(_reasoningStartedAt, this));
_classPrivateFieldGet2(_turn2, this).recordReasoning(duration);
_classPrivateFieldGet2(_turn2, this).emit("model.reasoning_completed", {
duration_ms: duration,
outcome
});
}
var _enabled = /* @__PURE__ */ new WeakMap();
var _ClientDiagnostics_brand = /* @__PURE__ */ new WeakSet();
/** Browser-only diagnostics. Activation always comes from the server welcome. */
var ClientDiagnostics = class {
constructor() {
_classPrivateMethodInitSpec(this, _ClientDiagnostics_brand);
_classPrivateFieldInitSpec(this, _enabled, false);
}
setEnabled(enabled) {
_classPrivateFieldSet2(_enabled, this, enabled);
}
emit(event, data) {
if (!_classPrivateFieldGet2(_enabled, this)) return;
_assertClassBrand(_ClientDiagnostics_brand, this, _log).call(this, "client", createDiagnosticEvent(event, data));
}
receive(event) {
if (!_classPrivateFieldGet2(_enabled, this)) return;
_assertClassBrand(_ClientDiagnostics_brand, this, _log).call(this, "server", event);
}
};
function _log(origin, event) {
try {
console.info(`[voice:${origin}] ${event.event}`, {
timestamp: event.timestamp,
...event.data ?? {}
});
} catch {}
}
//#endregion
export { ServerDiagnostics as n, ClientDiagnostics as t };
//# sourceMappingURL=diagnostics-C4jcz3VK.js.map