import { describe, expect, expectTypeOf, it } from "vitest";
import { z } from "zod";
import {
  ProviderTool,
  ToolContext,
  tool
} from "./tool_context.js";
describe("tool type inference", () => {
  it("should infer argument type from zod schema", () => {
    const toolType = tool({
      name: "test",
      description: "test",
      parameters: z.object({ number: z.number() }),
      execute: async () => "test"
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("should infer argument type for an anonymous (name-less) tool with a schema", () => {
    tool({
      description: "test",
      parameters: z.object({ number: z.number() }),
      execute: async (args) => {
        expectTypeOf(args).toEqualTypeOf();
        return `${args.number}`;
      }
    });
  });
  it("should infer empty args for an anonymous tool when parameters are omitted", () => {
    const toolType = tool({
      description: "test",
      execute: async (args) => {
        expectTypeOf(args).toEqualTypeOf();
        return "done";
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
    expectTypeOf(toolType).toMatchTypeOf();
  });
  it("should infer empty args for an anonymous tool when parameters are explicitly undefined", () => {
    const toolType = tool({
      description: "test",
      parameters: void 0,
      execute: async (args) => {
        expectTypeOf(args).toEqualTypeOf();
        return "done";
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("should infer args from an explicit empty object schema on anonymous tools", () => {
    const parameters = z.object({});
    const toolType = tool({
      description: "test",
      parameters,
      execute: async (args) => {
        expectTypeOf(args).toMatchTypeOf();
        expectTypeOf(args).toEqualTypeOf();
        return "done";
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("should infer args from populated object schemas on anonymous tools", () => {
    const parameters = z.object({
      location: z.string(),
      units: z.enum(["celsius", "fahrenheit"]).optional()
    });
    const toolType = tool({
      description: "test",
      parameters,
      execute: async (args) => {
        expectTypeOf(args).toEqualTypeOf();
        expectTypeOf(args.location).toEqualTypeOf();
        expectTypeOf(args.units).toEqualTypeOf();
        return { location: args.location, ok: true };
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("rejects direct instantiation of the abstract ProviderTool base", () => {
    new ProviderTool({ id: "code-interpreter" });
    class CodeInterpreter extends ProviderTool {
    }
    const providerTool = new CodeInterpreter({ id: "code-interpreter" });
    expectTypeOf(providerTool).toMatchTypeOf();
    expect(providerTool.id).toBe("code-interpreter");
    expect(providerTool.type).toBe("provider");
  });
  it("should infer run context type", () => {
    const toolType = tool({
      name: "test",
      description: "test",
      parameters: z.object({ number: z.number() }),
      execute: async ({ number }, { ctx }) => {
        return `The number is ${number}, ${ctx.userData.name}`;
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("should not accept primitive zod schemas", () => {
    expect(() => {
      tool({
        name: "test",
        description: "test",
        parameters: z.string(),
        execute: async () => "test"
      });
    }).toThrowError("Tool parameters must be a Zod object schema (z.object(...))");
  });
  it("should not accept array schemas", () => {
    expect(() => {
      tool({
        name: "test",
        description: "test",
        parameters: z.array(z.string()),
        execute: async () => "test"
      });
    }).toThrowError("Tool parameters must be a Zod object schema (z.object(...))");
  });
  it("should not accept union schemas", () => {
    expect(() => {
      tool({
        name: "test",
        description: "test",
        parameters: z.union([z.object({ a: z.string() }), z.object({ b: z.number() })]),
        execute: async () => "test"
      });
    }).toThrowError("Tool parameters must be a Zod object schema (z.object(...))");
  });
  it("should not accept non-Zod values as parameters", () => {
    expect(() => {
      tool({
        name: "test",
        description: "test",
        // @ts-expect-error - Testing that non-Zod values are rejected
        parameters: "invalid schema",
        execute: async () => "test"
      });
    }).toThrowError("Tool parameters must be a Zod object schema or a raw JSON schema");
  });
  it("should infer empty object type when parameters are omitted", () => {
    const toolType = tool({
      name: "simpleAction",
      description: "Simple action without parameters",
      execute: async () => "done"
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
  it("names tool context input shapes by role", () => {
    const objectTools = {
      lookupOrder: tool({
        description: "Look up an order",
        execute: async () => "done"
      })
    };
    const namedTool = tool({
      name: "simpleAction",
      description: "Simple action",
      execute: async () => "done"
    });
    expectTypeOf(objectTools).toMatchTypeOf();
    expectTypeOf(objectTools).toMatchTypeOf();
    expectTypeOf([namedTool]).toMatchTypeOf();
    expectTypeOf(new ToolContext(objectTools)).toMatchTypeOf();
    expectTypeOf(namedTool).toMatchTypeOf();
  });
  it("should infer correct types with context but no parameters", () => {
    const toolType = tool({
      name: "actionWithCtx",
      description: "Action with context",
      execute: async (args, { ctx }) => {
        expectTypeOf(args).toEqualTypeOf();
        expectTypeOf(ctx.userData.userId).toEqualTypeOf();
        return ctx.userData.userId;
      }
    });
    expectTypeOf(toolType).toEqualTypeOf();
  });
});
//# sourceMappingURL=tool_context.type.test.js.map