"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tool_context_exports = {};
__export(tool_context_exports, {
  CONFIRM_DUPLICATE_PARAM: () => CONFIRM_DUPLICATE_PARAM,
  ProviderTool: () => ProviderTool,
  ToolContext: () => ToolContext,
  ToolError: () => ToolError,
  ToolFlag: () => ToolFlag,
  Toolset: () => Toolset,
  handoff: () => handoff,
  isAgentHandoff: () => isAgentHandoff,
  isFunctionTool: () => isFunctionTool,
  isProviderTool: () => isProviderTool,
  isSameToolChoice: () => isSameToolChoice,
  isTool: () => isTool,
  isToolError: () => isToolError,
  isToolset: () => isToolset,
  normalizeToolContextInit: () => normalizeToolContextInit,
  sortedToolEntries: () => sortedToolEntries,
  sortedToolNames: () => sortedToolNames,
  toToolContext: () => toToolContext,
  tool: () => tool
});
module.exports = __toCommonJS(tool_context_exports);
var import_zod = require("zod");
var z4 = __toESM(require("zod/v4"), 1);
var import_zod_utils = require("./zod-utils.cjs");
const TOOL_SYMBOL = Symbol("tool");
const FUNCTION_TOOL_SYMBOL = Symbol("function_tool");
const PROVIDER_TOOL_SYMBOL = Symbol("provider_tool");
const TOOLSET_SYMBOL = Symbol("toolset");
const TOOL_ERROR_SYMBOL = Symbol("tool_error");
const HANDOFF_SYMBOL = Symbol("handoff");
const CONFIRM_DUPLICATE_PARAM = "lk_agents_confirm_duplicate";
const CONFIRM_DUPLICATE_DESCRIPTION = "Set this to true to confirm you want to run a duplicate. Only do this when user confirms the duplication is needed.";
class ToolError extends Error {
  constructor(message) {
    super(message);
    Object.defineProperty(this, TOOL_ERROR_SYMBOL, {
      value: true
    });
  }
}
const ToolFlag = {
  NONE: 0,
  IGNORE_ON_ENTER: 1 << 0,
  CANCELLABLE: 1 << 1
};
function handoff(options) {
  return {
    agent: options.agent,
    returns: options.returns,
    [HANDOFF_SYMBOL]: true
  };
}
class ProviderTool {
  type = "provider";
  id;
  [TOOL_SYMBOL] = true;
  [PROVIDER_TOOL_SYMBOL] = true;
  constructor({ id }) {
    this.id = id;
  }
}
function sortedToolEntries(toolCtx) {
  return Object.entries(toolCtx.functionTools).sort(
    ([nameA], [nameB]) => nameA.localeCompare(nameB)
  );
}
function sortedToolNames(toolCtx) {
  if (!toolCtx) return [];
  return Object.keys(toolCtx.functionTools).sort((nameA, nameB) => nameA.localeCompare(nameB));
}
class Toolset {
  #id;
  #tools;
  [TOOLSET_SYMBOL] = true;
  constructor({ id, tools }) {
    this.#id = id;
    this.#tools = [...tools];
  }
  /**
   * For when your tools share something that needs setup or cleanup, like a DB pool, an open MCP
   * client, or listeners on a shared bus. `setup` runs once at activation, `aclose` once at
   * teardown. If the tool list itself is dynamic (e.g. an MCP server), push it from `setup` via
   * {@link ToolsetContext.updateTools}.
   *
   * @example Static tool list with a shared backing resource
   * ```ts
   * function createPostgresToolset(connectionUrl: string): Toolset {
   *   const pool = new pg.Pool({ connectionString: connectionUrl });
   *   return Toolset.create({
   *     id: 'postgres',
   *     tools: [queryOrders, queryCustomers],
   *     aclose: () => pool.end(),
   *   });
   * }
   * ```
   *
   * @example Dynamic tool list bound to an external source
   * ```ts
   * function createMcpToolset(url: string): Toolset {
   *   const client = new MCPClient({ url });
   *   return Toolset.create({
   *     id: 'mcp_remote',
   *     // setup connects and wires listeners that push the server's tools whenever they change;
   *     // the runtime re-advertises without re-running anything.
   *     setup: async ({ updateTools }) => {
   *       const sync = async () => updateTools(await client.listTools());
   *       client.on('connect', sync);
   *       client.on('tool_list_changed', sync);
   *       await client.connect();
   *     },
   *     tools: [],
   *     aclose: () => client.disconnect(),
   *   });
   * }
   * ```
   */
  static create(options) {
    return new ToolsetFactory(options);
  }
  get id() {
    return this.#id;
  }
  get tools() {
    return this.#tools;
  }
  /**
   * Replace the toolset's current tools. Backs {@link ToolsetContext.updateTools}; the runtime
   * re-flattens and re-advertises after calling it.
   *
   * @internal
   */
  _setTools(tools) {
    this.#tools = [...tools];
  }
  async setup(_ctx) {
  }
  async aclose() {
  }
}
class ToolsetFactory extends Toolset {
  #setupFn;
  #acloseFn;
  constructor({ id, setup, tools, aclose }) {
    super({ id, tools });
    this.#setupFn = setup;
    this.#acloseFn = aclose;
  }
  async setup(ctx) {
    if (this.#setupFn) await this.#setupFn(ctx);
  }
  async aclose() {
    if (this.#acloseFn) await this.#acloseFn();
  }
}
function toToolContext(input) {
  if (input === void 0) return void 0;
  return input instanceof ToolContext ? input : new ToolContext(input);
}
function normalizeToolContextInit(input) {
  if (Array.isArray(input)) {
    return [...input];
  }
  return Object.entries(input).map(([name, toolValue]) => {
    if (name.length === 0) {
      throw new Error("tools object keys must be non-empty");
    }
    if (!isAnonFunctionTool(toolValue)) {
      throw new Error(`tools object entry "${name}" must be an anonymous function tool`);
    }
    if ("name" in toolValue || "id" in toolValue) {
      throw new Error(`tools object entry "${name}" must be anonymous`);
    }
    return {
      ...toolValue,
      id: name,
      name
    };
  });
}
class ToolContext {
  _tools = [];
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ToolContext stores generic function tools
  _functionToolsMap = /* @__PURE__ */ new Map();
  _providerTools = [];
  _toolsets = [];
  constructor(tools = []) {
    this.updateTools(tools);
  }
  static empty() {
    return new ToolContext([]);
  }
  /** A copy of all function tools in the tool context, including those in tool sets. */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  get functionTools() {
    return Object.fromEntries(this._functionToolsMap);
  }
  /** A copy of all provider tools in the tool context, including those in tool sets. */
  get providerTools() {
    return [...this._providerTools];
  }
  /** A copy of all toolsets registered in the context. */
  get toolsets() {
    return [...this._toolsets];
  }
  /**
   * A copy of the raw tool list this context was constructed with.
   */
  get tools() {
    return [...this._tools];
  }
  /** Flatten the tool context to a list of tools. */
  flatten() {
    return [...this._functionToolsMap.values(), ...this._providerTools];
  }
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Generic registry over any parameter/result types
  getFunctionTool(id) {
    return this._functionToolsMap.get(id);
  }
  hasTool(id) {
    if (this._functionToolsMap.has(id)) {
      return true;
    }
    return this._providerTools.some((tool2) => tool2.id === id);
  }
  updateTools(tools) {
    const normalizedTools = normalizeToolContextInit(tools);
    this._tools = normalizedTools;
    this._functionToolsMap = /* @__PURE__ */ new Map();
    this._providerTools = [];
    this._toolsets = [];
    const addTool = (tool2) => {
      if (isToolset(tool2)) {
        for (const inner of tool2.tools) {
          addTool(inner);
        }
        this._toolsets.push(tool2);
        return;
      }
      if (isProviderTool(tool2)) {
        this._providerTools.push(tool2);
        return;
      }
      if (isFunctionTool(tool2)) {
        const existing = this._functionToolsMap.get(tool2.id);
        if (existing !== void 0) {
          if (existing !== tool2) {
            throw new Error(`duplicate function name: ${tool2.id}`);
          }
          return;
        }
        this._functionToolsMap.set(tool2.id, tool2);
        return;
      }
      throw new Error(`unknown tool type: ${typeof tool2}`);
    };
    for (const tool2 of normalizedTools) {
      addTool(tool2);
    }
  }
  copy() {
    return new ToolContext([...this._tools]);
  }
  equals(other) {
    if (this._functionToolsMap.size !== other._functionToolsMap.size) {
      return false;
    }
    for (const [id, tool2] of this._functionToolsMap) {
      if (other._functionToolsMap.get(id) !== tool2) {
        return false;
      }
    }
    if (this._providerTools.length !== other._providerTools.length) {
      return false;
    }
    const otherProviderIds = new Set(other._providerTools);
    for (const tool2 of this._providerTools) {
      if (!otherProviderIds.has(tool2)) {
        return false;
      }
    }
    if (this._toolsets.length !== other._toolsets.length) {
      return false;
    }
    const otherToolsets = new Set(other._toolsets);
    for (const ts of this._toolsets) {
      if (!otherToolsets.has(ts)) {
        return false;
      }
    }
    return true;
  }
}
function isSameToolChoice(choice1, choice2) {
  if (choice1 === choice2) {
    return true;
  }
  if (choice1 === null || choice2 === null) {
    return false;
  }
  if (typeof choice1 === "string" && typeof choice2 === "string") {
    return choice1 === choice2;
  }
  if (typeof choice1 === "object" && typeof choice2 === "object") {
    return choice1.type === choice2.type && choice1.function.name === choice2.function.name;
  }
  return false;
}
function tool(tool2) {
  if (tool2.name !== void 0 && (typeof tool2.name !== "string" || tool2.name.length === 0)) {
    throw new Error("tool({ name, ... }) requires a non-empty name");
  }
  const onDuplicate = tool2.onDuplicate ?? "allow";
  let parameters = tool2.parameters ?? import_zod.z.object({});
  if ((0, import_zod_utils.isZodSchema)(parameters) && !(0, import_zod_utils.isZodObjectSchema)(parameters)) {
    throw new Error("Tool parameters must be a Zod object schema (z.object(...))");
  }
  if (!(0, import_zod_utils.isZodSchema)(parameters) && !(typeof parameters === "object")) {
    throw new Error("Tool parameters must be a Zod object schema or a raw JSON schema");
  }
  if (onDuplicate === "confirm") {
    parameters = injectConfirmDuplicateParameter(parameters);
  }
  const execute = onDuplicate === "confirm" ? wrapConfirmDuplicateExecute(tool2.execute) : tool2.execute;
  const functionTool = {
    type: "function",
    description: tool2.description,
    parameters,
    execute,
    flags: tool2.flags ?? ToolFlag.NONE,
    onDuplicate,
    [TOOL_SYMBOL]: true,
    [FUNCTION_TOOL_SYMBOL]: true
  };
  if (tool2.name === void 0) {
    return functionTool;
  }
  return {
    ...functionTool,
    id: tool2.name,
    name: tool2.name
  };
}
function injectConfirmDuplicateParameter(parameters) {
  if ((0, import_zod_utils.isZodSchema)(parameters)) {
    const maybeObjectSchema = parameters;
    if (typeof maybeObjectSchema.extend === "function") {
      const confirmSchema = (0, import_zod_utils.isZod4Schema)(parameters) ? z4.boolean().nullable().describe(CONFIRM_DUPLICATE_DESCRIPTION) : import_zod.z.boolean().nullable().describe(CONFIRM_DUPLICATE_DESCRIPTION);
      return maybeObjectSchema.extend({ [CONFIRM_DUPLICATE_PARAM]: confirmSchema });
    }
    throw new Error("Tool parameters must be a Zod object schema (z.object(...))");
  }
  const properties = {
    ...parameters.properties ?? {},
    [CONFIRM_DUPLICATE_PARAM]: {
      type: ["boolean", "null"],
      description: CONFIRM_DUPLICATE_DESCRIPTION
    }
  };
  const required = [...parameters.required ?? []];
  if (!required.includes(CONFIRM_DUPLICATE_PARAM)) {
    required.push(CONFIRM_DUPLICATE_PARAM);
  }
  return {
    ...parameters,
    properties,
    required
  };
}
function wrapConfirmDuplicateExecute(execute) {
  return async (args, opts) => {
    if (args && typeof args === "object" && !Array.isArray(args)) {
      const stripped = { ...args };
      delete stripped[CONFIRM_DUPLICATE_PARAM];
      return execute(stripped, opts);
    }
    return execute(args, opts);
  };
}
function isTool(tool2) {
  return !!tool2 && tool2[TOOL_SYMBOL] === true;
}
function isFunctionTool(tool2) {
  const maybeTool = tool2;
  return isAnonFunctionTool(tool2) && typeof maybeTool.id === "string" && typeof maybeTool.name === "string";
}
function isAnonFunctionTool(tool2) {
  const maybeTool = tool2;
  return isTool(tool2) && maybeTool[FUNCTION_TOOL_SYMBOL] === true;
}
function isProviderTool(tool2) {
  return isTool(tool2) && tool2[PROVIDER_TOOL_SYMBOL] === true;
}
function isToolset(value) {
  return !!value && value[TOOLSET_SYMBOL] === true;
}
function isToolError(error) {
  return !!error && error[TOOL_ERROR_SYMBOL] === true;
}
function isAgentHandoff(handoff2) {
  return !!handoff2 && handoff2[HANDOFF_SYMBOL] === true;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  CONFIRM_DUPLICATE_PARAM,
  ProviderTool,
  ToolContext,
  ToolError,
  ToolFlag,
  Toolset,
  handoff,
  isAgentHandoff,
  isFunctionTool,
  isProviderTool,
  isSameToolChoice,
  isTool,
  isToolError,
  isToolset,
  normalizeToolContextInit,
  sortedToolEntries,
  sortedToolNames,
  toToolContext,
  tool
});
//# sourceMappingURL=tool_context.cjs.map