{"version":3,"file":"retrievables.mjs","names":[],"sources":["../../../src/batteries/tools/retrievables/index.ts"],"sourcesContent":["/**\n * Pre-constructed CRUD tools for model-visible retrievable and RAG-record management.\n *\n * @module @nhtio/adk/batteries/tools/retrievables\n *\n * @remarks\n * Pre-constructed CRUD tools that expose the ADK's {@link @nhtio/adk!Retrievable} surface to the\n * model. Each tool delegates to the corresponding callback on the active\n * {@link @nhtio/adk!DispatchContext} (`fetchRetrievables`, `storeRetrievable`, `mutateRetrievable`,\n * `deleteRetrievable`) — the persistence layer is whatever the consumer wired into the\n * runner.\n *\n * Retrievables are RAG records and carry an explicit `trustTier` that drives the LLM\n * battery's rendering envelope. Exposing these CRUD tools to the model is a deliberate\n * deployer decision; the trust tier the model declares when creating or updating a record\n * is honoured verbatim by the persistence layer. The deployer is responsible for choosing\n * whether to register all four tools, only the read-only `list_retrievables`, or any subset\n * thereof — that registration choice is exactly the trust boundary documented in the\n * Retrievable battery contract.\n *\n * Output is JSON for every tool so consumers can parse the result without re-tokenising —\n * the artifact constructor is set to {@link @nhtio/adk!SpooledJsonArtifact}.\n *\n * Tools:\n * - {@link listRetrievablesTool} — read-only list of every retrievable currently held by\n *   the context.\n * - {@link storeRetrievableTool} — create a new retrievable record (auto-generates `id` /\n *   `createdAt` / `updatedAt` unless explicit values are supplied).\n * - {@link updateRetrievableTool} — replace an existing retrievable by `id`. Bumps\n *   `updatedAt`.\n * - {@link deleteRetrievableTool} — remove a retrievable by `id`.\n */\n\nimport { DateTime } from 'luxon'\nimport { v6 as uuidv6 } from 'uuid'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { Retrievable, SpooledJsonArtifact, Tool } from '@nhtio/adk/common'\n\nconst TRUST_TIERS = ['first-party', 'third-party-public', 'third-party-private'] as const\ntype TrustTier = (typeof TRUST_TIERS)[number]\n\nconst serialiseRetrievable = async (r: Retrievable): Promise<Record<string, unknown>> => ({\n  id: r.id,\n  content: await r.contentString(),\n  trustTier: r.trustTier,\n  source: r.source,\n  kind: r.kind,\n  score: r.score,\n  createdAt: r.createdAt.toISO(),\n  updatedAt: r.updatedAt.toISO(),\n})\n\n/**\n * List every retrievable record currently held by the active execution context.\n *\n * @remarks\n * Delegates to `ctx.fetchRetrievables()`. Returns a JSON-encoded array of retrievable records\n * (id, content, trustTier, source, kind, score, createdAt, updatedAt).\n */\nexport const listRetrievablesTool = new Tool({\n  name: 'list_retrievables',\n  description:\n    'List every retrievable record currently available to the agent. Returns a JSON array of records with id, content, trustTier, source, kind, score, createdAt, and updatedAt.',\n  inputSchema: validator.object({}),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (_args, ctx) => {\n    try {\n      const retrievables = await ctx.fetchRetrievables()\n      const serialised = await Promise.all(retrievables.map(serialiseRetrievable))\n      return JSON.stringify(serialised, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Create a new {@link @nhtio/adk!Retrievable} record and persist it via the context's `storeRetrievable`\n * callback.\n *\n * @remarks\n * When `id` is omitted, a UUID v6 is generated. When `createdAt` / `updatedAt` are omitted,\n * the current time is used. The model must declare `trustTier` explicitly — there is no\n * default; the choice is consciously the model's, exposed by the deployer's decision to\n * register this tool.\n */\nexport const storeRetrievableTool = new Tool({\n  name: 'store_retrievable',\n  description:\n    \"Store a new retrievable (RAG) record. The trustTier MUST be one of 'first-party' (deployer-vetted), 'third-party-public' (open-web), or 'third-party-private' (user uploads). id and timestamps are auto-generated if omitted.\",\n  inputSchema: validator.object({\n    content: validator\n      .string()\n      .required()\n      .description('The retrievable content as a plain string.'),\n    trustTier: validator\n      .string()\n      .valid(...TRUST_TIERS)\n      .required()\n      .description(\n        \"Trust tier: 'first-party' for deployer-vetted material, 'third-party-public' for open-web or public APIs, 'third-party-private' for user uploads or partner APIs.\"\n      ),\n    source: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Optional provenance string: URL, document path, KB id, etc. An empty string is treated as not provided.'\n      ),\n    kind: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        \"Optional semantic label: 'policy', 'reference', 'web-page', 'pdf', etc. An empty string is treated as not provided.\"\n      ),\n    score: validator\n      .number()\n      .min(0)\n      .max(1)\n      .optional()\n      .description('Optional relevance / similarity score in [0, 1].'),\n    id: validator\n      .string()\n      .optional()\n      .allow('')\n      .description('Optional stable id. Auto-generated when absent or an empty string.'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { content, trustTier, source, kind, score, id } = args as {\n      content: string\n      trustTier: TrustTier\n      source?: string\n      kind?: string\n      score?: number\n      id?: string\n    }\n    try {\n      const now = DateTime.now()\n      const retrievable = new Retrievable({\n        id: (id || undefined) ?? uuidv6(),\n        content,\n        trustTier,\n        source: source || undefined,\n        kind: kind || undefined,\n        score,\n        createdAt: now,\n        updatedAt: now,\n      })\n      await ctx.storeRetrievable(retrievable)\n      return JSON.stringify(\n        { ok: true, retrievable: await serialiseRetrievable(retrievable) },\n        null,\n        2\n      )\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Replace an existing {@link @nhtio/adk!Retrievable} by `id`.\n *\n * @remarks\n * The model supplies `id` plus any subset of `content` / `trustTier` / `source` / `kind` /\n * `score`; omitted fields retain their prior values. `updatedAt` is always bumped;\n * `createdAt` is preserved. Returns an error when no retrievable with the supplied `id` is\n * found.\n */\nexport const updateRetrievableTool = new Tool({\n  name: 'update_retrievable',\n  description:\n    'Update an existing retrievable by id. Supply any subset of content / trustTier / source / kind / score — omitted fields retain their prior values. updatedAt is always refreshed.',\n  inputSchema: validator.object({\n    id: validator.string().required().description('Id of the retrievable to update.'),\n    content: validator\n      .string()\n      .optional()\n      .allow('')\n      .description('Replacement content. Omit or send an empty string to leave it unchanged.'),\n    trustTier: validator\n      .string()\n      .valid(...TRUST_TIERS)\n      .optional()\n      .description('Replacement trust tier.'),\n    source: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Replacement provenance string. Omit or send an empty string to leave it unchanged.'\n      ),\n    kind: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Replacement semantic label. Omit or send an empty string to leave it unchanged.'\n      ),\n    score: validator.number().min(0).max(1).optional().description('Replacement score in [0, 1].'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { id, content, trustTier, source, kind, score } = args as {\n      id: string\n      content?: string\n      trustTier?: TrustTier\n      source?: string\n      kind?: string\n      score?: number\n    }\n    try {\n      const retrievables = await ctx.fetchRetrievables()\n      const existing = retrievables.find((r) => r.id === id)\n      if (!existing) {\n        return `Error: No retrievable found with id \"${id}\".`\n      }\n      const updated = new Retrievable({\n        id: existing.id,\n        content: (content || undefined) ?? existing.content,\n        trustTier: trustTier ?? existing.trustTier,\n        source: (source || undefined) ?? existing.source,\n        kind: (kind || undefined) ?? existing.kind,\n        score: score ?? existing.score,\n        createdAt: existing.createdAt,\n        updatedAt: DateTime.now(),\n      })\n      await ctx.mutateRetrievable(updated)\n      return JSON.stringify({ ok: true, retrievable: await serialiseRetrievable(updated) }, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Remove an existing {@link @nhtio/adk!Retrievable} by `id`.\n *\n * @remarks\n * Delegates to `ctx.deleteRetrievable(id)`. Returns `{ ok: true, id }` on success regardless\n * of whether a retrievable was actually present — `deleteRetrievable` is idempotent at the\n * ADK level.\n */\nexport const deleteRetrievableTool = new Tool({\n  name: 'delete_retrievable',\n  description: 'Delete a retrievable by id.',\n  inputSchema: validator.object({\n    id: validator.string().required().description('Id of the retrievable to delete.'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { id } = args as { id: string }\n    try {\n      await ctx.deleteRetrievable(id)\n      return JSON.stringify({ ok: true, id }, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Convenience tuple of every retrievable CRUD tool. Spread into a {@link @nhtio/adk!ToolRegistry} to\n * register the entire category at once.\n */\nexport const retrievableTools = [\n  listRetrievablesTool,\n  storeRetrievableTool,\n  updateRetrievableTool,\n  deleteRetrievableTool,\n] as const\n"],"mappings":"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"}