{"version":3,"sources":["../src/index.ts","../src/composed-function/summarize/summarizeRecursively.ts","../src/composed-function/summarize/summarizeRecursivelyWithTextGenerationAndTokenSplitting.ts","../src/guard/fixObject.ts","../src/guard/guard.ts"],"sourcesContent":["export * from \"./composed-function/index.js\";\nexport * from \"./guard/index.js\";\n","import { Run, SplitFunction } from \"modelfusion\";\nimport { SummarizationFunction } from \"./SummarizationFunction.js\";\n\nexport async function summarizeRecursively(\n  {\n    summarize,\n    split,\n    join = (texts) => texts.join(\"\\n\\n\"),\n    text,\n  }: {\n    summarize: SummarizationFunction;\n    split: SplitFunction;\n    join?: (texts: Array<string>) => string;\n    text: string;\n  },\n  options?: { run?: Run }\n): Promise<string> {\n  const chunks = await split({ text });\n\n  const summarizedTexts = await Promise.all(\n    chunks.map((chunk) => summarize({ text: chunk }, options))\n  );\n\n  if (summarizedTexts.length === 1) {\n    return summarizedTexts[0]!;\n  }\n\n  // recursive mapping: will split joined results as needed to stay\n  // within the allowed size limit of the splitter.\n  return summarizeRecursively(\n    {\n      text: join(summarizedTexts),\n      summarize,\n      split,\n      join,\n    },\n    options\n  );\n}\n","import {\n  FullTokenizer,\n  Run,\n  TextGenerationModel,\n  generateText,\n  splitAtToken,\n} from \"modelfusion\";\nimport { summarizeRecursively } from \"./summarizeRecursively.js\";\n\n/**\n * Recursively summarizes a text using a text generation model, e.g. for summarization or text extraction.\n * It automatically splits the text into optimal chunks that are small enough to be processed by the model,\n * while leaving enough space for the model to generate text.\n */\nexport async function summarizeRecursivelyWithTextGenerationAndTokenSplitting<\n  PROMPT,\n>(\n  {\n    text,\n    model,\n    prompt,\n    tokenLimit = model.contextWindowSize -\n      (model.settings.maxGenerationTokens ?? model.contextWindowSize / 4),\n    join,\n  }: {\n    text: string;\n    model: TextGenerationModel<PROMPT> & {\n      contextWindowSize: number;\n      tokenizer: FullTokenizer;\n      countPromptTokens: (prompt: PROMPT) => PromiseLike<number>;\n    };\n    prompt: (input: { text: string }) => Promise<PROMPT>;\n    tokenLimit?: number;\n    join?: (texts: Array<string>) => string;\n  },\n  options?: {\n    functionId?: string;\n    run?: Run;\n  }\n) {\n  const emptyPromptTokens = await model.countPromptTokens(\n    await prompt({ text: \"\" })\n  );\n\n  return summarizeRecursively(\n    {\n      split: splitAtToken({\n        tokenizer: model.tokenizer,\n        maxTokensPerChunk: tokenLimit - emptyPromptTokens,\n      }),\n      summarize: async (input: { text: string }) =>\n        generateText({ model, prompt: await prompt(input), ...options }),\n      join,\n      text,\n    },\n    options\n  );\n}\n","import { ObjectParseError, ObjectValidationError } from \"modelfusion\";\nimport { Guard } from \"./guard.js\";\n\n/**\n * Attempts to correct and retry object generation when encountering parsing or validation errors.\n *\n * This function acts as a guard within the object generation process. If the generation results in\n * an error, identified as either a `ObjectParseError` or `ObjectValidationError`, the function\n * triggers a retry mechanism. It uses the `modifyInputForRetry` method, provided via options, to adjust\n * the input parameters, aiming to resolve the issue that caused the initial error. The process continues\n * until a valid object is generated, or it exhausts the predefined retry limits.\n *\n * @template INPUT - The expected format/type of the input data used for object generation.\n * @template OUTPUT - The expected format/type of the output data, i.e., the successfully generated object.\n *\n * @param {Object} options - Configuration options for modifying the input before retrying object generation.\n * @param {function} options.modifyInputForRetry - A function that takes the error type, original input, and error object.\n *        It modifies the input data based on the error information, aiming to correct the issue for the retry attempt.\n *        This function must return a promise that resolves with the modified input.\n *\n * @returns {Guard<INPUT, OUTPUT>} A guard function that intercepts the object generation process, checking for\n *          errors, and initiating retries by modifying the input parameters. The guard can trigger multiple retries\n *          if the issues persist. If the process succeeds, it returns the valid object; otherwise, it returns\n *          undefined, indicating the exhaustion of retry attempts or a non-recoverable error.\n *\n * @example\n * const result = await guard(\n *  (input) =>\n *    generateObject(\n *      openai\n *        .ChatTextGenerator(/* ... * /)\n *        .asFunctionCallObjectGenerationModel(/* ... * /),\n *\n *      zodSchema({\n *        // ...\n *      }),\n *\n *      input\n *    ),\n *  [\n *    // ...\n *  ],\n *  fixObject({\n *    modifyInputForRetry: async ({ input, error }) => [\n *      ...input,\n *      openai.ChatMessage.assistant(null, {\n *        functionCall: {\n *          name: \"sentiment\",\n *          arguments: JSON.stringify(error.valueText),\n *        },\n *      }),\n *      openai.ChatMessage.user(error.message),\n *      openai.ChatMessage.user(\"Please fix the error and try again.\"),\n *    ],\n *  })\n * );\n */\nexport const fixObject: <INPUT, OUTPUT>(options: {\n  modifyInputForRetry: (options: {\n    type: \"error\";\n    input: INPUT;\n    error: ObjectValidationError | ObjectParseError;\n  }) => PromiseLike<INPUT>;\n}) => Guard<INPUT, OUTPUT> =\n  ({ modifyInputForRetry }) =>\n  async (result) => {\n    if (\n      result.type === \"error\" &&\n      (result.error instanceof ObjectValidationError ||\n        result.error instanceof ObjectParseError)\n    ) {\n      return {\n        action: \"retry\",\n        input: await modifyInputForRetry({\n          type: \"error\",\n          input: result.input,\n          error: result.error,\n        }),\n      };\n    }\n\n    return undefined;\n  };\n","import { FunctionOptions } from \"modelfusion\";\nimport { executeFunctionCall } from \"modelfusion/internal\";\n\ntype OutputResult<INPUT, OUTPUT> =\n  | {\n      type: \"value\";\n      input: INPUT;\n      output: OUTPUT;\n      error?: undefined;\n    }\n  | {\n      type: \"error\";\n      input: INPUT;\n      output?: undefined;\n      error: unknown;\n    };\n\nexport type OutputValidator<INPUT, OUTPUT> = ({\n  type,\n  input,\n  output,\n  error,\n}: OutputResult<INPUT, OUTPUT>) => PromiseLike<boolean>;\n\nexport type Guard<INPUT, OUTPUT> = ({\n  type,\n  input,\n  output,\n  error,\n}: OutputResult<INPUT, OUTPUT>) => PromiseLike<\n  | { action: \"retry\"; input: INPUT }\n  | { action: \"return\"; output: OUTPUT }\n  | { action: \"throwError\"; error: unknown }\n  | { action: \"passThrough\" }\n  | undefined\n>;\n\nexport async function guard<INPUT, OUTPUT>(\n  execute: (input: INPUT, options?: FunctionOptions) => PromiseLike<OUTPUT>,\n  input: INPUT,\n  guards: Guard<INPUT, OUTPUT> | Array<Guard<INPUT, OUTPUT>>,\n  options?: FunctionOptions & { maxAttempts: number }\n): Promise<OUTPUT | undefined> {\n  const guardList = Array.isArray(guards) ? guards : [guards];\n  const maxAttempts = options?.maxAttempts ?? 2;\n\n  return executeFunctionCall({\n    options,\n    input,\n    functionType: \"extension\",\n    execute: async (options) => {\n      let attempts = 0;\n      while (attempts < maxAttempts) {\n        let result: OutputResult<INPUT, OUTPUT>;\n\n        try {\n          result = {\n            type: \"value\" as const,\n            input,\n            output: await execute(input, options),\n          };\n        } catch (error) {\n          result = {\n            type: \"error\" as const,\n            input,\n            error,\n          };\n        }\n\n        let isValid = true;\n        for (const guard of guardList) {\n          const guardResult = await guard(result);\n\n          if (guardResult === undefined) {\n            continue;\n          }\n\n          switch (guardResult.action) {\n            case \"passThrough\": {\n              break;\n            }\n            case \"retry\": {\n              input = guardResult.input;\n              isValid = false;\n              break;\n            }\n            case \"return\": {\n              result = {\n                type: \"value\" as const,\n                input,\n                output: guardResult.output,\n              };\n              break;\n            }\n            case \"throwError\": {\n              result = {\n                type: \"error\" as const,\n                input,\n                error: guardResult.error,\n              };\n              break;\n            }\n          }\n        }\n\n        if (isValid) {\n          if (result.type === \"value\") {\n            return result.output;\n          } else {\n            throw result.error;\n          }\n        }\n\n        attempts++;\n      }\n\n      // TODO dedicated error type\n      throw new Error(\n        `Maximum attempts of ${maxAttempts} reached ` +\n          `without producing a valid output or handling an error.`\n      );\n    },\n  });\n}\n"],"mappings":"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","names":["import_modelfusion","options","guard"]}