{"version":3,"file":"tool.mjs","names":[],"sources":["../../../../../../../ai/src/tool/tool.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { BaseReport } from \"../contracts/result/base-report.type\";\nimport type { Usage } from \"../contracts/result/usage.type\";\nimport type { ToolConfig, ToolContext } from \"../contracts/tool.contract\";\nimport { AIError, SchemaValidationError, ToolExecutionError } from \"../errors\";\nimport { generateRunId } from \"../utils/generate-run-id\";\n\n/**\n * Degraded `ToolContext` supplied when no caller threads one through\n * (`tool.invoke(input)` standalone, batch scripts, tests). Per\n * decisions §35 — mutations on the empty bag are harmless no-ops;\n * production paths under a supervisor receive a real ctx with the\n * iteration's shared bag.\n */\nfunction defaultToolContext(): ToolContext {\n  return { artifacts: {} };\n}\n\nconst EMPTY_USAGE: Usage = Object.freeze({ input: 0, output: 0, total: 0 });\n\n/**\n * Result returned by `ToolContract.invoke()`.\n *\n * **Canonical destructure:** `const { data, usage, report, error }` —\n * matches every other executable (`AgentResult`, `WorkflowResult`,\n * `SupervisorResult`) so parent agents can treat every tool dispatch\n * uniformly.\n *\n * **Shape.** `data` / `error` carry the outcome; `usage` and `report`\n * are always present. For leaf tools, `usage` is zero and `report`\n * is a framework-synthesized {@link BaseReport} (`type: \"tool\"`,\n * `children: []`, real timing) so parents never have to nil-check.\n * For composites wrapped via `asTool()`, `usage` and `report` mirror\n * the inner primitive's — the nested tree lives in `report.children`.\n *\n * @example\n * const result = await myTool.invoke({ city: \"Cairo\" });\n * if (result.error) console.error(result.error.message);\n * else console.log(result.data, result.report.duration);\n */\nexport type ToolInvokeResult<TOutput> = {\n  /** Successfully-returned output. Undefined if execution or validation failed. */\n  data?: TOutput;\n  /** Typed AI error produced by validation or execute(), if any. */\n  error?: AIError;\n  /** Rolled-up usage (zero for leaf tools, populated for composites). */\n  usage: Usage;\n  /** Recursive execution report — `report.children` carries nested executables. */\n  report: BaseReport;\n};\n\n/**\n * A `ToolConfig` augmented with a safe `invoke()` entry point for the agent runtime.\n *\n * @example\n * const wrapped: ToolContract<{ city: string }, { temp: number }> = tool(contract);\n * const result = await wrapped.invoke({ city: \"Cairo\" });\n */\nexport interface ToolContract<TInput = unknown, TOutput = unknown> extends ToolConfig<\n  TInput,\n  TOutput\n> {\n  /**\n   * Agent-runtime entry point. Validates raw input against the tool's schema,\n   * calls execute(), catches errors, and reports duration.\n   * Never throws — errors surface in the returned `error` field as\n   * typed `AIError` subclasses.\n   *\n   * The optional second argument is a `ToolContext` (Phase 5 /\n   * decisions §35) — when supplied, threaded into `execute(input, ctx)`\n   * so tools can write system-only side data into `ctx.artifacts`.\n   * Standalone callers may omit it; the framework supplies a\n   * degraded `{ artifacts: {} }` so single-arg legacy handlers keep\n   * working unchanged.\n   *\n   * @example\n   * const result = await myTool.invoke(rawLLMArgs);\n   * if (result.error) handleError(result.error);\n   */\n  invoke(rawInput: unknown, ctx?: ToolContext): Promise<ToolInvokeResult<TOutput>>;\n}\n\n/**\n * Wraps a raw `ToolConfig` and adds a safe `invoke()` method for the agent runtime.\n * The returned object preserves all original contract fields unchanged.\n *\n * Error categorization:\n * - Input schema rejects model args → `SchemaValidationError` (issues preserved).\n * - Schema's `validate()` itself throws → `SchemaValidationError` wrapping the cause.\n * - `execute()` throws → `ToolExecutionError` wrapping the cause.\n *\n * @example\n * const weatherTool = tool({\n *   name: \"getWeather\",\n *   description: \"Fetch current weather for a city\",\n *   input: z.object({ city: z.string() }),\n *   execute: async ({ city }) => ({ temp: 72 }),\n * });\n *\n * const result = await weatherTool.invoke({ city: \"Cairo\" });\n */\n/**\n * Internal factory for `asTool()` wrappers on composite primitives\n * (agent / workflow / supervisor). Unlike the public `tool()` factory\n * (which synthesizes a leaf `BaseReport` every time), this variant\n * lets the composite's own `ExecuteResult` flow through: the inner\n * primitive's `report` becomes the sole child of the outer tool-call\n * node, and the inner `usage` is surfaced so parents can roll it up.\n *\n * The caller supplies `execute()` returning `{ data, usage, report }`\n * from the composite's own `execute()` method. Validation failures\n * and thrown errors still produce a synthesized failed leaf report —\n * the inner-report propagation is strictly a success-path concern.\n *\n * Not exported from the package barrel — used by `agent.asTool()`,\n * `workflow.asTool()`, `supervisor.asTool()` only.\n */\nexport function compositeAsTool<TInput, TOutput>(contract: {\n  name: string;\n  description?: string;\n  version?: string;\n  meta?: ToolConfig[\"meta\"];\n  input: StandardSchemaV1<TInput>;\n  /**\n   * Runs the underlying composite and returns its full envelope. The\n   * optional `ctx` relays the outer run's cancellation `signal` so a\n   * cancelled parent aborts the nested primitive instead of letting it\n   * outlive the cancellation (C2).\n   */\n  execute: (input: TInput, ctx?: ToolContext) => Promise<{\n    data?: TOutput;\n    error?: AIError;\n    usage: Usage;\n    report: BaseReport;\n  }>;\n}): ToolContract<TInput, TOutput> {\n  // The underlying `ToolConfig<TInput, TOutput>.execute` is typed as\n  // `(input) => Promise<TOutput>`, but composite wrappers return an\n  // envelope object instead. Surface a contract-shaped view that\n  // extracts `.data` on demand for any code that still treats this\n  // like a plain tool.\n  const publicExecute = async (input: TInput): Promise<TOutput> => {\n    const envelope = await contract.execute(input);\n    if (envelope.error) throw envelope.error;\n    return envelope.data as TOutput;\n  };\n\n  return {\n    name: contract.name,\n    description: contract.description ?? `Composite tool \"${contract.name}\".`,\n    meta: contract.meta,\n    input: contract.input,\n    execute: publicExecute,\n\n    async invoke(rawInput: unknown, ctx?: ToolContext): Promise<ToolInvokeResult<TOutput>> {\n      // Composite tools (asTool-wrapped agent/workflow/supervisor) run in\n      // their own state/scope — the ctx's `artifacts` bag is NOT shared\n      // into the inner primitive (an inner supervisor gets a fresh bag).\n      // The cancellation `signal`, however, IS relayed (below, into\n      // `contract.execute`) so a cancelled outer run aborts the nested\n      // primitive instead of letting it outlive the cancellation (C2).\n      const startedAtDate = new Date();\n      const start = performance.now();\n      const runId = generateRunId(\"tool\");\n\n      const failLeaf = (error: AIError): ToolInvokeResult<TOutput> => {\n        const endedAt = new Date().toISOString();\n        const duration = performance.now() - start;\n        return {\n          error,\n          usage: EMPTY_USAGE,\n          report: {\n            runId,\n            rootRunId: runId,\n            name: contract.name,\n            version: contract.version,\n            type: \"tool\",\n            status: \"failed\",\n            startedAt: startedAtDate.toISOString(),\n            endedAt,\n            duration,\n            usage: EMPTY_USAGE,\n            children: [],\n          },\n        };\n      };\n\n      let validationResult: StandardSchemaV1.Result<TInput>;\n      try {\n        const schema = contract.input as StandardSchemaV1<TInput>;\n        validationResult = await schema[\"~standard\"].validate(rawInput);\n      } catch (thrown) {\n        const message = thrown instanceof Error ? thrown.message : String(thrown);\n        return failLeaf(\n          new SchemaValidationError(\n            `Schema validation threw for tool \"${contract.name}\": ${message}`,\n            { cause: thrown, context: { toolName: contract.name } },\n          ),\n        );\n      }\n\n      if (validationResult.issues) {\n        const summary = validationResult.issues.map((issue) => issue.message).join(\"; \");\n        return failLeaf(\n          new SchemaValidationError(`Validation failed: ${summary}`, {\n            issues: validationResult.issues,\n            context: { toolName: contract.name },\n          }),\n        );\n      }\n\n      try {\n        const composite = await contract.execute(validationResult.value, ctx);\n        // Surface the inner primitive's full envelope. The outer\n        // ToolInvokeResult carries the composite's usage and report\n        // verbatim; the agent runtime nests the report as a child of\n        // the tool-dispatch node it records.\n        return {\n          data: composite.data,\n          error: composite.error,\n          usage: composite.usage,\n          report: composite.report,\n        };\n      } catch (thrown) {\n        const message = thrown instanceof Error ? thrown.message : String(thrown);\n        return failLeaf(\n          new ToolExecutionError(message, {\n            cause: thrown,\n            toolName: contract.name,\n          }),\n        );\n      }\n    },\n  };\n}\n\nexport function tool<TInput, TOutput>(\n  contract: ToolConfig<TInput, TOutput>,\n): ToolContract<TInput, TOutput> {\n  return {\n    ...contract,\n\n    async invoke(rawInput: unknown, ctx?: ToolContext): Promise<ToolInvokeResult<TOutput>> {\n      const startedAtDate = new Date();\n      const start = performance.now();\n      const runId = generateRunId(\"tool\");\n      const handlerCtx = ctx ?? defaultToolContext();\n\n      const finish = (partial: { data?: TOutput; error?: AIError }): ToolInvokeResult<TOutput> => {\n        const endedAt = new Date().toISOString();\n        const duration = performance.now() - start;\n        const status: BaseReport[\"status\"] = partial.error ? \"failed\" : \"completed\";\n        const report: BaseReport = {\n          runId,\n          rootRunId: runId,\n          name: contract.name,\n          version: contract.version,\n          type: \"tool\",\n          status,\n          startedAt: startedAtDate.toISOString(),\n          endedAt,\n          duration,\n          usage: EMPTY_USAGE,\n          children: [],\n        };\n\n        return {\n          ...partial,\n          usage: EMPTY_USAGE,\n          report,\n        };\n      };\n\n      let validationResult: StandardSchemaV1.Result<TInput>;\n      if (contract.input) {\n        try {\n          validationResult = await contract.input[\"~standard\"].validate(rawInput);\n        } catch (thrown) {\n          const message = thrown instanceof Error ? thrown.message : String(thrown);\n\n          return finish({\n            error: new SchemaValidationError(\n              `Schema validation threw for tool \"${contract.name}\": ${message}`,\n              { cause: thrown, context: { toolName: contract.name } },\n            ),\n          });\n        }\n      } else {\n        // `input` is optional on ToolConfig — this is a no-argument tool\n        // (e.g. view_cart, checkout). With no schema there is nothing to\n        // validate, so pass the raw model args straight to execute()\n        // instead of dereferencing a missing schema's `~standard`.\n        validationResult = { value: rawInput as TInput };\n      }\n\n      if (validationResult.issues) {\n        const summary = validationResult.issues.map((issue) => issue.message).join(\"; \");\n\n        return finish({\n          error: new SchemaValidationError(`Validation failed: ${summary}`, {\n            issues: validationResult.issues,\n            context: { toolName: contract.name },\n          }),\n        });\n      }\n\n      try {\n        const output = await contract.execute(validationResult.value, handlerCtx);\n        return finish({ data: output });\n      } catch (thrown) {\n        const message = thrown instanceof Error ? thrown.message : String(thrown);\n\n        return finish({\n          error: new ToolExecutionError(message, {\n            cause: thrown,\n            toolName: contract.name,\n          }),\n        });\n      }\n    },\n  };\n}\n"],"mappings":"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"}