UNPKG

synthex

Version:

Type-safe LLM response simulation with streaming & error injection

508 lines (507 loc) 18.8 kB
declare class SchemaIO { /** * Serialize a schema to JSON string. */ static toJSON(schema: SchemaForm): string; /** * Deserialize a schema from JSON string. */ static fromJSON(json: string): SchemaForm; /** * Serialize a schema to YAML string (if js-yaml is available). */ static toYAML(schema: SchemaForm): string; /** * Deserialize a schema from YAML string (if js-yaml is available). */ static fromYAML(yamlStr: string): SchemaForm; /** * Save a schema to a file (JSON or YAML by extension). */ static saveToFile(schema: SchemaForm, filePath: string): void; /** * Load a schema from a file (JSON or YAML by extension). */ static loadFromFile(filePath: string): SchemaForm; } export { SchemaIO }; /** * Type for a literal value or a weighted object for enums. */ type EnumValue<T> = T | { value: T; weight: number; }; /** * Defines the structure and constraints for a single field within a schema. * Represents the internal representation of a field after the builder constructs it. */ interface SchemaField<T = any> { type: "string" | "number" | "boolean" | "array" | "object" | "enum" | "uuid" | "email" | "url" | "date" | "union" | "intersection" | "nullable" | "reference"; required?: boolean; min?: number; max?: number; items?: SchemaField; properties?: Record<string, SchemaField>; enum?: Array<EnumValue<any>>; pattern?: string; format?: "date" | "date-time"; unionTypes?: SchemaField[]; intersectionTypes?: SchemaField[]; reference?: string; nullableType?: SchemaField; probability?: number; condition?: (currentData: Record<string, any>, globalContext: Record<string, any>) => boolean; template?: string; simulateError?: boolean; errorType?: string; generateFn?: (context: Record<string, any>, currentData: Record<string, any>, rng: RandomGenerator) => T; } /** * Represents a compiled schema for structured data, typically for an object type. * This is what m.object().build() returns. */ declare class SchemaForm<T = any> implements SchemaField<T> { type: SchemaField["type"]; _isSchemaForm: true; name?: string; version?: string; fields: Record<string, SchemaField<any>>; /** * This property is only for type extraction, not runtime use. * Use as: type MyType = typeof schema.infer */ readonly infer: T; required?: boolean; min?: number; max?: number; items?: SchemaField; properties?: Record<string, SchemaField>; enum?: Array<EnumValue<any>>; pattern?: string; format?: "date" | "date-time"; unionTypes?: SchemaField[]; intersectionTypes?: SchemaField[]; reference?: string; nullableType?: SchemaField; probability?: number; condition?: (currentData: Record<string, any>, globalContext: Record<string, any>) => boolean; template?: string; simulateError?: boolean; errorType?: string; generateFn?: (context: Record<string, any>, currentData: Record<string, any>, rng: RandomGenerator) => T; constructor(params: { name?: string; version?: string; fields: Record<string, SchemaField<any>>; required?: boolean; min?: number; max?: number; items?: SchemaField; properties?: Record<string, SchemaField>; enum?: Array<EnumValue<any>>; pattern?: string; format?: "date" | "date-time"; unionTypes?: SchemaField[]; intersectionTypes?: SchemaField[]; reference?: string; nullableType?: SchemaField; probability?: number; condition?: (currentData: Record<string, any>, globalContext: Record<string, any>) => boolean; template?: string; simulateError?: boolean; errorType?: string; generateFn?: (context: Record<string, any>, currentData: Record<string, any>, rng: RandomGenerator) => T; }); } /** * Represents a collection of schemas, allowing for structured data definitions * and references between them. */ interface SchemaCollection { name: string; version: string; schemas: SchemaForm[]; } /** * Represents a mock response structure, including the schema and the data. */ interface MockResponse<T = any> { schema: SchemaForm; data: T; metadata?: { generatedAt: string; generator: string; version: string; seed?: number; tokenUsage: number; modelInfo: string; latencyMs: number; roles?: Array<"system" | "user" | "assistant" | "tool">; log?: { requestTime: number; requestId: string; }; rateLimit?: number; quota?: number; quotaUsed?: number; finishReason?: string; stopSequence?: string; [key: string]: any; }; tokens?: string[]; finishReason?: string; } /** * Configuration options for the mock generator. */ interface MockGeneratorOptions { seed?: number; locale?: string; dateRange?: { start: Date; end: Date; }; simulateError?: boolean; errorProbability?: number; context?: Record<string, any>; metadata?: Record<string, any>; tokenUsage?: number; modelInfo?: string; latencyMs?: number; randomness?: "deterministic" | "fuzz" | "random"; outputFormat?: "json" | "xml" | "markdown"; maxTokens?: number; roles?: Array<"system" | "user" | "assistant" | "tool">; logTrace?: boolean; rateLimit?: number; rateLimitIntervalMs?: number; quota?: number; quotaUsed?: number; abortSignal?: AbortSignal; hallucinate?: boolean; hallucinationProbability?: number; simulateFunctionCall?: boolean; streamChunkSize?: number; streamDelayMs?: number; } /** * Error class for schema validation and generation errors. */ declare class SyntexError extends Error { code: string; constructor(message: string, code: string); } /** * Utility class for generating random values with constraints. * * */ declare class RandomGenerator { private seed; private rng; private randomness; constructor(seed?: number, randomness?: "deterministic" | "fuzz" | "random"); private createSeededRandom; random(): number; randomInt(min: number, max: number): number; randomChoice<T>(array: T[]): T; randomWeightedChoice<T>(items: Array<EnumValue<T>>): T; randomString(length: number, charset?: string): string; randomEmail(): string; randomUrl(): string; randomUuid(): string; randomDate(start?: Date, end?: Date): Date; randomBoolean(): boolean; } /** * Main mock generator class that creates structured data based on schemas. */ type SynthexPlugin = { name: string; onInit?: (generator: MockGenerator) => void; onGenerateField?: (field: SchemaField, context: Record<string, any>, currentData: Record<string, any>, rng: RandomGenerator) => any | undefined; }; declare class MockGenerator { private rng; private options; private requestCount; private lastReset; private registeredSchemas; private static _plugins; private _plugins; static registerPlugin(plugin: SynthexPlugin): void; constructor(options?: MockGeneratorOptions); /** * Registers a schema to be available for references within other schemas. * @param schema The SchemaForm to register. */ registerSchema(schema: SchemaForm): void; /** * Simulate streaming tokens for a given string field. * Returns an array of tokens and a finish reason. */ streamTokens(text: string, maxTokens?: number, stopSequence?: string): { tokens: string[]; finishReason: string; }; /** * Generates mock data based on the provided schema form. */ generate<T>(schema: SchemaForm<T>): MockResponse<T>; /** * Generates multiple mock responses based on the schema. */ generateMultiple<T>(schema: SchemaForm<T>, count: number): MockResponse<T>[]; /** * Generates mock data from a schema collection by name. */ generateFromCollection<T>(collection: SchemaCollection, schemaName: string): MockResponse<T>; streamGenerate<T>(schema: SchemaForm<T>, chunkSize?: number, delayMs?: number): AsyncGenerator<Record<string, any>, void, unknown>; /** * Simulate hallucination for a field (random or nonsense value). */ private simulateHallucination; /** * Simulate an OpenAI function/tool call response. */ simulateFunctionCall(functionName: string, args?: Record<string, any>): any; formatOutput(response: MockResponse): string; private toXML; private toMarkdown; private validateSchema; private validateField; private generateObjectData; private interpolateTemplate; private generateFieldValue; private generateString; private generatePatternString; private generateNumber; private generateArray; private generateDate; private handleRateLimiting; private handleQuota; private handleGlobalErrorSimulation; } /** * Base class for all schema field builders. * Handles common modifiers like required, min, max, probability, condition, template, etc. * @template TInfer The inferred TypeScript type of the field. */ declare abstract class SBase<TInfer = any> { protected _field: Partial<SchemaField>; protected _type: SchemaField["type"]; constructor(type: SchemaField["type"]); /** Marks the field as required. */ required(): this; /** Marks the field as optional (default behavior). */ optional(): this; /** Sets the minimum value for numbers, minimum length for strings/arrays. */ min(val: number): this; /** Sets the maximum value for numbers, maximum length for strings/arrays. */ max(val: number): this; /** Sets a regex pattern for string generation. */ pattern(p: string): this; /** Sets a format for date generation (e.g., "date-time" or "date"). */ format(f: "date" | "date-time"): this; /** Sets the probability (0-1) that this field will be included in the output. */ probability(p: number): this; /** * Defines a condition function for field inclusion. * The field will only be generated if the condition returns true. * @param conditionFn A function that receives the `currentData` (generated fields within the current object) and `globalContext` and returns a boolean. */ condition(conditionFn: (currentData: Record<string, any>, globalContext: Record<string, any>) => boolean): this; /** * A simplified `when` helper for common conditional logic. * Includes the field only if `fieldName` in `currentData` equals `value`. * For more complex logic, use `condition()`. * @param fieldName The name of another field in the same object. * @param value The value the `fieldName` should have for this field to be included. */ when(fieldName: string, value: any): this; /** Sets a string template for the field's value. Can use `{{key}}` for context values or other fields. */ template(t: string): this; /** Enables simulation of an error for this specific field. */ simulateError(enable?: boolean): this; /** Sets a specific error type for a simulated field error. */ errorType(type: string): this; /** * Provides a custom function to generate the field's value. * This overrides all other generation methods for this field. * @param fn A function that receives the `globalContext`, `currentData`, and `rng` instance and returns the value. */ generate(fn: (context: Record<string, any>, currentData: Record<string, any>, rng: RandomGenerator) => TInfer): this; /** Returns the compiled SchemaField object. */ build(): SchemaField; } declare class SString extends SBase<string> { constructor(); } declare class SNumber extends SBase<number> { constructor(); } declare class SBoolean extends SBase<boolean> { constructor(); } declare class SUUID extends SBase<string> { constructor(); } declare class SEmail extends SBase<string> { constructor(); } declare class SURL extends SBase<string> { constructor(); } declare class SDate extends SBase<string> { constructor(); } declare class SEnum<T extends string | number | boolean> extends SBase<T> { constructor(values: Array<EnumValue<T>>); } declare class SArray<TItem extends SBase> extends SBase<Array<InferSBase<TItem>>> { constructor(item: TItem); } /** * Helper type to extract the inferred type from a `SBase` instance. * `typeof m.string().infer` would be `string`. */ type InferSBase<T extends SBase> = T extends SBase<infer U> ? U : never; /** * Maps a record of SBase types to their inferred TypeScript types. * Used for `SObject` to get the final inferred type. */ type MapSBaseToInfer<T extends Record<string, SBase>> = { [K in keyof T]: InferSBase<T[K]> extends SchemaForm<infer O> ? O : InferSBase<T[K]>; }; declare class SObject<TFields extends Record<string, SBase>, TInferred = MapSBaseToInfer<TFields>> extends SBase<TInferred> { private _fields; constructor(fields: TFields); /** * Extends the current object schema with additional fields. * @param additionalFields A record of new SBase fields to add. */ extend<TExtraFields extends Record<string, SBase>>(additionalFields: TExtraFields): SObject<TFields & TExtraFields, TInferred & MapSBaseToInfer<TExtraFields>>; /** * Creates a new object schema with only the specified fields. * @param keys An array of keys to pick from the current schema. */ pick<K extends keyof TFields>(keys: K[]): SObject<Pick<TFields, K>, unknown>; /** * Creates a new object schema by omitting the specified fields. * @param keys An array of keys to omit from the current schema. */ omit<K extends keyof TFields>(keys: K[]): SObject<Omit<TFields, K>, unknown>; /** Returns the compiled SchemaField object. */ build(name?: string, version?: string): SchemaForm<TInferred>; } declare class SUnion<TTypes extends SBase[]> extends SBase<InferSBase<TTypes[number]>> { constructor(types: TTypes); build(): SchemaField<InferSBase<TTypes[number]>> & { readonly infer: InferSBase<TTypes[number]>; }; } declare class SIntersection<TTypes extends SBase[]> extends SBase<InferSBase<TTypes[number]>> { constructor(types: TTypes); build(): SchemaField<InferSBase<TTypes[number]>> & { readonly infer: InferSBase<TTypes[number]>; }; } declare class SNullable<TType extends SBase> extends SBase<InferSBase<TType> | null> { constructor(type: TType); build(): SchemaField<InferSBase<TType> | null> & { readonly infer: InferSBase<TType> | null; }; } declare class SReference extends SBase<any> { constructor(ref: string); } declare class SnapshotUtils { static toSnapshot(data: any): string; static compareSnapshot(data: any, snapshot: string): boolean; } declare class DocGenerator { static toMarkdown(schema: SchemaForm): string; static fieldType(field: SchemaField): string; } /** * Creates instances of the MockGenerator with various configurations. */ declare class SyntexFactory { static createGenerator(options?: MockGeneratorOptions): MockGenerator; static createSeededGenerator(seed: number): MockGenerator; static createLocalizedGenerator(locale: string, options?: MockGeneratorOptions): MockGenerator; } declare class SchemaUtils { /** * Creates a basic SchemaForm for an object type. * @deprecated Use `m.object({...}).build('SchemaName', '1.0.0')` directly for better type inference. */ static createBasicSchema(name: string, fields: Record<string, SchemaField>): SchemaForm; static createCollection(name: string, schemas: SchemaForm[]): SchemaCollection; /** * Merges two SchemaForms (object types). The fields from `extensionSchema` will override those in `baseSchema`. * @param baseSchema The base SchemaForm. * @param extensionSchema The SchemaForm to extend with. * @returns A new SchemaForm with merged fields. */ static mergeSchemas<T1, T2>(baseSchema: SchemaForm<T1>, extensionSchema: SchemaForm<T2>): SchemaForm<T1 & T2>; static validateData(data: any, schema: SchemaForm): boolean; static validateType(value: any, field: SchemaField): boolean; } /** * Utility for generating TypeScript interface strings from schemas. */ declare class TypeInference { /** * Generates a TypeScript interface string from a compiled SchemaForm. * This is provided for documentation/tooling; for direct type inference, * use `typeof mySchema.infer`. * @param schema The SchemaForm object. * @returns A string representing the TypeScript interface. */ static inferType(schema: SchemaForm): string; static fieldType(field: SchemaField): string; } /** * The main entry point for building Syntex schemas. */ export declare const s: { string: () => SString; number: () => SNumber; boolean: () => SBoolean; uuid: () => SUUID; email: () => SEmail; url: () => SURL; date: () => SDate; /** * Defines an enum field. Can accept a simple array of values or an array of objects * with `value` and `weight` for probabilistic generation. * @example * m.enum(['red', 'green', 'blue']) * m.enum([{ value: 'admin', weight: 0.8 }, { value: 'user', weight: 0.2 }]) */ enum: <T extends string | number | boolean>(values: Array<EnumValue<T>>) => SEnum<T>; array: <TItem extends SBase>(item: TItem) => SArray<TItem>; /** * Defines an object field with nested properties. * @example * m.object({ * id: m.uuid().required(), * name: m.string(), * }).build('UserSchema'); */ object: <TFields extends Record<string, SBase>>(fields: TFields) => SObject<TFields, MapSBaseToInfer<TFields>>; union: <TTypes extends SBase[]>(types: TTypes) => SUnion<TTypes>; intersection: <TTypes extends SBase[]>(types: TTypes) => SIntersection<TTypes>; nullable: <TType extends SBase>(type: TType) => SNullable<TType>; /** * Defines a reference to another named schema within a SchemaCollection. * The referenced schema must be registered with the MockGenerator or included in a collection. * @example * m.object({ * organization: m.reference('OrganizationSchema') * }) */ reference: (ref: string) => SReference; }; export { SchemaField, SchemaForm, SchemaCollection, MockResponse, MockGeneratorOptions, SyntexError, MockGenerator, SyntexFactory, TypeInference, SnapshotUtils, DocGenerator, SchemaUtils, SynthexPlugin, };