import { z } from 'zod';
import { BaseBubble } from './base-bubble-class.js';
/**
 * Abstract base class for all tool bubbles that can be converted to LangGraph tools
 */
export class ToolBubble extends BaseBubble {
    type = 'tool';
    constructor(params, context, instanceId) {
        super(params, context, instanceId);
    }
    // Static method - returns LangChain tool with credentials injected
    // Creates a LangGraph compatible tool with specific configurations that will
    // be passed in to the tool bubble
    static toolAgent(credentials, config, context) {
        // In static context, 'this' refers to the constructor/class
        const ToolClass = this;
        const { schema, bubbleName, shortDescription } = ToolClass;
        if (!schema || !bubbleName || !shortDescription) {
            throw new Error(`${ToolClass.name} must define static schema, bubbleName, and shortDescription`);
        }
        // Remove credentials and config from schema for agent use
        // Handle both ZodObject and ZodDiscriminatedUnion schemas
        // For Gemini compatibility, convert discriminated unions to flat objects with enum
        let agentSchema;
        if (schema instanceof z.ZodDiscriminatedUnion) {
            // For discriminated unions, convert to a flat object for Gemini compatibility
            // Discriminated unions produce "const" in JSON Schema which Gemini doesn't support
            const discriminator = schema.discriminator;
            const options = schema.options;
            // Collect all discriminator values and merge all fields
            const discriminatorValues = [];
            const mergedShape = {};
            const descriptions = {};
            for (const option of options) {
                const shape = option.shape;
                // Extract discriminator literal value
                const discriminatorField = shape[discriminator];
                if (discriminatorField instanceof z.ZodLiteral) {
                    discriminatorValues.push(discriminatorField.value);
                }
                // Merge all other fields (make them optional since they're operation-specific)
                for (const [key, fieldSchema] of Object.entries(shape)) {
                    if (key === discriminator ||
                        key === 'credentials' ||
                        key === 'config')
                        continue;
                    if (!mergedShape[key]) {
                        // Make the field optional since it's only required for certain operations
                        const zodField = fieldSchema;
                        mergedShape[key] = zodField.isOptional()
                            ? zodField
                            : zodField.optional();
                        // Preserve description if available
                        if (zodField.description) {
                            descriptions[key] = zodField.description;
                        }
                    }
                }
            }
            // Build the flat schema with enum for discriminator
            const flatShape = {
                [discriminator]: z
                    .enum(discriminatorValues)
                    .describe(`Operation to perform. One of: ${discriminatorValues.join(', ')}`),
                ...mergedShape,
            };
            agentSchema = z.object(flatShape).passthrough();
        }
        else {
            // For regular ZodObject schemas
            let objectSchema = schema;
            if (objectSchema.shape?.credentials) {
                objectSchema = objectSchema.omit({ credentials: true });
            }
            if (objectSchema.shape?.config) {
                objectSchema = objectSchema.omit({ config: true });
            }
            agentSchema = objectSchema.passthrough();
        }
        return {
            name: bubbleName,
            description: shortDescription,
            schema: agentSchema,
            func: async (toolParams) => {
                // Create instance with credentials and config injected
                // Sometimes config should be dynamic and determined on each
                // tool invocation, rather than the start of agent run
                // In this case, we will replace the config (statically configured in the tool bubble)
                // with the runtime config
                const runtimeConfig = toolParams?.config;
                const enrichedParams = {
                    ...toolParams,
                    credentials,
                    config: runtimeConfig || config,
                };
                // 'this' in static context is the constructor
                const instance = new ToolClass(enrichedParams, context);
                // Use performAction directly to get raw result, not wrapped BubbleResult
                return instance.action();
            },
        };
    }
}
//# sourceMappingURL=tool-bubble-class.js.map