{"version":3,"file":"adapter.mjs","names":["#options","#model","#processor","#resolve","#loadPromise"],"sources":["../../../../src/batteries/generation/transformers_js/adapter.ts"],"sourcesContent":["/**\n * transformers.js (on-device, EXPERIMENTAL) Generation adapter battery — DeepSeek Janus text→image.\n *\n * @module @nhtio/adk/batteries/generation/transformers_js/adapter\n *\n * @remarks\n * Media-generation battery backed by transformers.js's Janus (`MultiModalityCausalLM`) model family\n * (documented reference model: `onnx-community/Janus-Pro-1B-ONNX`). **Environment-neutral** — runs in\n * Node (via `onnxruntime-node`) and the browser (via `onnxruntime-web` / WebGPU), auto-selected by the\n * package; there is no WebGPU requirement.\n *\n * **EXPERIMENTAL.** Janus is a ~2GB multimodal model; on WASM/CPU a single image can take minutes to\n * generate. This battery exists for completeness of the on-device story, not as a fast path — prefer\n * the OpenAI/Gemini engines unless running fully offline is the point.\n *\n * There is no `pipeline('text-to-image')` task in transformers.js (verified against the installed\n * `@huggingface/transformers` source — no such task is registered in `src/pipelines.js`). The only\n * image-generation surface is `MultiModalityCausalLM.generate_images(options)`\n * (`src/models/multi_modality/modeling_multi_modality.js`), fed by `VLChatProcessor`\n * (`src/models/janus/processing_janus.js`) — both exported from the package root, per the official\n * `onnx-community/Janus-Pro-1B-ONNX` model card:\n *\n * ```javascript\n * import { AutoProcessor, MultiModalityCausalLM } from \"@huggingface/transformers\"\n * const processor = await AutoProcessor.from_pretrained(model_id)\n * const model = await MultiModalityCausalLM.from_pretrained(model_id)\n * const inputs = await processor([{ role: \"<|User|>\", content: prompt }], { chat_template: \"text_to_image\" })\n * const outputs = await model.generate_images({ ...inputs, min_new_tokens: processor.num_image_tokens, max_new_tokens: processor.num_image_tokens, do_sample: true })\n * ```\n *\n * This adapter mirrors that shape exactly, with every knob overridable per-call (see\n * `./types` for the full source-verified knob provenance) and both the model and processor typed\n * **structurally** (duck-typed local interfaces, never a hard import of the peer's classes) so\n * fake-model/fake-processor unit tests never load the real peer.\n *\n * **`generate_images` returns `RawImage[]`** — raw decoded pixel data, not encoded bytes. Encoding to\n * PNG is env-branched (browser `toBlob('image/png')` / Node `toSharp().png().toBuffer()`), handled by\n * {@link @nhtio/adk/batteries/generation/transformers_js/helpers!rawImageToEncodedBytes}, which also\n * accepts an injectable `encodeImage` override — the primary hermetic-test seam.\n *\n * **`edit()` is unsupported.** Janus's only generation entry point (`generate_images`) is\n * text-conditioned; there is no image-conditioned edit/inpaint surface in the installed\n * `@huggingface/transformers` API. Calling `edit()` throws\n * {@link @nhtio/adk/batteries/generation/transformers_js/exceptions!E_TRANSFORMERS_JS_GENERATION_UNSUPPORTED_OPERATION}.\n *\n * `@huggingface/transformers` is an optional peer dependency, imported lazily (only inside the default\n * model/processor factories, i.e. only when no `janusModel`/`processor`/`createModel`/`createProcessor`\n * override is supplied).\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validateOptions } from './validation'\nimport { rawImageToEncodedBytes } from './helpers'\nimport { emitLifecycle } from '../../llm/chat_common/lifecycle'\nimport { withModelSource } from '../../llm/transformers_js/model_source'\nimport {\n  E_INVALID_TRANSFORMERS_JS_GENERATION_OPTIONS,\n  E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR,\n  E_TRANSFORMERS_JS_GENERATION_UNSUPPORTED_OPERATION,\n} from './exceptions'\nimport type { EditOptions, GeneratedMediaOutput } from '../openai/types'\nimport type {\n  TransformersJsGenerationAdapterOptions,\n  TransformersJsGenerationModel,\n  TransformersJsGenerationProcessor,\n  TransformersJsGenerateOptions,\n  CreateTransformersJsGenerationModel,\n  CreateTransformersJsGenerationProcessor,\n} from './types'\n\nconst DEFAULT_ROLE = '<|User|>'\nconst DEFAULT_CHAT_TEMPLATE = 'text_to_image'\n\nconst makeDefaultCreateModel = (\n  modelSource: TransformersJsGenerationAdapterOptions['modelSource']\n): CreateTransformersJsGenerationModel => {\n  return async ({ model, device, dtype, onInitProgress }) => {\n    const transformers = await import('@huggingface/transformers')\n    const { MultiModalityCausalLM, env } = transformers as unknown as {\n      MultiModalityCausalLM: {\n        from_pretrained: (model: string, opts?: unknown) => Promise<unknown>\n      }\n      env: unknown\n    }\n    const load = async () =>\n      (await MultiModalityCausalLM.from_pretrained(model, {\n        ...(device ? { device } : {}),\n        ...(dtype ? { dtype } : {}),\n        ...(onInitProgress ? { progress_callback: onInitProgress } : {}),\n      })) as unknown as TransformersJsGenerationModel\n    // When a custom model source is configured, serve files through it behind the global-`env` mutex.\n    return modelSource ? withModelSource(env as never, modelSource, load) : load()\n  }\n}\n\nconst makeDefaultCreateProcessor = (\n  modelSource: TransformersJsGenerationAdapterOptions['modelSource']\n): CreateTransformersJsGenerationProcessor => {\n  return async ({ model, onInitProgress }) => {\n    const transformers = await import('@huggingface/transformers')\n    const { AutoProcessor, env } = transformers as unknown as {\n      AutoProcessor: { from_pretrained: (model: string, opts?: unknown) => Promise<unknown> }\n      env: unknown\n    }\n    const load = async () =>\n      (await AutoProcessor.from_pretrained(model, {\n        ...(onInitProgress ? { progress_callback: onInitProgress } : {}),\n      })) as unknown as TransformersJsGenerationProcessor\n    return modelSource ? withModelSource(env as never, modelSource, load) : load()\n  }\n}\n\n/**\n * Media generation adapter for transformers.js's Janus (`MultiModalityCausalLM`) text→image model\n * family.\n *\n * @remarks\n * Reusable: construct once, call {@link TransformersJsGenerationAdapter.generate} as many times as\n * needed. The model + processor are resolved lazily on first use (or via {@link preload}) and cached\n * with single-flight semantics so concurrent calls share one load. {@link edit} always throws — see\n * the module remarks.\n */\nexport class TransformersJsGenerationAdapter {\n  readonly #options: TransformersJsGenerationAdapterOptions\n  #model: TransformersJsGenerationModel | undefined\n  #processor: TransformersJsGenerationProcessor | undefined\n  #loadPromise:\n    | Promise<{\n        model: TransformersJsGenerationModel\n        processor: TransformersJsGenerationProcessor\n      }>\n    | undefined\n\n  /**\n   * Whether this battery is available. transformers.js is environment-neutral (Node + browser), so\n   * this is `true` whenever the runtime can import the peer — there is no WebGPU requirement.\n   */\n  public static isAvailable(): boolean {\n    return true\n  }\n\n  /**\n   * @param options - Constructor options. Validated eagerly.\n   * @throws {@link @nhtio/adk/batteries!E_INVALID_TRANSFORMERS_JS_GENERATION_OPTIONS} when invalid.\n   */\n  constructor(options: unknown) {\n    this.#options = validateOptions(options)\n    this.#model = this.#options.janusModel\n    this.#processor = this.#options.processor\n  }\n\n  /** Instance availability probe (honours an injected `isAvailable`). */\n  isAvailable(): boolean {\n    return (this.#options.isAvailable ?? TransformersJsGenerationAdapter.isAvailable)()\n  }\n\n  /** Eagerly loads (and caches) the model + processor so the first `generate` call is fast. Idempotent. */\n  async preload(): Promise<void> {\n    await this.#resolve()\n  }\n\n  /** Drops the cached model/processor and in-flight load so the next call reloads. */\n  reset(): void {\n    this.#model = undefined\n    this.#processor = undefined\n    this.#loadPromise = undefined\n  }\n\n  async #resolve(): Promise<{\n    model: TransformersJsGenerationModel\n    processor: TransformersJsGenerationProcessor\n  }> {\n    if (this.#model && this.#processor) {\n      return { model: this.#model, processor: this.#processor }\n    }\n    if (!this.isAvailable()) {\n      throw new E_INVALID_TRANSFORMERS_JS_GENERATION_OPTIONS([\n        'the transformers.js generation battery is not available in this runtime',\n      ])\n    }\n    const opts = this.#options\n    this.#loadPromise ??= (async () => {\n      emitLifecycle(opts, 'transformers_js_generation', opts.model, 'loading', {\n        detail: 'loading Janus model + processor',\n      })\n      const hasLifecycle =\n        opts.onLifecycle ?? opts.onLoading ?? opts.onReady ?? opts.onGenerating ?? opts.onError\n      const forwardedInitProgress = hasLifecycle\n        ? (info: unknown) => {\n            const p = (info as { progress?: number } | undefined)?.progress\n            emitLifecycle(opts, 'transformers_js_generation', opts.model, 'loading', {\n              ...(typeof p === 'number' ? { progress: p / 100 } : {}),\n              raw: info,\n            })\n            opts.onInitProgress?.(info as never)\n          }\n        : opts.onInitProgress\n      const createModel = opts.createModel ?? makeDefaultCreateModel(opts.modelSource)\n      const createProcessor = opts.createProcessor ?? makeDefaultCreateProcessor(opts.modelSource)\n      try {\n        emitLifecycle(opts, 'transformers_js_generation', opts.model, 'compiling', {\n          detail: 'compiling Janus graph',\n        })\n        const [model, processor] = await Promise.all([\n          this.#model ??\n            createModel({\n              model: opts.model,\n              device: opts.device,\n              dtype: opts.dtype,\n              onInitProgress: forwardedInitProgress,\n            }),\n          this.#processor ??\n            createProcessor({ model: opts.model, onInitProgress: forwardedInitProgress }),\n        ])\n        this.#model = model\n        this.#processor = processor\n        emitLifecycle(opts, 'transformers_js_generation', opts.model, 'ready', {\n          detail: 'Janus model + processor ready',\n        })\n        return { model, processor }\n      } catch (err) {\n        this.#loadPromise = undefined\n        emitLifecycle(opts, 'transformers_js_generation', opts.model, 'error', { error: err })\n        throw new E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR([\n          `could not load the transformers.js Janus model/processor: ${isError(err) ? err.message : String(err)} — install the peer dependency (pnpm add @huggingface/transformers)`,\n        ])\n      }\n    })()\n    return this.#loadPromise\n  }\n\n  /**\n   * Generates image(s) from a text prompt via Janus's `generate_images`.\n   *\n   * @param prompt - The text prompt describing the desired image.\n   * @param opts - Per-call knob overrides — see {@link TransformersJsGenerateOptions}.\n   * @returns The generated image(s), each PNG-encoded.\n   * @throws {@link @nhtio/adk/batteries!E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR} when the call fails\n   *   or returns no usable images.\n   */\n  async generate(\n    prompt: string,\n    opts?: TransformersJsGenerateOptions\n  ): Promise<GeneratedMediaOutput[]> {\n    const { model, processor } = await this.#resolve()\n    const merged = this.#options\n\n    const role = opts?.role ?? merged.role ?? DEFAULT_ROLE\n    const chatTemplate = opts?.chatTemplate ?? merged.chatTemplate ?? DEFAULT_CHAT_TEMPLATE\n\n    emitLifecycle(merged, 'transformers_js_generation', merged.model, 'generating')\n\n    let images: Array<{ toBlob?: unknown; toSharp?: unknown }>\n    try {\n      const inputs = await processor([{ role, content: prompt }], { chat_template: chatTemplate })\n      const numImageTokens = processor.num_image_tokens\n\n      const doSample = opts?.doSample ?? merged.doSample ?? true\n      const temperature = opts?.temperature ?? merged.temperature\n      const topK = opts?.topK ?? merged.topK\n      const guidanceScale = opts?.guidanceScale ?? merged.guidanceScale\n      const repetitionPenalty = opts?.repetitionPenalty ?? merged.repetitionPenalty\n      const minNewTokens = opts?.minNewTokens ?? numImageTokens\n      const maxNewTokens = opts?.maxNewTokens ?? numImageTokens\n\n      const generateOptions: Record<string, unknown> = {\n        ...inputs,\n        do_sample: doSample,\n        ...(typeof temperature === 'number' ? { temperature } : {}),\n        ...(typeof topK === 'number' ? { top_k: topK } : {}),\n        ...(typeof guidanceScale === 'number' ? { guidance_scale: guidanceScale } : {}),\n        ...(typeof repetitionPenalty === 'number' ? { repetition_penalty: repetitionPenalty } : {}),\n        ...(typeof minNewTokens === 'number' ? { min_new_tokens: minNewTokens } : {}),\n        ...(typeof maxNewTokens === 'number' ? { max_new_tokens: maxNewTokens } : {}),\n      }\n\n      images = (await model.generate_images(generateOptions)) as unknown as Array<{\n        toBlob?: unknown\n        toSharp?: unknown\n      }>\n    } catch (err) {\n      emitLifecycle(merged, 'transformers_js_generation', merged.model, 'error', { error: err })\n      throw new E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR([\n        isError(err) ? err.message : String(err),\n      ])\n    }\n\n    if (!Array.isArray(images) || images.length === 0) {\n      const error = new Error('generate_images returned no images')\n      emitLifecycle(merged, 'transformers_js_generation', merged.model, 'error', { error })\n      throw new E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR([\n        'the Janus model returned no images — an empty result is an engine failure, not a valid empty generation',\n      ])\n    }\n\n    let outputs: GeneratedMediaOutput[]\n    try {\n      outputs = await Promise.all(\n        images.map(async (image, i) => {\n          const bytes = await rawImageToEncodedBytes(image as never, merged.encodeImage as never)\n          return {\n            kind: 'image' as const,\n            mimeType: 'image/png',\n            bytes,\n            filename: `generated-${i + 1}.png`,\n          }\n        })\n      )\n    } catch (err) {\n      emitLifecycle(merged, 'transformers_js_generation', merged.model, 'error', { error: err })\n      throw new E_TRANSFORMERS_JS_GENERATION_ENGINE_ERROR([\n        isError(err) ? err.message : String(err),\n      ])\n    }\n\n    emitLifecycle(merged, 'transformers_js_generation', merged.model, 'complete')\n    return outputs\n  }\n\n  /**\n   * Unsupported. Janus's only generation entry point (`generate_images`) is text-conditioned; there is\n   * no image-conditioned edit/inpaint surface in the installed `@huggingface/transformers` API.\n   *\n   * @throws {@link @nhtio/adk/batteries!E_TRANSFORMERS_JS_GENERATION_UNSUPPORTED_OPERATION} always.\n   */\n  async edit(\n    _image: unknown,\n    _prompt: string,\n    _opts?: EditOptions\n  ): Promise<GeneratedMediaOutput[]> {\n    throw new E_TRANSFORMERS_JS_GENERATION_UNSUPPORTED_OPERATION([\n      'edit',\n      'Janus (MultiModalityCausalLM.generate_images) is text-conditioned image generation only — there is no image-conditioned edit/inpaint entry point in the installed @huggingface/transformers API',\n    ])\n  }\n}\n"],"mappings":"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"}