{"version":3,"file":"fan-out.mjs","names":[],"sources":["../../../../../../../ai/src/supervisor/fan-out.ts"],"sourcesContent":["import type { AgentContract } from \"../contracts/agent/agent.contract\";\nimport type { IntentEntry } from \"../contracts/supervisor/intent-entry.type\";\nimport type { WorkflowInstance } from \"../contracts/workflow/workflow.contract\";\n\n/**\n * A dispatchable unit that can be fanned out — an agent or a workflow.\n * The same union the supervisor's `intents` map accepts for its\n * agent/workflow object entries.\n */\nexport type FanOutUnit = AgentContract<unknown> | WorkflowInstance<unknown, unknown>;\n\n/**\n * Options for {@link fanOut}.\n */\nexport type FanOutOptions = {\n  /**\n   * Base name for the generated intent keys. Defaults to the unit's own\n   * `name`. The keys are `<keyPrefix>1`, `<keyPrefix>2`, … `<keyPrefix>n`.\n   */\n  keyPrefix?: string;\n  /**\n   * Description applied to every generated entry. Defaults to the\n   * unit's own `description`. A description is required when the\n   * supervisor uses a `router` (the LLM needs a signal per intent); the\n   * factory enforces that downstream, so supply one here when the\n   * underlying unit has none.\n   */\n  description?: string;\n};\n\n/**\n * Spread one agent/workflow into `n` distinctly-keyed intent entries\n * for voting / self-consistency under a supervisor.\n *\n * A supervisor dispatches a fan-out array (`[\"writer1\", \"writer2\",\n * \"writer3\"]`) in parallel; each branch runs the SAME unit independently\n * so a downstream evaluate/aggregate intent can pick the majority answer\n * or the best of `n` samples. Because every branch needs its own intent\n * KEY, this helper clones the unit across distinct keys rather than\n * cloning the unit itself — the underlying agent/workflow is referenced\n * by all entries, but each entry is a separate dispatch slot.\n *\n * Returns a `Record<string, IntentEntry>` you spread directly into the\n * supervisor's `intents` map. The keys are `<keyPrefix>1..<keyPrefix>n`.\n *\n * @example\n * const writer = ai.agent({ name: \"writer\", description: \"Drafts an answer.\", model });\n *\n * const support = ai.supervisor({\n *   name: \"self-consistency\",\n *   intents: {\n *     ...ai.fanOut(writer, 3),          // writer1, writer2, writer3\n *     vote: { run: pickMajority, description: \"Choose the majority answer.\" },\n *   },\n *   route: (ctx) =>\n *     ctx.iteration === 0 ? [\"writer1\", \"writer2\", \"writer3\"] : \"vote\",\n * });\n *\n * @param unit  The agent or workflow to fan out.\n * @param count Number of parallel copies. Must be an integer >= 1.\n * @param options Optional key-prefix / description overrides.\n */\nexport function fanOut(\n  unit: FanOutUnit,\n  count: number,\n  options: FanOutOptions = {},\n): Record<string, IntentEntry> {\n  if (!unit || typeof (unit as { execute?: unknown }).execute !== \"function\") {\n    throw new TypeError(\"ai.fanOut: first argument must be an agent or workflow\");\n  }\n\n  if (!Number.isInteger(count) || count < 1) {\n    throw new TypeError(`ai.fanOut: \\`count\\` must be an integer >= 1 (received ${String(count)})`);\n  }\n\n  const keyPrefix = resolveKeyPrefix(unit, options.keyPrefix);\n  const description = options.description ?? readDescription(unit);\n\n  const entries: Record<string, IntentEntry> = {};\n\n  for (let index = 1; index <= count; index++) {\n    const entry: IntentEntry = { agent: unit };\n\n    if (description) {\n      entry.description = description;\n    }\n\n    entries[`${keyPrefix}${index}`] = entry;\n  }\n\n  return entries;\n}\n\n/**\n * Resolve the base key prefix: explicit override wins, then the unit's\n * own name. A unit with no usable name forces an explicit `keyPrefix`\n * so the generated keys stay meaningful and collision-free.\n */\nfunction resolveKeyPrefix(unit: FanOutUnit, override: string | undefined): string {\n  if (override && override.trim().length > 0) {\n    return override.trim();\n  }\n\n  const name = (unit as { name?: unknown }).name;\n\n  if (typeof name === \"string\" && name.trim().length > 0) {\n    return name.trim();\n  }\n\n  throw new TypeError(\n    \"ai.fanOut: the unit has no usable `name` — pass `options.keyPrefix` to name the generated intent keys\",\n  );\n}\n\nfunction readDescription(unit: FanOutUnit): string | undefined {\n  const description = (unit as { description?: unknown }).description;\n\n  return typeof description === \"string\" && description.trim().length > 0 ? description : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,OACd,MACA,OACA,UAAyB,CAAC,GACG;CAC7B,IAAI,CAAC,QAAQ,OAAQ,KAA+B,YAAY,YAC9D,MAAM,IAAI,UAAU,wDAAwD;CAG9E,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,UAAU,0DAA0D,OAAO,KAAK,EAAE,EAAE;CAGhG,MAAM,YAAY,iBAAiB,MAAM,QAAQ,SAAS;CAC1D,MAAM,cAAc,QAAQ,eAAe,gBAAgB,IAAI;CAE/D,MAAM,UAAuC,CAAC;CAE9C,KAAK,IAAI,QAAQ,GAAG,SAAS,OAAO,SAAS;EAC3C,MAAM,QAAqB,EAAE,OAAO,KAAK;EAEzC,IAAI,aACF,MAAM,cAAc;EAGtB,QAAQ,GAAG,YAAY,WAAW;CACpC;CAEA,OAAO;AACT;;;;;;AAOA,SAAS,iBAAiB,MAAkB,UAAsC;CAChF,IAAI,YAAY,SAAS,KAAK,CAAC,CAAC,SAAS,GACvC,OAAO,SAAS,KAAK;CAGvB,MAAM,OAAQ,KAA4B;CAE1C,IAAI,OAAO,SAAS,YAAY,KAAK,KAAK,CAAC,CAAC,SAAS,GACnD,OAAO,KAAK,KAAK;CAGnB,MAAM,IAAI,UACR,uGACF;AACF;AAEA,SAAS,gBAAgB,MAAsC;CAC7D,MAAM,cAAe,KAAmC;CAExD,OAAO,OAAO,gBAAgB,YAAY,YAAY,KAAK,CAAC,CAAC,SAAS,IAAI,cAAc;AAC1F"}