Files
callstack__agent-device/src/snapshot-capture-annotations.ts
T
Michał Pierzchała 0425df2be6 refactor: bundle snapshot capture annotations (#777)
* refactor: bundle snapshot capture annotations

* refactor: address snapshot annotations review

* test: cover snapshot annotation quality mapping
2026-06-12 12:43:13 +02:00

81 lines
2.7 KiB
TypeScript

import type { AndroidSnapshotBackendMetadata } from './platforms/android/snapshot-types.ts';
import {
readSnapshotQualityVerdict,
type SnapshotQualityVerdict,
} from './utils/snapshot-quality.ts';
export type SnapshotCaptureAnalysis = {
rawNodeCount: number;
maxDepth: number;
};
export type SnapshotCaptureFreshness = {
action: string;
retryCount: number;
staleAfterRetries: boolean;
reason?: 'empty-interactive' | 'sharp-drop' | 'stuck-route';
};
export type SnapshotCaptureAnnotations = {
analysis?: SnapshotCaptureAnalysis;
androidSnapshot?: AndroidSnapshotBackendMetadata;
freshness?: SnapshotCaptureFreshness;
quality?: SnapshotQualityVerdict;
warnings?: string[];
};
export type PublicSnapshotCaptureAnnotations = Pick<
SnapshotCaptureAnnotations,
'androidSnapshot' | 'warnings'
> & {
snapshotQuality?: SnapshotQualityVerdict;
};
export function snapshotCaptureAnnotationsFrom(
source: Partial<Omit<SnapshotCaptureAnnotations, 'quality'>> & { quality?: unknown },
): SnapshotCaptureAnnotations {
const quality = readSnapshotQualityVerdict(source.quality);
return {
...(source.analysis ? { analysis: source.analysis } : {}),
...(source.androidSnapshot ? { androidSnapshot: source.androidSnapshot } : {}),
...(source.freshness ? { freshness: source.freshness } : {}),
...(quality ? { quality } : {}),
...(source.warnings ? { warnings: source.warnings } : {}),
};
}
export function publicSnapshotCaptureAnnotations(
annotations: Partial<SnapshotCaptureAnnotations>,
): PublicSnapshotCaptureAnnotations {
return {
...(annotations.androidSnapshot ? { androidSnapshot: annotations.androidSnapshot } : {}),
...(annotations.quality ? { snapshotQuality: annotations.quality } : {}),
...(annotations.warnings && annotations.warnings.length > 0
? { warnings: annotations.warnings }
: {}),
};
}
export function readSerializedSnapshotCaptureAnnotations(
data: Record<string, unknown>,
): PublicSnapshotCaptureAnnotations {
const androidSnapshot = readObject(data.androidSnapshot);
const warnings = Array.isArray(data.warnings)
? data.warnings.filter((entry): entry is string => typeof entry === 'string')
: undefined;
const quality = readSnapshotQualityVerdict(data.snapshotQuality);
return publicSnapshotCaptureAnnotations({
...(androidSnapshot
? { androidSnapshot: androidSnapshot as AndroidSnapshotBackendMetadata }
: {}),
...(quality ? { quality } : {}),
...(warnings ? { warnings } : {}),
});
}
function readObject(value: unknown): Record<string, unknown> | undefined {
return typeof value === 'object' && value !== null
? (value as Record<string, unknown>)
: undefined;
}