import { Cognitive, Models, Model, BotpressClientLike, GenerateContentInput, GenerateContentOutput } from '@botpress/cognitive';
import { TextTokenizer } from '@bpinternal/thicktoken';

type GenerationMetadata = {
    model: string;
    cost: {
        input: number;
        output: number;
    };
    latency: number;
    tokens: {
        input: number;
        output: number;
    };
};

type SaveExampleProps<TInput, TOutput> = {
    key: string;
    taskType: string;
    taskId: string;
    instructions: string;
    input: TInput;
    output: TOutput;
    explanation?: string;
    metadata: GenerationMetadata;
    status?: 'pending' | 'approved';
};
type GetExamplesProps<TInput> = {
    taskType: string;
    taskId: string;
    input: TInput;
};
declare abstract class Adapter {
    abstract getExamples<TInput, TOutput>(props: GetExamplesProps<TInput>): Promise<Array<{
        key: string;
        input: TInput;
        output: TOutput;
        explanation?: string;
        similarity: number;
    }>>;
    abstract saveExample<TInput, TOutput>(props: SaveExampleProps<TInput, TOutput>): Promise<void>;
}

type ActiveLearning = {
    enable: boolean;
    tableName: string;
    taskId: string;
};
type ZaiConfig = {
    client: BotpressClientLike | Cognitive;
    userId?: string;
    modelId?: Models;
    activeLearning?: ActiveLearning;
    namespace?: string;
};
declare class Zai {
    protected static tokenizer: TextTokenizer;
    protected client: Cognitive;
    private _originalConfig;
    private _userId;
    protected Model: Models;
    protected ModelDetails: Model;
    protected namespace: string;
    protected adapter: Adapter;
    protected activeLearning: ActiveLearning;
    constructor(config: ZaiConfig);
    /** @internal */
    protected callModel(props: Parameters<Cognitive['generateContent']>[0]): ReturnType<Cognitive['generateContent']>;
    protected getTokenizer(): Promise<TextTokenizer>;
    protected fetchModelDetails(): Promise<void>;
    protected get taskId(): string;
    with(options: Partial<ZaiConfig>): Zai;
    learn(taskId: string): Zai;
}

type Meta = Awaited<ReturnType<Cognitive['generateContent']>>['meta'];
type GenerateContentProps<T> = Omit<GenerateContentInput, 'model' | 'signal'> & {
    maxRetries?: number;
    transform?: (text: string | undefined, output: GenerateContentOutput) => T;
};
type ZaiContextProps = {
    client: Cognitive;
    taskType: string;
    taskId: string;
    modelId: string;
    adapter?: Adapter;
    source?: GenerateContentInput['meta'];
};
type Usage = {
    requests: {
        requests: number;
        errors: number;
        responses: number;
        cached: number;
        percentage: number;
    };
    cost: {
        input: number;
        output: number;
        total: number;
    };
    tokens: {
        input: number;
        output: number;
        total: number;
    };
};
type ContextEvents = {
    update: Usage;
};
declare class ZaiContext {
    private _startedAt;
    private _inputCost;
    private _outputCost;
    private _inputTokens;
    private _outputTokens;
    private _totalCachedResponses;
    private _totalRequests;
    private _totalErrors;
    private _totalResponses;
    taskId: string;
    taskType: string;
    modelId: GenerateContentInput['model'];
    adapter?: Adapter;
    source?: GenerateContentInput['meta'];
    private _eventEmitter;
    controller: AbortController;
    private _client;
    constructor(props: ZaiContextProps);
    getModel(): Promise<Model>;
    on<K extends keyof ContextEvents>(type: K, listener: (event: ContextEvents[K]) => void): this;
    clear(): void;
    generateContent<Out = string>(props: GenerateContentProps<Out>): Promise<{
        meta: Meta;
        output: GenerateContentOutput;
        text: string | undefined;
        extracted: Out;
    }>;
    get elapsedTime(): number;
    get usage(): Usage;
}

type ResponseEvents<TComplete = any> = {
    progress: Usage;
    complete: TComplete;
    error: unknown;
};
declare class Response<T = any, S = T> implements PromiseLike<S> {
    private _promise;
    private _eventEmitter;
    private _context;
    private _elasped;
    private _simplify;
    constructor(context: ZaiContext, promise: Promise<T>, simplify: (value: T) => S);
    on<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    off<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    once<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    bindSignal(signal: AbortSignal): this;
    abort(reason?: string | Error): void;
    then<TResult1 = S, TResult2 = never>(onfulfilled?: ((value: S) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): PromiseLike<S | TResult>;
    result(): Promise<{
        output: T;
        usage: Usage;
        elapsed: number;
    }>;
}

type Options$7 = {
    /** The maximum number of tokens to generate */
    length?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Generates a text of the desired length according to the prompt */
        text(prompt: string, options?: Options$7): Response<string>;
    }
}

type Example$3 = {
    input: string;
    output: string;
    instructions?: string;
};
type Options$6 = {
    /** Examples to guide the rewriting */
    examples?: Array<Example$3>;
    /** The maximum number of tokens to generate */
    length?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Rewrites a string according to match the prompt */
        rewrite(original: string, prompt: string, options?: Options$6): Response<string>;
    }
}

type Options$5 = {
    /** What should the text be summarized to? */
    prompt?: string;
    /** How to format the example text */
    format?: string;
    /** The length of the summary in tokens */
    length?: number;
    /** How many times longer (than final length) are the intermediate summaries generated */
    intermediateFactor?: number;
    /** The maximum number of iterations to perform */
    maxIterations?: number;
    /** Sliding window options */
    sliding?: {
        window: number;
        overlap: number;
    };
};
declare module '@botpress/zai' {
    interface Zai {
        /** Summarizes a text of any length to a summary of the desired length */
        summarize(original: string, options?: Options$5): Response<string>;
    }
}

type Example$2 = {
    input: unknown;
    check: boolean;
    reason?: string;
    condition?: string;
};
type Options$4 = {
    /** Examples to check the condition against */
    examples?: Array<Example$2>;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Checks wether a condition is true or not */
        check(input: unknown, condition: string, options?: Options$4): Response<{
            /** Whether the condition is true or not */
            value: boolean;
            /** The explanation of the decision */
            explanation: string;
        }, boolean>;
    }
}

type Example$1 = {
    input: unknown;
    filter: boolean;
    reason?: string;
};
type Options$3 = {
    /** The maximum number of tokens per item */
    tokensPerItem?: number;
    /** Examples to filter the condition against */
    examples?: Array<Example$1>;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Filters elements of an array against a condition */
        filter<T>(input: Array<T>, condition: string, options?: Options$3): Response<Array<T>>;
    }
}

type Options$2 = {
    /** Instructions to guide the user on how to extract the data */
    instructions?: string;
    /** The maximum number of tokens per chunk */
    chunkLength?: number;
    /** Whether to strictly follow the schema or not */
    strict?: boolean;
};
type __Z<T extends any = any> = {
    _output: T;
};
type OfType<O, T extends __Z = __Z<O>> = T extends __Z<O> ? T : never;
declare module '@botpress/zai' {
    interface Zai {
        /** Extracts one or many elements from an arbitrary input */
        extract<S extends OfType<any>>(input: unknown, schema: S, options?: Options$2): Response<S['_output']>;
    }
}

type Label = keyof typeof LABELS;
declare const LABELS: {
    readonly ABSOLUTELY_NOT: "ABSOLUTELY_NOT";
    readonly PROBABLY_NOT: "PROBABLY_NOT";
    readonly AMBIGUOUS: "AMBIGUOUS";
    readonly PROBABLY_YES: "PROBABLY_YES";
    readonly ABSOLUTELY_YES: "ABSOLUTELY_YES";
};
type Example<T extends string> = {
    input: unknown;
    labels: Partial<Record<T, {
        label: Label;
        explanation?: string;
    }>>;
};
type Options$1<T extends string> = {
    /** Examples to help the user make a decision */
    examples?: Array<Example<T>>;
    /** Instructions to guide the user on how to extract the data */
    instructions?: string;
    /** The maximum number of tokens per chunk */
    chunkLength?: number;
};
type Labels<T extends string> = Record<T, string>;
declare module '@botpress/zai' {
    interface Zai {
        /** Tags the provided input with a list of predefined labels */
        label<T extends string>(input: unknown, labels: Labels<T>, options?: Options$1<T>): Response<{
            [K in T]: {
                explanation: string;
                value: boolean;
                confidence: number;
            };
        }, {
            [K in T]: boolean;
        }>;
    }
}

type Group<T> = {
    id: string;
    label: string;
    elements: T[];
};
type InitialGroup = {
    id: string;
    label: string;
    elements?: unknown[];
};
type Options = {
    instructions?: string;
    tokensPerElement?: number;
    chunkLength?: number;
    initialGroups?: Array<InitialGroup>;
};
declare module '@botpress/zai' {
    interface Zai {
        group<T>(input: Array<T>, options?: Options): Response<Array<Group<T>>, Record<string, T[]>>;
    }
}

export { Zai };
