{"version":3,"file":"adapter.mjs","names":["#baseline","#engine","#resolveEngine","#enginePromise","#engineSettings","#gen","#samplerParams","#sessionConfig"],"sources":["../../../../src/batteries/llm/litert_lm/adapter.ts"],"sourcesContent":["/**\n * Browser/WebGPU executor adapter for Google's LiteRT-LM (`@litert-lm/core`).\n *\n * @module @nhtio/adk/batteries/llm/litert_lm/adapter\n *\n * @remarks\n * On-device LLM inference via WebGPU + a bundled wasm runtime, `.litertlm` models. Unlike the WebLLM\n * battery (a thin extension of the OpenAI Chat Completions wire shape), LiteRT-LM has its **own** API —\n * `Engine.create() → engine.createConversation({ preface }) → conversation.sendMessageStreaming():\n * ReadableStream<Message>` — with native `Message`/`Tool`/`tool_calls`/`tool_response` shapes (tool-call\n * `arguments` arrive as a parsed object, not a JSON string). So this is a standalone adapter that reuses\n * the ADK's format-agnostic render helpers but maps history/tools/results to LiteRT's shapes.\n *\n * Three pluggable layers mirror the other LLM batteries: swappable translation helpers, three-layer\n * options merging (constructor → `executor()` overrides → `ctx.stash.liteRtLm`), and an\n * injectable/lazy engine (`engine` or `createEngine`, defaulting to a dynamic `@litert-lm/core` import).\n *\n * **The published `@litert-lm/core` docs lag the library** — every wire field here is mapped against the\n * installed package's type declarations, the source of truth. The dependency is young (pinned exact);\n * re-verify on upgrade.\n */\n\nimport { DateTime } from 'luxon'\nimport { sha256 } from 'js-sha256'\nimport { v6 as uuidv6 } from 'uuid'\nimport { validateOptions } from './validation'\nimport { emitLifecycle } from '../chat_common/lifecycle'\nimport { E_LLM_GPU_OUT_OF_MEMORY } from '../chat_common/exceptions'\nimport { isError, isInstanceOf, isObject } from '@nhtio/adk/guards'\nimport { resolveToolCallParser } from '../chat_common/tool_parsers'\nimport { resolveGenerationOptions } from '../chat_common/generation'\nimport { canonicalStringify } from '../../../lib/utils/canonical_json'\nimport { resolveReasoningParser } from '../chat_common/reasoning_parsers'\nimport { InMemorySpoolStore } from '@nhtio/adk/batteries/storage/in_memory'\nimport { isGpuOutOfMemoryError, probeGpuBudget } from '../chat_common/gpu_budget'\nimport {\n  looksLikeSpooledArtifact,\n  stripEnvelopeSpecialTokens,\n  normalizeToolName,\n} from '../chat_common/helpers'\nimport {\n  Tokenizable,\n  ToolCall,\n  Message,\n  Thought,\n  SpooledArtifact,\n  Media,\n  ArtifactTool,\n} from '@nhtio/adk/common'\nimport {\n  E_INVALID_LITERT_LM_OPTIONS,\n  E_LITERT_LM_CONTEXT_OVERFLOW,\n  E_LITERT_LM_STREAM_ERROR,\n  E_LITERT_LM_INVALID_TOOL_CALL_ARGS,\n} from './exceptions'\nimport {\n  defaultDescriptionToChatCompletionsJsonSchema,\n  defaultRenderUntrustedContent,\n  defaultRenderTrustedContent,\n  defaultRenderStandingInstructions,\n  defaultRenderMemories,\n  defaultRenderRetrievables,\n  defaultRenderRetrievableHandleBody,\n  defaultRenderRetrievableSafetyDirective,\n  defaultRenderFirstPartyRetrievables,\n  defaultRenderThirdPartyPublicRetrievables,\n  defaultRenderThirdPartyPrivateRetrievables,\n  defaultRenderThought,\n  defaultFilterThoughts,\n  defaultRenderChatCompletionsSystemPrompt,\n  defaultToolsToLiteRtTools,\n  defaultRenderToolsAsPromptText,\n  defaultRenderLiteRtToolResult,\n  defaultRenderArtifactHandleBody,\n  defaultBuildLiteRtConversationInput,\n  defaultCreateLiteRtStreamAccumulator,\n  renderMediaToLiteRtContent,\n} from './helpers'\nimport type { Tool } from '@nhtio/adk/common'\nimport type { DispatchContext } from '@nhtio/adk/types'\nimport type { ParsedToolCall } from '../chat_common/tool_parsers'\nimport type { TokenEncoding, TokenEncodingId } from '@nhtio/adk/types'\nimport type { ChatSampler, ResolvedGenerationOptions } from '../chat_common/generation'\nimport type { DispatchExecutorFn, DispatchExecutorHelpers } from '@nhtio/adk/dispatch_runner'\nimport type {\n  LiteRtLmAdapterOptions,\n  LiteRtLmEngine,\n  LiteRtLmConversation,\n  LiteRtMessage,\n  LiteRtMessageContentItem,\n  LiteRtEngineSettings,\n  LiteRtConversationConfig,\n  LiteRtSessionConfig,\n  LiteRtSamplerParametersOption,\n} from './types'\n\n/** Markers that signal the start of tool-call / reasoning markup — used to stop streaming prose. */\nconst TEXT_MARKUP_MARKERS = [\n  '<tool_call>',\n  '<|tool_call>',\n  '<|channel',\n  '<think',\n  '[TOOL_CALLS]',\n  '<function=',\n]\n\n// ─── Option merging (constructor → executor overrides → stash) ────────────────────────────────────\n\nconst mergeHelpers = (\n  layers: ReadonlyArray<Partial<NonNullable<LiteRtLmAdapterOptions['helpers']>> | undefined>\n): Partial<NonNullable<LiteRtLmAdapterOptions['helpers']>> | undefined => {\n  let merged: Partial<NonNullable<LiteRtLmAdapterOptions['helpers']>> | undefined\n  for (const layer of layers) {\n    if (!layer) continue\n    merged = { ...(merged ?? {}), ...layer }\n  }\n  return merged\n}\n\nconst mergeOptions = (\n  baseline: LiteRtLmAdapterOptions,\n  exec: Partial<LiteRtLmAdapterOptions> | undefined,\n  stash: Partial<LiteRtLmAdapterOptions> | undefined\n): Partial<LiteRtLmAdapterOptions> => {\n  const layers = [baseline as Partial<LiteRtLmAdapterOptions>, exec ?? {}, stash ?? {}]\n  const out: Record<string, unknown> = {}\n  for (const layer of layers) {\n    for (const [k, v] of Object.entries(layer)) {\n      if (v === undefined) continue\n      if (k === 'helpers') continue\n      out[k] = v\n    }\n  }\n  const helpers = mergeHelpers(layers.map((l) => l.helpers))\n  if (helpers !== undefined) out.helpers = helpers\n  return out as Partial<LiteRtLmAdapterOptions>\n}\n\n// ─── Helper resolution (fall back to bundled defaults per field) ──────────────────────────────────\n\ninterface ResolvedHelpers {\n  descriptionToChatCompletionsJsonSchema: typeof defaultDescriptionToChatCompletionsJsonSchema\n  renderUntrustedContent: typeof defaultRenderUntrustedContent\n  renderTrustedContent: typeof defaultRenderTrustedContent\n  renderStandingInstructions: typeof defaultRenderStandingInstructions\n  renderMemories: typeof defaultRenderMemories\n  renderRetrievables: typeof defaultRenderRetrievables\n  renderRetrievableSafetyDirective: typeof defaultRenderRetrievableSafetyDirective\n  renderFirstPartyRetrievables: typeof defaultRenderFirstPartyRetrievables\n  renderThirdPartyPublicRetrievables: typeof defaultRenderThirdPartyPublicRetrievables\n  renderThirdPartyPrivateRetrievables: typeof defaultRenderThirdPartyPrivateRetrievables\n  renderThought: typeof defaultRenderThought\n  filterThoughts: typeof defaultFilterThoughts\n  renderChatCompletionsSystemPrompt: typeof defaultRenderChatCompletionsSystemPrompt\n  toolsToLiteRtTools: typeof defaultToolsToLiteRtTools\n  renderToolsAsPromptText: typeof defaultRenderToolsAsPromptText\n  renderLiteRtToolResult: typeof defaultRenderLiteRtToolResult\n  renderArtifactHandleBody: typeof defaultRenderArtifactHandleBody\n  renderRetrievableHandleBody: typeof defaultRenderRetrievableHandleBody\n  buildLiteRtConversationInput: typeof defaultBuildLiteRtConversationInput\n  createLiteRtStreamAccumulator: typeof defaultCreateLiteRtStreamAccumulator\n}\n\nconst resolveHelpers = (\n  overrides: Partial<LiteRtLmAdapterOptions['helpers']> | undefined\n): ResolvedHelpers => {\n  const src = (overrides ?? {}) as Record<string, unknown>\n  return {\n    descriptionToChatCompletionsJsonSchema:\n      (src.descriptionToChatCompletionsJsonSchema as ResolvedHelpers['descriptionToChatCompletionsJsonSchema']) ??\n      defaultDescriptionToChatCompletionsJsonSchema,\n    renderUntrustedContent:\n      (src.renderUntrustedContent as ResolvedHelpers['renderUntrustedContent']) ??\n      defaultRenderUntrustedContent,\n    renderTrustedContent:\n      (src.renderTrustedContent as ResolvedHelpers['renderTrustedContent']) ??\n      defaultRenderTrustedContent,\n    renderStandingInstructions:\n      (src.renderStandingInstructions as ResolvedHelpers['renderStandingInstructions']) ??\n      defaultRenderStandingInstructions,\n    renderMemories:\n      (src.renderMemories as ResolvedHelpers['renderMemories']) ?? defaultRenderMemories,\n    renderRetrievables:\n      (src.renderRetrievables as ResolvedHelpers['renderRetrievables']) ??\n      defaultRenderRetrievables,\n    renderRetrievableSafetyDirective:\n      (src.renderRetrievableSafetyDirective as ResolvedHelpers['renderRetrievableSafetyDirective']) ??\n      defaultRenderRetrievableSafetyDirective,\n    renderFirstPartyRetrievables:\n      (src.renderFirstPartyRetrievables as ResolvedHelpers['renderFirstPartyRetrievables']) ??\n      defaultRenderFirstPartyRetrievables,\n    renderThirdPartyPublicRetrievables:\n      (src.renderThirdPartyPublicRetrievables as ResolvedHelpers['renderThirdPartyPublicRetrievables']) ??\n      defaultRenderThirdPartyPublicRetrievables,\n    renderThirdPartyPrivateRetrievables:\n      (src.renderThirdPartyPrivateRetrievables as ResolvedHelpers['renderThirdPartyPrivateRetrievables']) ??\n      defaultRenderThirdPartyPrivateRetrievables,\n    renderThought: (src.renderThought as ResolvedHelpers['renderThought']) ?? defaultRenderThought,\n    filterThoughts:\n      (src.filterThoughts as ResolvedHelpers['filterThoughts']) ?? defaultFilterThoughts,\n    renderChatCompletionsSystemPrompt:\n      (src.renderChatCompletionsSystemPrompt as ResolvedHelpers['renderChatCompletionsSystemPrompt']) ??\n      defaultRenderChatCompletionsSystemPrompt,\n    toolsToLiteRtTools:\n      (src.toolsToLiteRtTools as ResolvedHelpers['toolsToLiteRtTools']) ??\n      defaultToolsToLiteRtTools,\n    renderToolsAsPromptText:\n      (src.renderToolsAsPromptText as ResolvedHelpers['renderToolsAsPromptText']) ??\n      defaultRenderToolsAsPromptText,\n    renderLiteRtToolResult:\n      (src.renderLiteRtToolResult as ResolvedHelpers['renderLiteRtToolResult']) ??\n      defaultRenderLiteRtToolResult,\n    renderArtifactHandleBody:\n      (src.renderArtifactHandleBody as ResolvedHelpers['renderArtifactHandleBody']) ??\n      defaultRenderArtifactHandleBody,\n    renderRetrievableHandleBody:\n      (src.renderRetrievableHandleBody as ResolvedHelpers['renderRetrievableHandleBody']) ??\n      defaultRenderRetrievableHandleBody,\n    buildLiteRtConversationInput:\n      (src.buildLiteRtConversationInput as ResolvedHelpers['buildLiteRtConversationInput']) ??\n      defaultBuildLiteRtConversationInput,\n    createLiteRtStreamAccumulator:\n      (src.createLiteRtStreamAccumulator as ResolvedHelpers['createLiteRtStreamAccumulator']) ??\n      defaultCreateLiteRtStreamAccumulator,\n  }\n}\n\nconst nowIso = (): string => DateTime.now().toISO() as string\n\n/** Best-effort lifecycle `model` label: the URL string, else a `<blob>`/`<stream>`/`<model>` marker. */\nconst litertModelLabel = (model: unknown): string =>\n  typeof model === 'string'\n    ? model\n    : isInstanceOf(model, 'Blob', typeof Blob !== 'undefined' ? Blob : (undefined as never))\n      ? '<blob>'\n      : model && typeof (model as { getReader?: unknown }).getReader === 'function'\n        ? '<stream>'\n        : '<model>'\n\nconst computeChecksum = (tool: string, args: Record<string, unknown>): string =>\n  sha256(canonicalStringify({ tool, args }))\n\n/** An assembled tool call drained from the stream/response (args already a parsed object). */\ninterface AssembledLiteRtToolCall {\n  id: string\n  name: string\n  args: Record<string, unknown>\n  argsWellFormed: boolean\n}\n\n/**\n * Does this raw engine message report an INPUT context-cap overflow — the prompt's token ids exceed the\n * engine's fixed `maxNumTokens`? The LiteRT-web runtime throws e.g. `Input token ids are too long.\n * Exceeding the maximum number of tokens allowed: 12596 >= 12288`. Matched so the raw throw can be\n * translated into the typed {@link E_LITERT_LM_CONTEXT_OVERFLOW} instead of the generic stream error —\n * this is the ENGINE BACKSTOP that fires when the optional pre-dispatch guard is unarmed or undercounts.\n * Exported so a host can classify a thrown/caught error the same way.\n */\nexport const isEngineContextOverflowMessage = (message: string): boolean =>\n  /input token ids are too long|exceeding the maximum number of tokens/i.test(message)\n\n/**\n * Translate a generation/load throw into the right battery exception:\n * - a typed {@link E_LITERT_LM_CONTEXT_OVERFLOW} when the engine reports an input context-cap overflow\n *   (parsed `actual >= limit` numbers when present), so a host can `catch` it and shed/retry — this is\n *   the backstop for the optional pre-dispatch guard;\n * - a typed, catchable {@link @nhtio/adk/batteries!E_LLM_GPU_OUT_OF_MEMORY} when the message matches a\n *   known WebGPU exhaustion signature (surface, don't impose);\n * - else the generic {@link E_LITERT_LM_STREAM_ERROR}.\n *\n * @param err - The raw thrown value.\n * @param contextNote - A short human-readable note carried on the OOM error's message.\n */\nconst toLiteRtGenerationError = (\n  err: unknown,\n  contextNote: string\n):\n  | InstanceType<typeof E_LITERT_LM_CONTEXT_OVERFLOW>\n  | InstanceType<typeof E_LLM_GPU_OUT_OF_MEMORY>\n  | InstanceType<typeof E_LITERT_LM_STREAM_ERROR> => {\n  const message = isError(err) ? err.message : String(err)\n  if (isEngineContextOverflowMessage(message)) {\n    // Parse the engine's `actual >= limit` pair when present so the typed error carries real numbers the\n    // host can act on; fall back to 0/0 with the raw message as the breakdown otherwise.\n    const m = /(\\d+)\\s*>=\\s*(\\d+)/.exec(message)\n    const actual = m ? Number(m[1]) : 0\n    const limit = m ? Number(m[2]) : 0\n    return new E_LITERT_LM_CONTEXT_OVERFLOW([actual, limit, 'engine', message])\n  }\n  if (isGpuOutOfMemoryError(message)) {\n    return new E_LLM_GPU_OUT_OF_MEMORY([message, contextNote], {\n      cause: isError(err) ? err : undefined,\n    })\n  }\n  return new E_LITERT_LM_STREAM_ERROR([message])\n}\n\n/**\n * Cross-environment executor adapter for LiteRT-LM.\n *\n * @remarks\n * Construct with at least `{ model }`; wire `new LiteRtLmAdapter(opts).executor()` into a\n * `DispatchRunner` as the `executorCallback`. The engine is resolved lazily on first dispatch (or\n * eagerly via {@link LiteRtLmAdapter.preload}); pass `engine` to inject a pre-built one (e.g. in tests).\n */\nexport class LiteRtLmAdapter {\n  /** The `ctx.stash` key under which per-dispatch option overrides are read. */\n  public static readonly STASH_KEY = 'liteRtLm' as const\n\n  readonly #baseline: LiteRtLmAdapterOptions\n  #engine: LiteRtLmEngine | undefined\n  #enginePromise: Promise<LiteRtLmEngine> | undefined\n\n  /**\n   * Returns `true` when the current runtime exposes WebGPU (`navigator.gpu`).\n   */\n  public static isAvailable(): boolean {\n    return (\n      typeof globalThis.navigator !== 'undefined' &&\n      'gpu' in globalThis.navigator &&\n      typeof (globalThis.navigator as { gpu?: unknown }).gpu !== 'undefined'\n    )\n  }\n\n  /**\n   * @param options - Raw adapter options, validated against `liteRtLmOptionsSchema`.\n   * @throws {@link @nhtio/adk/batteries!E_INVALID_LITERT_LM_OPTIONS} when `options` are invalid.\n   */\n  constructor(options: unknown) {\n    this.#baseline = validateOptions(options)\n    this.#engine = this.#baseline.engine\n  }\n\n  /** Instance WebGPU-availability probe (honours the `isWebGPUAvailable` option override). */\n  isAvailable(): boolean {\n    return (this.#baseline.isWebGPUAvailable ?? LiteRtLmAdapter.isAvailable)()\n  }\n\n  /**\n   * Eagerly resolve (load) the engine before the first dispatch.\n   *\n   * @param overrides - Optional option overrides applied for this load.\n   * @returns The resolved {@link LiteRtLmEngine}.\n   */\n  async preload(overrides?: Partial<LiteRtLmAdapterOptions>): Promise<LiteRtLmEngine> {\n    const merged = validateOptions(mergeOptions(this.#baseline, overrides, undefined))\n    return this.#resolveEngine(merged)\n  }\n\n  /** Drop the cached engine and any in-flight load so the next dispatch re-resolves it. */\n  reset(): void {\n    this.#engine = undefined\n    this.#enginePromise = undefined\n  }\n\n  /**\n   * Release the loaded engine's native resources (`Engine.delete()`), then drop the cached reference.\n   *\n   * @remarks\n   * `reset()` only nulls the JS reference; the LiteRT engine holds a WebGPU device + compiled graph that\n   * stay alive until GC. Loading many `.litertlm` engines back-to-back in one browser session accumulates\n   * those until the GPU heap is exhausted. `@litert-lm/core`'s `Engine` exposes `delete()` — this settles\n   * any in-flight load, awaits `delete()`, swallows a teardown error (teardown must not throw), and\n   * finishes with `reset()`. Idempotent and safe when nothing is loaded.\n   */\n  async dispose(): Promise<void> {\n    const engine = this.#engine ?? (await this.#enginePromise?.catch(() => undefined))\n    const withDelete = engine as { delete?: () => unknown } | undefined\n    if (typeof withDelete?.delete === 'function') {\n      try {\n        await Promise.resolve(withDelete.delete())\n      } catch {\n        // teardown must not throw\n      }\n    }\n    this.reset()\n  }\n\n  /**\n   * Free the WebGPU buffer cache by deleting the engine, then reload the same model.\n   *\n   * @remarks\n   * The consumer-facing lever for the ONNX Runtime Web WebGPU buffer-freelist high-water-mark (see\n   * {@link @nhtio/adk/batteries!probeGpuBudget}). The pool is flushed only when the engine's sessions are\n   * released; there is no public flag to flush it mid-life, so the supported way to reclaim the retained\n   * working-set without permanently unloading is to delete the engine and load again. This is exactly\n   * `dispose()` then `preload()`, surfaced as a named, intentional operation (e.g. an application\n   * offering a \"free GPU memory\" action after a {@link @nhtio/adk/batteries!E_LLM_GPU_OUT_OF_MEMORY}).\n   * NOT invoked automatically — the ADK surfaces the lever and leaves the decision to the consumer.\n   * Re-incurs the cold-load cost. Idempotent.\n   *\n   * @param overrides - Optional option overrides applied to the reload (same as {@link preload}).\n   */\n  async recycle(overrides?: Partial<LiteRtLmAdapterOptions>): Promise<void> {\n    await this.dispose()\n    await this.preload(overrides)\n  }\n\n  /** Build the LiteRT `EngineSettings` from the merged adapter options. */\n  #engineSettings(merged: LiteRtLmAdapterOptions): LiteRtEngineSettings {\n    const settings: LiteRtEngineSettings = {\n      model: merged.model as LiteRtEngineSettings['model'],\n    }\n    if (merged.backend !== undefined) settings.backend = merged.backend as never\n    if (merged.maxNumTokens !== undefined) {\n      settings.mainExecutorSettings = { maxNumTokens: merged.maxNumTokens }\n    }\n    return settings\n  }\n\n  async #resolveEngine(merged: LiteRtLmAdapterOptions): Promise<LiteRtLmEngine> {\n    if (merged.engine) {\n      this.#engine = merged.engine\n      return merged.engine\n    }\n    if (this.#engine) return this.#engine\n    const available = (merged.isWebGPUAvailable ?? LiteRtLmAdapter.isAvailable)()\n    if (!available) {\n      throw new E_INVALID_LITERT_LM_OPTIONS([\n        'LiteRT-LM requires a browser/runtime with WebGPU support',\n      ])\n    }\n    const modelLabel = litertModelLabel(merged.model)\n    this.#enginePromise ??= (async () => {\n      // LiteRT 0.13.1 reports no granular download progress (Engine.create takes no callback), so\n      // `loading` is a coarse start marker — the WebGPU/wasm boot happens inside Engine.create.\n      emitLifecycle(merged, 'litert_lm', modelLabel, 'loading', {\n        detail: 'loading model + booting WebGPU runtime',\n      })\n      try {\n        const engineSettings = this.#engineSettings(merged)\n        const createEngine =\n          merged.createEngine ??\n          (async ({ engineSettings: settings }) => {\n            const { Engine } = await import('@litert-lm/core')\n            return (await Engine.create(\n              settings as never,\n              merged.inputPromptAsHint\n            )) as LiteRtLmEngine\n          })\n        // `Engine.create` is one opaque call covering both the (stream-fed) download and the WebGPU\n        // shader/graph compilation. The compile span is the slow, otherwise-invisible part — mark it as\n        // `compiling` here (the boundary the official LiteRT chat demo's \"Compiling Model…\" status marks).\n        emitLifecycle(merged, 'litert_lm', modelLabel, 'compiling', {\n          detail: 'compiling model + WebGPU shaders',\n        })\n        const engine = await createEngine({\n          engineSettings,\n          onInitProgress: merged.onInitProgress,\n        })\n        this.#engine = engine\n        emitLifecycle(merged, 'litert_lm', modelLabel, 'ready', {\n          detail: 'engine ready',\n          // Surface the WebGPU budget (LiteRT-LM is WebGPU-only) so the consumer can relate its context\n          // window to the device's per-allocation ceiling — observability, never an imposed cap.\n          gpuBudget: await probeGpuBudget(),\n        })\n        return engine\n      } catch (err) {\n        this.#enginePromise = undefined\n        emitLifecycle(merged, 'litert_lm', modelLabel, 'error', { error: err })\n        throw err\n      }\n    })()\n    return this.#enginePromise\n  }\n\n  /**\n   * Resolve the PORTABLE generation contract (shared with transformers.js) from the merged options.\n   * Canonical fields win; the LiteRT-native fields ({@link LiteRtLmAdapterOptions.samplerParams},\n   * `maxOutputTokens`, `visionModalityEnabled`/`audioModalityEnabled`) are the fallback layer consulted\n   * only when the canonical one is unset.\n   */\n  #gen(merged: LiteRtLmAdapterOptions): ResolvedGenerationOptions {\n    const sp = merged.samplerParams\n    // Native samplerParams.type (1=TOP_K, 2=TOP_P, 3=GREEDY) → canonical sampler strategy.\n    const nativeSampler: ChatSampler | undefined =\n      sp?.type === 1 ? 'top-k' : sp?.type === 2 ? 'top-p' : sp?.type === 3 ? 'greedy' : undefined\n    return resolveGenerationOptions(\n      {\n        maxTokens: merged.maxTokens,\n        sampler: merged.sampler,\n        temperature: merged.temperature,\n        topK: merged.topK,\n        topP: merged.topP,\n        seed: merged.seed,\n        enableThinking: merged.enableThinking,\n        multimodal: merged.multimodal,\n      },\n      {\n        maxTokens: merged.maxOutputTokens,\n        sampler: nativeSampler,\n        temperature: sp?.temperature,\n        topK: sp?.k,\n        topP: sp?.p,\n        seed: sp?.seed,\n        multimodal: {\n          image: merged.visionModalityEnabled,\n          audio: merged.audioModalityEnabled,\n        },\n      }\n    )\n  }\n\n  /** Map the resolved canonical sampler → LiteRT `samplerParams` (`type` enum + k/p/temperature). */\n  #samplerParams(gen: ResolvedGenerationOptions): LiteRtSamplerParametersOption {\n    // SamplerType: 1=TOP_K, 2=TOP_P, 3=GREEDY. CRITICAL LiteRT-web invariant: on the WebGPU sampling\n    // path the runtime IGNORES `type` (it always combines top-k + top-p) and the WebGPU TopK sampler\n    // REQUIRES `k <= 1` — passing the canonical default (topK 40) or any k>1 throws\n    // `Top-K value N must be <= 1` at generate time (grounded in runtime/proto/sampler_params.proto:\n    // \"type … Ignored on the GPU path\"). This battery is WebGPU-only, so we clamp k to 1 for EVERY\n    // sampler type and let `p`/`temperature` drive diversity. (The validator additionally REJECTS an\n    // explicit topK>1 so a caller learns the constraint rather than being silently clamped.)\n    const k = Math.min(gen.topK, 1)\n    if (gen.sampler === 'top-k') {\n      return {\n        type: 1,\n        k,\n        p: gen.topP,\n        temperature: gen.temperature,\n        ...(gen.seed !== undefined ? { seed: gen.seed } : {}),\n      }\n    }\n    if (gen.sampler === 'top-p') {\n      return {\n        type: 2,\n        k,\n        p: gen.topP,\n        temperature: gen.temperature,\n        ...(gen.seed !== undefined ? { seed: gen.seed } : {}),\n      }\n    }\n    return {\n      type: 3,\n      k: 1,\n      p: gen.topP,\n      temperature: gen.temperature,\n      ...(gen.seed !== undefined ? { seed: gen.seed } : {}),\n    }\n  }\n\n  /** Build the per-dispatch session config from the resolved portable generation contract. */\n  #sessionConfig(merged: LiteRtLmAdapterOptions): LiteRtSessionConfig | undefined {\n    const gen = this.#gen(merged)\n    const cfg: LiteRtSessionConfig = {\n      samplerParams: this.#samplerParams(gen) as never,\n      maxOutputTokens: gen.maxTokens,\n    }\n    if (gen.multimodal.audio) cfg.audioModalityEnabled = true\n    if (gen.multimodal.image) cfg.visionModalityEnabled = true\n    return cfg\n  }\n\n  /**\n   * Produce the bound {@link DispatchExecutorFn} the `DispatchRunner` invokes.\n   *\n   * @param overrides - Option overrides layered above the constructor baseline (below `ctx.stash`).\n   */\n  executor(overrides?: Partial<LiteRtLmAdapterOptions>): DispatchExecutorFn {\n    const baseline = this.#baseline\n    const adapterClass = LiteRtLmAdapter\n    const self = this\n    return async (ctx: DispatchContext, helpers: DispatchExecutorHelpers): Promise<void> => {\n      // 1. Three-layer merge + re-validate.\n      const stashRaw = ctx.stash.get(adapterClass.STASH_KEY, {}) as unknown\n      const stashOverrides =\n        stashRaw && typeof stashRaw === 'object'\n          ? (stashRaw as Partial<LiteRtLmAdapterOptions>)\n          : {}\n      const merged = validateOptions(mergeOptions(baseline, overrides, stashOverrides))\n      const h = resolveHelpers(merged.helpers)\n      const selfIdentity = merged.selfIdentity ?? 'assistant'\n      const unsupportedMediaPolicy = merged.unsupportedMediaPolicy ?? 'throw'\n      const toolCallParser = resolveToolCallParser(merged.toolCallParser)\n      const reasoningParser = resolveReasoningParser(merged.reasoningParser, undefined, {\n        orphanRecovery: merged.reasoningOrphanRecovery,\n      })\n\n      // 2. Artifact-reader tools are forged by the DispatchRunner CORE into `ctx.tools` before the input\n      //    pipeline runs (generation is a generic core concern; this battery owns only representation).\n      //    Read the pre-forged `ctx.tools` directly — no local merge, no bindContext here.\n\n      // 3. Pre-render persisted tool-call results into LiteRT tool_response content items.\n      const renderedToolCallResults = new Map<ToolCall, LiteRtMessageContentItem>()\n      for (const tc of ctx.turnToolCalls) {\n        const tool = ctx.tools.get(tc.tool)\n        const item = await h.renderLiteRtToolResult({\n          toolCall: tc,\n          results: tc.results,\n          tool: tool as Tool | ArtifactTool | undefined,\n          unsupportedMediaPolicy,\n          renderUntrustedContent: h.renderUntrustedContent,\n          renderTrustedContent: h.renderTrustedContent,\n          renderArtifactHandleBody: h.renderArtifactHandleBody,\n          warn: (m) => helpers.log.warn({ kind: 'litert-render-warning', message: m }),\n        })\n        renderedToolCallResults.set(tc, item)\n      }\n\n      // 4. Optional context-window enforcement.\n      if (merged.tokenEncoding && merged.contextWindow !== undefined) {\n        const enc = merged.tokenEncoding\n        const tally = (s: string): number =>\n          new Tokenizable(s).estimateTokens(enc as TokenEncodingId)\n        // For Tokenizable-backed fields, measure the Tokenizable ITSELF with the live `ctx` (not a temp\n        // built from its coerced string): a DYNAMIC value resolves against ctx, so `estimateTokens(enc,\n        // ctx)` counts EXACTLY the string that `render(ctx)` will assemble below — keeping this guard's\n        // total honest for evaluatable content. A static value counts identically to before.\n        const tallyTok = (t: Tokenizable): number => t.estimateTokens(enc, ctx)\n        // Per-bucket accounting so the overflow exception carries a real breakdown (its `perBucket` arg,\n        // documented for middleware shed-targeting) instead of a single lumped number. A subtractive pass\n        // must measure each bucket the SAME way this guard does; a per-bucket split is what lets a\n        // pass↔guard disagreement be pinned to the exact bucket rather than inferred.\n        const b = {\n          system: 0,\n          standingInstructions: 0,\n          memories: 0,\n          retrievables: 0,\n          messages: 0,\n          thoughts: 0,\n          toolResults: 0,\n          tools: 0,\n        }\n        b.system = tallyTok(ctx.systemPrompt as Tokenizable)\n        for (const si of ctx.standingInstructions)\n          b.standingInstructions += tallyTok(si as Tokenizable)\n        for (const m of ctx.turnMemories) b.memories += tallyTok(m.content as Tokenizable)\n        for (const r of ctx.turnRetrievables) {\n          b.retrievables +=\n            !r.inline && SpooledArtifact.isSpooledArtifact(r.content) && r.content.hasSizeHints()\n              ? r.content.estimateHandleTokens(\n                  r.id,\n                  enc as TokenEncoding,\n                  h.renderRetrievableHandleBody\n                )\n              : tally((await r.contentString?.()) ?? '')\n        }\n        for (const m of ctx.turnMessages)\n          b.messages += m.content ? tallyTok(m.content as Tokenizable) : 0\n        for (const t of ctx.turnThoughts) b.thoughts += tallyTok(t.content as Tokenizable)\n        for (const item of renderedToolCallResults.values()) {\n          const tr = (item as { tool_response?: { response?: { content?: string } } }).tool_response\n          b.toolResults += tally(tr?.response?.content ?? '')\n        }\n        let total =\n          b.system +\n          b.standingInstructions +\n          b.memories +\n          b.retrievables +\n          b.messages +\n          b.thoughts +\n          b.toolResults\n        // The TOOL DECLARATIONS are part of the dispatched prompt too — and for the default\n        // `toolDelivery:'prompt'` path they are the FULL JSON-Schema block rendered by\n        // `renderToolsAsPromptText`, often the single largest bucket (hundreds of tokens for a handful of\n        // tools). Omitting them made this guard undercount by exactly that block and let a tool-heavy\n        // prompt sail past the check and blow the engine's hard cap. Tally the EXACT string that\n        // buildLiteRtConversationInput renders into the system message (same visible()/toolDelivery/\n        // renderer), so the guard sees what the model sees. (Native delivery sends `preface.tools`; its\n        // weight is model/runtime-dependent — the on-device Gemma path is prompt-delivery, so that is the\n        // case that matters here.)\n        const toolDelivery = merged.toolDelivery ?? 'prompt'\n        if (toolDelivery === 'prompt') {\n          const visibleTools = ctx.tools.visible()\n          if (visibleTools.length > 0) b.tools = tally(h.renderToolsAsPromptText(visibleTools))\n        }\n        total += b.tools\n        if (total > merged.contextWindow) {\n          throw new E_LITERT_LM_CONTEXT_OVERFLOW([\n            total,\n            merged.contextWindow,\n            String(enc),\n            `system=${b.system} standingInstructions=${b.standingInstructions} memories=${b.memories} retrievables=${b.retrievables} messages=${b.messages} thoughts=${b.thoughts} toolResults=${b.toolResults} tools=${b.tools}`,\n          ])\n        }\n      }\n\n      // 5. Build LiteRT conversation input (preface + per-turn messages).\n      // Resolve the portable generation contract once so thinking + modality flags are consistent with\n      // what #sessionConfig sends to the runtime (canonical-wins over the native flags).\n      const gen = self.#gen(merged)\n      // A short, user-facing note carried on a GPU-OOM error so the application can show WHY it failed\n      // and what to change. We surface the budget/window relationship, never silently cap it.\n      const oomNote =\n        merged.contextWindow !== undefined\n          ? `The configured context window (${merged.contextWindow} tokens, max ${gen.maxTokens} output) exceeded the available GPU memory. Reduce the context window or max output tokens and retry, recycle the adapter to free the WebGPU buffer cache, or switch to a smaller model.`\n          : `The request exceeded the available GPU memory. Reduce the context window or max output tokens and retry, recycle the adapter to free the WebGPU buffer cache, or switch to a smaller model.`\n      const { preface, messages: turnMessages } = await h.buildLiteRtConversationInput({\n        systemPrompt: ctx.systemPrompt,\n        standingInstructions: ctx.standingInstructions,\n        memories: ctx.turnMemories,\n        retrievables: ctx.turnRetrievables,\n        messages: ctx.turnMessages,\n        thoughts: ctx.turnThoughts,\n        toolCalls: ctx.turnToolCalls,\n        tools: ctx.tools,\n        // The live dispatch context, threaded so DYNAMIC (evaluatable) Tokenizables resolve against it at\n        // assembly (`.render(ctx)`), matching what the overflow guard above counted with the same ctx.\n        // Static Tokenizables ignore it — no behavioral change for the common case.\n        renderCtx: ctx,\n        renderedToolCallResults,\n        bucketOrder: merged.bucketOrder ?? [\n          'standingInstructions',\n          'memories',\n          'retrievables',\n          'timeline',\n        ],\n        selfIdentity,\n        thoughtSurfacing: merged.thoughtSurfacing ?? 'all-self',\n        replayCompatibility: merged.replayCompatibility ?? [],\n        toolDelivery: merged.toolDelivery,\n        enableThinking: gen.enableThinking,\n        toolsToLiteRtTools: h.toolsToLiteRtTools,\n        renderToolsAsPromptText: h.renderToolsAsPromptText,\n        renderThought: h.renderThought,\n        filterThoughts: h.filterThoughts,\n        renderUntrustedContent: h.renderUntrustedContent,\n        renderTrustedContent: h.renderTrustedContent,\n        renderChatCompletionsSystemPrompt: h.renderChatCompletionsSystemPrompt,\n        renderStandingInstructions: h.renderStandingInstructions,\n        renderMemories: h.renderMemories,\n        renderRetrievables: h.renderRetrievables,\n        renderRetrievableSafetyDirective: h.renderRetrievableSafetyDirective,\n        renderFirstPartyRetrievables: h.renderFirstPartyRetrievables,\n        renderThirdPartyPublicRetrievables: h.renderThirdPartyPublicRetrievables,\n        renderThirdPartyPrivateRetrievables: h.renderThirdPartyPrivateRetrievables,\n        renderRetrievableHandleBody: h.renderRetrievableHandleBody,\n        // Multimodal (opt-in): thread the two modality flags + policy + the media renderer so user\n        // messages with attachments map to LiteRT content items. NO EngineSettings change — only the\n        // existing SessionConfig flags gate it. GATED ON A REAL-MODEL PROOF (browser matrix).\n        visionModalityEnabled: gen.multimodal.image,\n        audioModalityEnabled: gen.multimodal.audio,\n        unsupportedMediaPolicy,\n        renderMediaToLiteRtContent,\n        warn: (m) => helpers.log.warn({ kind: 'litert-history-warning', message: m }),\n      })\n\n      // 6. Resolve engine + create the conversation.\n      const sessionConfig = self.#sessionConfig(merged)\n      const conversationConfig: LiteRtConversationConfig = {\n        preface,\n        ...(sessionConfig ? { sessionConfig } : {}),\n        ...(merged.enableConstrainedDecoding !== undefined\n          ? { enableConstrainedDecoding: merged.enableConstrainedDecoding }\n          : {}),\n        ...(merged.filterChannelContentFromKvCache !== undefined\n          ? {\n              filterChannelContentFromKvCache: merged.filterChannelContentFromKvCache,\n            }\n          : {}),\n      }\n\n      let conversation: LiteRtLmConversation\n      try {\n        const engine = await self.#resolveEngine(merged)\n        conversation = await engine.createConversation(conversationConfig as never)\n      } catch (err) {\n        ctx.nack(toLiteRtGenerationError(err, oomNote))\n        return\n      }\n\n      const spoolStore = merged.spoolStore ?? new InMemorySpoolStore()\n      const stream = merged.stream ?? true\n\n      // One id for this whole generation — correlates the TO tap (onPromptAssembled) with the FROM tap\n      // (onRawGeneration) and the reported message. Minted here so both the streaming and non-streaming\n      // paths below reuse it instead of generating their own.\n      const dispatchStreamId = uuidv6()\n\n      // Prompt-assembled observability tap: surface the EXACT prompt bytes going TO the model, the instant\n      // assembly finished (above) and before the engine dispatch (below). Mirror of onRawGeneration.\n      // Handed back AS-IS — no redaction — and swallow callback errors so a misbehaving observer can never\n      // corrupt the generation path.\n      if (merged.onPromptAssembled) {\n        try {\n          merged.onPromptAssembled({\n            battery: 'litert_lm',\n            kind: 'rendered-prompt',\n            // The assembled preface object verbatim — carries the system message text (prompt-delivery\n            // folds the tool block in here) and, for native delivery, the tool list on `preface.tools`.\n            preface,\n            messages: turnMessages,\n            tools: (preface as { tools?: unknown })?.tools,\n            streamed: stream,\n            streamId: dispatchStreamId,\n          })\n        } catch {\n          /* observer errors are non-fatal */\n        }\n      }\n\n      // Wire abort → conversation.cancel().\n      const onAbort = (): void => {\n        try {\n          conversation.cancel()\n        } catch {\n          /* cancel is best-effort */\n        }\n      }\n      if (ctx.abortSignal.aborted) {\n        onAbort()\n        return\n      }\n      ctx.abortSignal.addEventListener('abort', onAbort, { once: true })\n\n      // ── Tool execution + persistence (args already an object — no JSON.parse) ──\n      const executeAndPersistToolCall = async (call: AssembledLiteRtToolCall): Promise<void> => {\n        const tool = ctx.tools.get(call.name)\n        const completedAt = nowIso()\n\n        if (!call.argsWellFormed) {\n          const toolName = normalizeToolName(call.name)\n          const err = new E_LITERT_LM_INVALID_TOOL_CALL_ARGS([\n            'must be a JSON object',\n            JSON.stringify(call.args),\n          ])\n          const results = new Tokenizable(err.message)\n          helpers.reportToolCall(call.id, { tool: toolName, args: {} })\n          helpers.reportToolCall(call.id, {\n            results,\n            isError: true,\n            isComplete: true,\n          })\n          await ctx.storeToolCall(\n            new ToolCall({\n              id: call.id,\n              tool: toolName,\n              args: {},\n              checksum: computeChecksum(toolName, {}),\n              isComplete: true,\n              isError: true,\n              results,\n              createdAt: completedAt,\n              updatedAt: completedAt,\n              completedAt,\n            })\n          )\n          return\n        }\n\n        if (!tool) {\n          const toolName = normalizeToolName(call.name)\n          const available = ctx.tools\n            .all()\n            .map((t) => t.name)\n            .sort()\n          const errText =\n            available.length > 0\n              ? `Tool not found: ${toolName}. Available tools: ${available.join(', ')}.`\n              : `Tool not found: ${toolName}. No tools are available this turn.`\n          const results = new Tokenizable(errText)\n          helpers.reportToolCall(call.id, { tool: toolName, args: call.args })\n          helpers.reportToolCall(call.id, {\n            results,\n            isError: true,\n            isComplete: true,\n          })\n          await ctx.storeToolCall(\n            new ToolCall({\n              id: call.id,\n              tool: toolName,\n              args: call.args,\n              checksum: computeChecksum(toolName, call.args),\n              isComplete: true,\n              isError: true,\n              results,\n              createdAt: completedAt,\n              updatedAt: completedAt,\n              completedAt,\n            })\n          )\n          return\n        }\n\n        helpers.reportToolCall(call.id, { tool: tool.name, args: call.args })\n        const isArtifactTool = ArtifactTool.isArtifactTool(tool)\n        let results: Tokenizable | SpooledArtifact | SpooledArtifact[] | Media | Media[] =\n          new Tokenizable('')\n        let toolHadError = false\n        try {\n          const raw = await tool.executor(ctx)(call.args)\n          if (isArtifactTool) {\n            results = Tokenizable.isTokenizable(raw)\n              ? raw\n              : typeof raw === 'string'\n                ? new Tokenizable(raw)\n                : (() => {\n                    throw new Error(\n                      `ArtifactTool \"${tool.name}\" returned a non-string/non-Tokenizable value`\n                    )\n                  })()\n          } else if (Media.isMedia(raw)) {\n            results = raw\n          } else if (Array.isArray(raw) && raw.length > 0 && raw.every((m) => Media.isMedia(m))) {\n            results = raw as Media[]\n          } else if (looksLikeSpooledArtifact(raw)) {\n            results = raw as SpooledArtifact\n          } else if (typeof raw === 'string' || isInstanceOf(raw, 'Uint8Array', Uint8Array)) {\n            const reader = await spoolStore.write(call.id, raw as string | Uint8Array)\n            const ArtifactCtor = (tool as Tool).artifactConstructor?.() ?? SpooledArtifact\n            results = new ArtifactCtor(reader)\n          } else {\n            const reader = await spoolStore.write(call.id, String(raw))\n            const ArtifactCtor = (tool as Tool).artifactConstructor?.() ?? SpooledArtifact\n            results = new ArtifactCtor(reader)\n          }\n        } catch (err) {\n          toolHadError = true\n          let detailMsg = isError(err) ? err.message : String(err)\n          if (isError(err) && isError(err.cause) && err.cause.message !== err.message) {\n            detailMsg = `${detailMsg} ${err.cause.message}`\n          }\n          results = new Tokenizable(detailMsg)\n        }\n        helpers.reportToolCall(call.id, {\n          results,\n          isError: toolHadError,\n          isComplete: true,\n        })\n        const completedAt2 = nowIso()\n        await ctx.storeToolCall(\n          new ToolCall({\n            id: call.id,\n            tool: tool.name,\n            args: call.args,\n            checksum: computeChecksum(tool.name, call.args),\n            isComplete: true,\n            isError: toolHadError,\n            results,\n            fromArtifactTool: isArtifactTool,\n            // ArtifactTool results are the documented exception: they inline the slice the model queried\n            // from a prior artifact (handing back a handle to a query result would be recursion). Every\n            // other result keeps the secure default (inline:false → handle).\n            inline: isArtifactTool,\n            createdAt: completedAt2,\n            updatedAt: completedAt2,\n            completedAt: completedAt2,\n          })\n        )\n      }\n\n      const assembleCalls = (raw: ReadonlyArray<ParsedToolCall>): AssembledLiteRtToolCall[] =>\n        raw.map((c) => ({\n          id: uuidv6(),\n          name: c.name,\n          args: isObject(c.arguments) ? (c.arguments as Record<string, unknown>) : {},\n          argsWellFormed: isObject(c.arguments),\n        }))\n\n      // Parse the full generated text → reasoning + clean prose + tool calls, then persist.\n      // LiteRT-LM (v0.13.1) is text-only: tool calls + reasoning arrive as text in `content`, in the\n      // model family's format, parsed here via the shared parser layer.\n      const toolNames = ctx.tools.visible().map((t) => t.name)\n      // Run the optional media-output extractor over the raw LiteRT generation result, persisting each\n      // generated media via `ctx.storeMediaBytes` and building first-party `Media`. Returns [] when no hook\n      // is configured (today's text-only output, unchanged).\n      const collectGeneratedMedia = async (raw: unknown): Promise<Media[]> => {\n        if (!merged.extractMediaOutputs || raw === undefined) return []\n        const outputs = await merged.extractMediaOutputs(raw)\n        const media: Media[] = []\n        for (const o of outputs) {\n          const id = uuidv6()\n          const reader = await ctx.storeMediaBytes(id, o.bytes)\n          media.push(\n            Media.toolGenerated({\n              id,\n              kind: o.kind,\n              mimeType: o.mimeType,\n              filename: o.filename ?? `${id}.${o.kind}`,\n              reader,\n            })\n          )\n        }\n        return media\n      }\n\n      const finishFromText = async (\n        rawText: string,\n        streamId: string,\n        streamedProse: boolean,\n        generatedMedia: Media[] = []\n      ): Promise<void> => {\n        // Strip non-semantic envelope/turn-boundary special tokens (Llama/ChatML wrappers) before\n        // parsing — the streamed text can retain them, and they'd make the JSON parsers decline a valid\n        // call. Excludes every token the parsers key on. Idempotent when none are present.\n        const fullText = stripEnvelopeSpecialTokens(rawText)\n        const reasoned = reasoningParser(fullText)\n        const parsed = toolCallParser(reasoned.cleanedText, { toolNames })\n        const cleanText = parsed.cleanedText\n\n        // Raw-generation observability tap: surface what the model emitted vs. what parsed, before any\n        // persistence. Purely observational — swallow callback errors so a misbehaving observer can\n        // never corrupt the generation path.\n        if (merged.onRawGeneration) {\n          try {\n            merged.onRawGeneration({\n              rawText: fullText,\n              cleanedText: cleanText,\n              reasoning: reasoned.reasoning,\n              toolCalls: parsed.calls,\n              streamed: streamedProse,\n              streamId,\n            })\n          } catch {\n            /* observer errors are non-fatal */\n          }\n        }\n\n        // Drop empty/whitespace traces — a model's no-think artifact carries no information.\n        for (const trace of reasoned.reasoning) {\n          if (trace.trim().length === 0) continue\n          const id = uuidv6()\n          helpers.reportThought(id, trace, { isComplete: true })\n          await ctx.storeThought(\n            new Thought({\n              id,\n              content: trace,\n              identity: selfIdentity,\n              createdAt: nowIso(),\n              updatedAt: nowIso(),\n            })\n          )\n        }\n\n        // Persist the assistant message when there is clean prose OR generated media. A media-only turn\n        // (empty text + attachment) is legitimate; a turn with neither stores nothing (unchanged).\n        if (cleanText.length > 0 || generatedMedia.length > 0) {\n          if (streamedProse) helpers.reportMessage(streamId, '', { isComplete: true })\n          else if (cleanText.length > 0)\n            helpers.reportMessage(streamId, cleanText, { isComplete: true })\n          await ctx.storeMessage(\n            new Message({\n              id: streamId,\n              role: 'assistant',\n              ...(cleanText.length > 0 ? { content: cleanText } : {}),\n              ...(generatedMedia.length > 0 ? { attachments: generatedMedia } : {}),\n              identity: selfIdentity,\n              createdAt: nowIso(),\n              updatedAt: nowIso(),\n            })\n          )\n        }\n\n        const calls = assembleCalls(parsed.calls)\n        if (calls.length === 0) {\n          if (merged.autoAck) ctx.ack()\n          return\n        }\n        for (const call of calls) {\n          if (ctx.abortSignal.aborted) return\n          await executeAndPersistToolCall(call)\n        }\n      }\n\n      const lifecycleModel = litertModelLabel(merged.model)\n      emitLifecycle(merged, 'litert_lm', lifecycleModel, 'generating')\n\n      // ── Streaming path ──\n      if (stream) {\n        const accumulator = h.createLiteRtStreamAccumulator()\n        const streamId = dispatchStreamId\n        let proseStopped = false\n        let streamedProse = false\n\n        let readable: ReadableStream<LiteRtMessage>\n        try {\n          readable = conversation.sendMessageStreaming(\n            turnMessages as never\n          ) as ReadableStream<LiteRtMessage>\n        } catch (err) {\n          emitLifecycle(merged, 'litert_lm', lifecycleModel, 'error', {\n            error: err,\n          })\n          ctx.nack(toLiteRtGenerationError(err, oomNote))\n          return\n        }\n\n        let lastChunk: LiteRtMessage | undefined\n        try {\n          const reader = readable.getReader()\n          while (true) {\n            if (ctx.abortSignal.aborted) {\n              await reader.cancel().catch(() => undefined)\n              return\n            }\n            const { value: chunk, done } = await reader.read()\n            if (done) break\n            if (!chunk) continue\n            lastChunk = chunk\n            const { contentDelta } = accumulator.feed(chunk)\n            if (contentDelta.length > 0 && !proseStopped) {\n              // Once the buffered output shows any tool-call/reasoning marker, stop streaming prose;\n              // the authoritative clean message is persisted after the stream drains.\n              if (TEXT_MARKUP_MARKERS.some((m) => accumulator.content().includes(m))) {\n                proseStopped = true\n              } else {\n                streamedProse = true\n                helpers.reportMessage(streamId, contentDelta)\n              }\n            }\n          }\n        } catch (err) {\n          if (ctx.abortSignal.aborted) return\n          emitLifecycle(merged, 'litert_lm', lifecycleModel, 'error', {\n            error: err,\n          })\n          ctx.nack(toLiteRtGenerationError(err, oomNote))\n          return\n        }\n\n        const streamMedia = await collectGeneratedMedia(lastChunk)\n        await finishFromText(accumulator.content(), streamId, streamedProse, streamMedia)\n        emitLifecycle(merged, 'litert_lm', lifecycleModel, 'complete')\n        return\n      }\n\n      // ── Non-streaming path ──\n      let final: LiteRtMessage\n      try {\n        final = (await conversation.sendMessage(turnMessages as never)) as LiteRtMessage\n      } catch (err) {\n        emitLifecycle(merged, 'litert_lm', lifecycleModel, 'error', {\n          error: err,\n        })\n        ctx.nack(toLiteRtGenerationError(err, oomNote))\n        return\n      }\n      const contentText =\n        typeof final.content === 'string'\n          ? final.content\n          : Array.isArray(final.content)\n            ? final.content\n                .filter((i) => i.type === 'text' && typeof i.text === 'string')\n                .map((i) => i.text)\n                .join('')\n            : ''\n      const nonStreamMedia = await collectGeneratedMedia(final)\n      await finishFromText(contentText, dispatchStreamId, false, nonStreamMedia)\n      emitLifecycle(merged, 'litert_lm', lifecycleModel, 'complete')\n    }\n  }\n}\n"],"mappings":"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"}