import type { ITelemetryService } from '@moonshot-ai/agent-core-v2/app/telemetry/telemetry'; import { MAX_IMAGE_EDGE_PX, READ_IMAGE_BYTE_BUDGET, compressBase64ForModel as v2CompressBase64ForModel, compressImageForModel as v2CompressImageForModel, } from '@moonshot-ai/agent-core-v2'; import type { CompressBase64Result, CompressImageResult, ImageCompressionCaptionInput, } from '@moonshot-ai/agent-core-v2/agent/media/image-compress'; import type { ImageConfig } from '#/config/index'; import type { TelemetryClient, TelemetryProperties } from '#/telemetry'; export type { CompressBase64Result, CompressImageResult, ImageCompressionCaptionInput }; export interface ImageCompressionTelemetry { readonly client: TelemetryClient; readonly source: string; } export interface CompressImageOptions { readonly maxEdge?: number; readonly byteBudget?: number; readonly maxDecodeBytes?: number; readonly telemetry?: ImageCompressionTelemetry; } export class ImageLimits { constructor( private readonly env: Readonly> = process.env, private config: ImageConfig | undefined = undefined, ) {} setConfig(config: ImageConfig | undefined): void { this.config = config; } maxEdgePx(): number { return positiveIntFromEnv(this.env, 'KIMI_IMAGE_MAX_EDGE_PX') ?? this.config?.maxEdgePx ?? MAX_IMAGE_EDGE_PX; } readByteBudget(): number { return ( positiveIntFromEnv(this.env, 'KIMI_IMAGE_READ_BYTE_BUDGET') ?? this.config?.readByteBudget ?? READ_IMAGE_BYTE_BUDGET ); } } export function compressImageForModel( bytes: Uint8Array, mimeType: string, options: CompressImageOptions = {}, ): Promise { const { telemetry, ...rest } = options; return v2CompressImageForModel(bytes, mimeType, { ...rest, telemetry: toV2TelemetryService(telemetry), telemetrySource: telemetry?.source, }); } export function compressBase64ForModel( base64: string, mimeType: string, options: CompressImageOptions = {}, ): Promise { const { telemetry, ...rest } = options; return v2CompressBase64ForModel(base64, mimeType, { ...rest, telemetry: toV2TelemetryService(telemetry), telemetrySource: telemetry?.source, }); } function toV2TelemetryService( telemetry: ImageCompressionTelemetry | undefined, ): ITelemetryService | undefined { if (telemetry === undefined) return undefined; const client = telemetry.client; return { track2: (event: string, properties?: TelemetryProperties) => { client.track(event, properties); }, } as unknown as ITelemetryService; } function positiveIntFromEnv( env: Readonly>, name: string, ): number | undefined { const raw = env[name]?.trim(); if (raw === undefined || raw.length === 0 || !/^\d+$/.test(raw)) return undefined; const parsed = Number(raw); return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined; }