{"version":3,"file":"system-prompt.mjs","names":[],"sources":["../../../../../../../ai/src/system-prompt/system-prompt.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport type { Placeholders } from \"../contracts/placeholders.type\";\nimport type {\n  InstructionContract,\n  PersonaContract,\n  RefinedSystemPromptContract,\n  RefinedSystemPromptOptions,\n  SystemPromptBlockContract,\n  SystemPromptContract,\n  SystemPromptMergeOptions,\n  SystemPromptMeta,\n} from \"../contracts/system-prompt.contract\";\nimport { InvalidRequestError } from \"../errors\";\nimport { defaultPromptsManager, promptKey } from \"../prompts/prompts-manager\";\nimport type {\n  PromptValidationResult,\n  PromptsValidateOptions,\n} from \"../prompts/prompts-manager.type\";\nimport { Instruction } from \"./instruction\";\nimport { Persona } from \"./persona\";\nimport { RefinedSystemPrompt } from \"./refined-system-prompt\";\n\n/**\n * Monotonic source of the internal, non-registry display id every\n * `SystemPrompt` carries. Anonymous (unnamed) prompts have nothing else to\n * identify them by; this id never feeds the registry and is never derived from\n * the wall clock, so it stays stable and order-deterministic across a run.\n */\nlet displayIdCounter = 0;\n\n/**\n * Narrow an arbitrary value to a `SystemPromptContract` — true when it exposes\n * the builder surface (`blocks` array + a callable `resolve`). Used by the\n * registry-aware `merge` overload to tell a folded contract from a raw block\n * or a registry name string, robustly across duplicate package copies.\n */\nfunction isSystemPromptContract(\n  value: unknown,\n): value is SystemPromptContract {\n  return (\n    typeof value === \"object\" &&\n    value !== null &&\n    Array.isArray((value as { blocks?: unknown }).blocks) &&\n    typeof (value as { resolve?: unknown }).resolve === \"function\"\n  );\n}\n\n/**\n * Build the deterministic provenance label for a prompt — `name@version` when\n * it is registered, otherwise its internal display id. No random suffixes, so\n * the same source always yields the same `composedFrom` entry.\n */\nfunction provenanceLabel(prompt: SystemPromptContract): string {\n  const meta = prompt.meta();\n\n  if (meta?.name) {\n    return promptKey(meta.name, meta.version ?? \"1\");\n  }\n\n  return prompt instanceof SystemPrompt ? prompt.id : \"anonymous\";\n}\n\n/**\n * Concrete `SystemPromptContract` — an immutable layered prompt builder.\n *\n * **Role.** The top-level composer for a system prompt: it holds an ordered\n * list of typed blocks (persona + instructions) and resolves the whole\n * stack into one final string when the agent is about to call the model.\n *\n * **Responsibility.**\n * - Owns: the ordered `blocks` list and the block-join rules (insertion\n *   order, blank-line separator, trim).\n * - Does NOT own: how any individual block is rendered (delegated to each\n *   block's `resolve()`), the placeholder syntax (delegated to\n *   `renderPlaceholders`), or any knowledge of the agent, model, or\n *   session consuming the resolved text.\n *\n * Blocks are discriminated by a string `type` tag (`\"persona\"` /\n * `\"instruction\"`) rather than `instanceof`, so user-supplied blocks that\n * implement `SystemPromptBlockContract` interoperate seamlessly with blocks\n * built via `ai.persona()` / `ai.instruction()` — even across duplicate\n * package copies or bundler scope boundaries.\n *\n * The builder is **immutable** — every `.persona()` / `.instruction()`\n * call returns a fresh `SystemPrompt` instance sharing nothing mutable\n * with its parent. This makes forking a base prompt into specialized\n * variants a safe, side-effect-free operation.\n *\n * Users construct via the `ai.systemPrompt()` factory — `new SystemPrompt()`\n * is not the public API (see §4.2 of code-style.md). Modeled as a class so\n * that methods live on the prototype (one copy shared across every forked\n * instance) and downstream code can branch via `instanceof SystemPrompt`.\n *\n * @example\n * // Chainable form\n * const alex = ai.persona(\"You are Alex, a TypeScript expert.\");\n * const replyIn = ai.instruction(\"Respond in {{language|English}}.\");\n *\n * const base = ai.systemPrompt().persona(alex).instruction(replyIn);\n * const arabicVariant = base.instruction(\"Prefer Arabic comments.\");\n *\n * base.resolve({ language: \"English\" });\n * arabicVariant.resolve({ language: \"Arabic\" });\n *\n * @example\n * // Array form — insertion order is preserved exactly\n * const prompt = ai.systemPrompt([\n *   ai.persona(\"You are Alex, a TypeScript expert.\"),\n *   ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport class SystemPrompt implements SystemPromptContract {\n  /**\n   * Internal, non-registry id for display / provenance. Stable for the life of\n   * the instance; sourced from a monotonic counter, never the wall clock.\n   * Anonymous prompts are identified solely by this id.\n   */\n  public readonly id: string;\n\n  public constructor(\n    public readonly blocks: readonly SystemPromptBlockContract[] = [],\n    private readonly metaData?: SystemPromptMeta,\n  ) {\n    this.id = `prompt#${displayIdCounter++}`;\n\n    // Auto-register the moment a builder acquires a name — whether through the\n    // `systemPrompt(input, { name })` factory or a `.meta({ name })` rename.\n    // Forks built by `persona()` / `instruction()` / `merge()` deliberately\n    // drop the name (they pass no meta), so they stay anonymous and never land\n    // in the registry unless explicitly re-named.\n    if (metaData?.name) {\n      defaultPromptsManager().register(this);\n    }\n  }\n\n  /**\n   * Read the current metadata snapshot (no argument) or derive a renamed\n   * builder (with `meta`). The accessor returns `undefined` for an anonymous\n   * prompt; the updater shallow-merges `meta` onto the current metadata and\n   * returns a fresh builder. Naming the result registers it in `ai.prompts`.\n   */\n  public meta(): SystemPromptMeta | undefined;\n  public meta(meta: SystemPromptMeta): SystemPromptContract;\n  public meta(\n    meta?: SystemPromptMeta,\n  ): SystemPromptMeta | undefined | SystemPromptContract {\n    if (meta === undefined) {\n      return this.metaData;\n    }\n\n    return new SystemPrompt(this.blocks, { ...this.metaData, ...meta });\n  }\n\n  /**\n   * Build a system prompt by reading the file at `path` once, synchronously,\n   * at construction time. The file's UTF-8 contents seed a single instruction\n   * block — the same semantics as the string-seed form of `systemPrompt()` —\n   * so placeholders inside the file (`{{language|English}}`) resolve at\n   * `resolve()` time and the result can be forked with further\n   * `.persona()` / `.instruction()` calls.\n   *\n   * One-shot by design: the file is read exactly once here, never re-read on\n   * `resolve()`. Reads are synchronous so the call stays a drop-in for the\n   * synchronous `systemPrompt()` factory and the synchronous `resolve()` API.\n   *\n   * Throws `InvalidRequestError` when the file cannot be read (missing path,\n   * permission denied) — surfacing the underlying cause so a typo in the\n   * prompt path fails loudly at construction instead of silently producing an\n   * empty prompt.\n   *\n   * @param path - Filesystem path to the prompt template file.\n   *\n   * @example\n   * const prompt = SystemPrompt.fromFile(\"./prompts/support-agent.md\");\n   *\n   * const localized = prompt.instruction(\"Respond in {{language|English}}.\");\n   * localized.resolve({ language: \"Arabic\" });\n   */\n  public static fromFile(path: string): SystemPrompt {\n    let contents: string;\n\n    try {\n      contents = readFileSync(path, \"utf8\");\n    } catch (error) {\n      throw new InvalidRequestError(\n        `Failed to read system prompt file \"${path}\" — ${\n          error instanceof Error ? error.message : String(error)\n        }`,\n        { context: { path }, cause: error },\n      );\n    }\n\n    return new SystemPrompt([new Instruction(contents)]);\n  }\n\n  /**\n   * Return a new builder with the persona block set. If a persona already\n   * exists it's replaced in place (preserving its position in `blocks`);\n   * otherwise the new persona is prepended so persona-first remains the\n   * default for chain-built prompts. Accepts either raw text (auto-wrapped\n   * via `new Persona`) or an existing `PersonaContract` instance for reuse\n   * across prompts.\n   */\n  public persona(value: PersonaContract | string): SystemPromptContract {\n    const block = typeof value === \"string\" ? new Persona(value) : value;\n    const existingIndex = this.blocks.findIndex(\n      candidate => candidate.type === \"persona\",\n    );\n\n    if (existingIndex >= 0) {\n      const next = [...this.blocks];\n      next[existingIndex] = block;\n\n      return new SystemPrompt(next) as this;\n    }\n\n    return new SystemPrompt([block, ...this.blocks]);\n  }\n\n  /**\n   * Return a new builder with the given instruction appended. Instructions\n   * render in insertion order. Accepts either raw text (auto-wrapped via\n   * `new Instruction`) or an existing `InstructionContract` instance for\n   * cross-prompt reuse.\n   */\n  public instruction(\n    value: InstructionContract | string,\n  ): SystemPromptContract {\n    const block = typeof value === \"string\" ? new Instruction(value) : value;\n\n    return new SystemPrompt([...this.blocks, block]);\n  }\n\n  /**\n   * Fold predefined blocks, another prompt contract, or a registered prompt\n   * name into this builder. Three forms share one method:\n   *\n   * - `merge(...blocks)` — N pre-built `ai.persona()` / `ai.instruction()`\n   *   blocks. A `persona` block sets/replaces the single, leading persona;\n   *   every other block appends in order. `base.merge(reviewer, style, lang)`\n   *   equals `base.persona(reviewer).instruction(style).instruction(lang)`.\n   * - `merge(contract)` — another prompt; its blocks fold in (persona\n   *   replaces, instructions append) and `meta.composedFrom` records the\n   *   provenance of both sides.\n   * - `merge(name, { fromVersion })` — a prompt resolved from `ai.prompts`\n   *   (latest version unless `fromVersion` selects another); throws\n   *   `InvalidRequestError` when the name / version is unregistered.\n   *\n   * Immutable — the original builder is untouched; passing zero blocks returns\n   * an equivalent builder. The folded result is anonymous (no `name`), so it\n   * is never auto-registered even though it carries `composedFrom` provenance.\n   */\n  public merge(\n    ...blocks: readonly SystemPromptBlockContract[]\n  ): SystemPromptContract;\n  public merge(source: SystemPromptContract): SystemPromptContract;\n  public merge(\n    name: string,\n    options?: SystemPromptMergeOptions,\n  ): SystemPromptContract;\n  public merge(\n    first?:\n      | SystemPromptBlockContract\n      | SystemPromptContract\n      | string,\n    // `undefined` is part of the element union so the `merge(name, options?)`\n    // overload's optional trailing `options?` (i.e. `… | undefined`) stays\n    // assignable to this implementation signature.\n    ...rest: readonly (\n      | SystemPromptBlockContract\n      | SystemPromptMergeOptions\n      | undefined\n    )[]\n  ): SystemPromptContract {\n    // Registry-name form: resolve from ai.prompts at the chosen version.\n    if (typeof first === \"string\") {\n      const options = rest[0] as SystemPromptMergeOptions | undefined;\n      const resolved = defaultPromptsManager().get(first, options?.fromVersion);\n\n      return this.mergeContract(resolved);\n    }\n\n    // Contract form: fold another prompt's blocks + record provenance.\n    if (isSystemPromptContract(first)) {\n      return this.mergeContract(first);\n    }\n\n    // Variadic block form (the original behavior).\n    const all = [\n      ...(first ? [first] : []),\n      ...rest,\n    ] as readonly SystemPromptBlockContract[];\n\n    return this.foldBlocks(this, all);\n  }\n\n  /**\n   * Fold an ordered list of blocks onto a starting prompt: persona blocks\n   * set/replace the single leading persona; every other block appends in\n   * order. The shared core of the variadic-block `merge` and the contract fold.\n   */\n  private foldBlocks(\n    start: SystemPromptContract,\n    blocks: readonly SystemPromptBlockContract[],\n  ): SystemPromptContract {\n    return blocks.reduce<SystemPromptContract>((prompt, block) => {\n      if (block.type === \"persona\") {\n        return prompt.persona(block as PersonaContract);\n      }\n\n      return new SystemPrompt([...prompt.blocks, block]);\n    }, start);\n  }\n\n  /**\n   * Fold another prompt contract into this one (persona replaces, instructions\n   * append) and stamp the deterministic `composedFrom` provenance — this\n   * prompt's existing provenance (or its own label) followed by the folded\n   * source's label. The result is anonymous so it never auto-registers.\n   */\n  private mergeContract(\n    source: SystemPromptContract,\n  ): SystemPromptContract {\n    const folded = this.foldBlocks(this, source.blocks);\n\n    const baseProvenance =\n      this.metaData?.composedFrom ??\n      (this.metaData?.name ? [provenanceLabel(this)] : []);\n\n    const composedFrom = [...baseProvenance, provenanceLabel(source)];\n\n    // Carry forward only provenance — never the name — so the merged result is\n    // a fresh anonymous prompt (immutable rename = new key; original stays).\n    return new SystemPrompt(folded.blocks, { composedFrom });\n  }\n\n  /**\n   * Resolve every block against the placeholder map, join the results with\n   * blank-line separators (in insertion order), and trim. Returns an empty\n   * string when no blocks are present — callers treat that as \"no system\n   * message\".\n   */\n  public resolve(placeholders?: Placeholders): string {\n    return this.blocks\n      .map(block => block.resolve(placeholders))\n      .join(\"\\n\\n\")\n      .trim();\n  }\n\n  /**\n   * Validate this prompt via the process-wide `ai.prompts` manager — sugar for\n   * `ai.prompts.validate(this, options)`. Runs the deterministic placeholder\n   * check and, when `options.judge` is supplied, the Nova-safe LLM-as-judge\n   * pass. Never throws on a judge failure; `ok` tracks the deterministic\n   * verdict alone.\n   */\n  public validate(\n    options?: PromptsValidateOptions,\n  ): Promise<PromptValidationResult> {\n    return defaultPromptsManager().validate(this, options);\n  }\n\n  /**\n   * Derive the compiled form of this prompt — a lazy wrapper that rewrites\n   * the human-authored text into a model-optimized version on first use,\n   * pins the result, and serves the pin thereafter. See\n   * {@link RefinedSystemPromptContract} for the full semantics (lockfile\n   * pinning, placeholder parity, advisory fallback, `refine()` /\n   * `refinePrompt()`).\n   *\n   * The wrapper's collaborators are injected here rather than imported by\n   * `refined-system-prompt.ts` — importing this module (or the prompts\n   * manager) back from there would close an import cycle.\n   */\n  public refined(\n    options: RefinedSystemPromptOptions,\n  ): RefinedSystemPromptContract {\n    return new RefinedSystemPrompt(this, options, {\n      buildPrompt: (blocks, meta) => new SystemPrompt([...blocks], meta),\n      validatePrompt: (target, validateOptions) =>\n        defaultPromptsManager().validate(target, validateOptions),\n    });\n  }\n}\n\n/**\n * Public factory for `SystemPrompt`, callable directly or via its\n * `fromFile` static. Exists as a named interface so the callable signature\n * and the `fromFile` attachment travel together as one public type.\n */\nexport interface SystemPromptFactory {\n  (\n    input?: string | ReadonlyArray<SystemPromptBlockContract>,\n    meta?: SystemPromptMeta,\n  ): SystemPrompt;\n\n  /**\n   * Build a system prompt from a file read once at construction. Delegates\n   * to {@link SystemPrompt.fromFile}, so `ai.systemPrompt.fromFile(path)` and\n   * `SystemPrompt.fromFile(path)` behave identically.\n   *\n   * @example\n   * const prompt = ai.systemPrompt.fromFile(\"./prompts/support-agent.md\");\n   */\n  fromFile(path: string): SystemPrompt;\n}\n\nfunction systemPromptFactory(\n  input?: string | ReadonlyArray<SystemPromptBlockContract>,\n  meta?: SystemPromptMeta,\n): SystemPrompt {\n  if (input === undefined) {\n    return new SystemPrompt([], meta);\n  }\n\n  if (typeof input === \"string\") {\n    return new SystemPrompt([new Instruction(input)], meta);\n  }\n\n  return new SystemPrompt([...input], meta);\n}\n\n/**\n * Create a new immutable system-prompt builder.\n *\n * **Role.** Public factory for `SystemPrompt` — keeps user-facing code\n * free of `new` and consistent with `ai.tool()`, `ai.agent()`,\n * `ai.persona()`, `ai.instruction()`.\n *\n * Input forms:\n * - No argument → empty builder, chain `.persona()` / `.instruction()`\n * - Single string → seeded with one instruction for quick one-shot prompts\n * - Array of blocks → used verbatim, preserving insertion order\n * - `.fromFile(path)` → seeded from a file read once at construction\n *\n * Pass a second `meta` argument to name the prompt — a named prompt\n * auto-registers in `ai.prompts` under `name@version` (version defaults to the\n * next integer). Forks (`.persona()`, `.instruction()`, `.merge()`) are\n * anonymous unless re-named via `.meta({ name })`.\n *\n * @example\n * // Composed builder\n * const prompt = systemPrompt()\n *   .persona(\"You are Alex, a senior TypeScript engineer.\")\n *   .instruction(\"Always include working code examples.\")\n *   .instruction(\"Respond in {{language|English}}.\");\n *\n * prompt.resolve({ language: \"Arabic\" });\n *\n * @example\n * // One-shot seed\n * const prompt = systemPrompt(\"Answer only with JSON matching the schema.\");\n *\n * @example\n * // From a file, read once at construction\n * const prompt = systemPrompt.fromFile(\"./prompts/support-agent.md\");\n *\n * @example\n * // Array form — fully declarative\n * const prompt = systemPrompt([\n *   ai.persona(\"You are Alex.\"),\n *   ai.instruction(\"Always cite sources.\"),\n *   ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport const systemPrompt: SystemPromptFactory = Object.assign(\n  systemPromptFactory,\n  { fromFile: SystemPrompt.fromFile },\n);\n"],"mappings":"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"}