var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, ID, Int } from 'type-graphql';
import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
import { AgentRunner } from '@memberjunction/ai-agents';
import { ConversationUtility } from '@memberjunction/ai-core-plus';
import { AIEngine } from '@memberjunction/aiengine';
import { ResolverBase } from '../generic/ResolverBase.js';
import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
import { GetReadWriteProvider } from '../util.js';
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
import { getAttachmentService } from '@memberjunction/aiengine';
import { NotificationEngine } from '@memberjunction/notifications';
let AIAgentRunResult = class AIAgentRunResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], AIAgentRunResult.prototype, "success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AIAgentRunResult.prototype, "errorMessage", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], AIAgentRunResult.prototype, "executionTimeMs", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], AIAgentRunResult.prototype, "result", void 0);
AIAgentRunResult = __decorate([
    ObjectType()
], AIAgentRunResult);
export { AIAgentRunResult };
let AgentExecutionProgress = class AgentExecutionProgress {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionProgress.prototype, "currentStep", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], AgentExecutionProgress.prototype, "percentage", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionProgress.prototype, "message", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionProgress.prototype, "agentName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionProgress.prototype, "agentType", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], AgentExecutionProgress.prototype, "stepCount", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionProgress.prototype, "hierarchicalStep", void 0);
AgentExecutionProgress = __decorate([
    ObjectType()
], AgentExecutionProgress);
export { AgentExecutionProgress };
let AgentStreamingContent = class AgentStreamingContent {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentStreamingContent.prototype, "content", void 0);
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], AgentStreamingContent.prototype, "isPartial", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentStreamingContent.prototype, "stepName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentStreamingContent.prototype, "agentName", void 0);
AgentStreamingContent = __decorate([
    ObjectType()
], AgentStreamingContent);
export { AgentStreamingContent };
let AgentExecutionStepSummary = class AgentExecutionStepSummary {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "stepId", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "stepName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "agentName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "agentType", void 0);
__decorate([
    Field(),
    __metadata("design:type", Date)
], AgentExecutionStepSummary.prototype, "startTime", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], AgentExecutionStepSummary.prototype, "endTime", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "status", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentExecutionStepSummary.prototype, "result", void 0);
AgentExecutionStepSummary = __decorate([
    ObjectType()
], AgentExecutionStepSummary);
export { AgentExecutionStepSummary };
let AgentPartialResult = class AgentPartialResult {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentPartialResult.prototype, "currentStep", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], AgentPartialResult.prototype, "partialOutput", void 0);
AgentPartialResult = __decorate([
    ObjectType()
], AgentPartialResult);
export { AgentPartialResult };
let AgentExecutionStreamMessage = class AgentExecutionStreamMessage {
};
__decorate([
    Field(() => ID),
    __metadata("design:type", String)
], AgentExecutionStreamMessage.prototype, "sessionId", void 0);
__decorate([
    Field(() => ID),
    __metadata("design:type", String)
], AgentExecutionStreamMessage.prototype, "agentRunId", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], AgentExecutionStreamMessage.prototype, "type", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", AgentExecutionProgress)
], AgentExecutionStreamMessage.prototype, "progress", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", AgentStreamingContent)
], AgentExecutionStreamMessage.prototype, "streaming", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", AgentPartialResult)
], AgentExecutionStreamMessage.prototype, "partialResult", void 0);
__decorate([
    Field(),
    __metadata("design:type", Date)
], AgentExecutionStreamMessage.prototype, "timestamp", void 0);
AgentExecutionStreamMessage = __decorate([
    ObjectType()
], AgentExecutionStreamMessage);
export { AgentExecutionStreamMessage };
let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
    /**
     * Sanitize ExecuteAgentResult for JSON serialization
     * Removes circular references and non-serializable objects
     */
    sanitizeAgentResult(result) {
        const sanitized = {
            success: result.success,
            payload: result.payload,
            responseForm: result.responseForm,
            actionableCommands: result.actionableCommands,
            automaticCommands: result.automaticCommands,
            errorMessage: result.agentRun?.ErrorMessage,
            finalStep: result.agentRun?.FinalStep,
            cancelled: result.agentRun?.Status === 'Cancelled',
            cancellationReason: result.agentRun?.CancellationReason
        };
        // Safely extract agent run data using GetAll() for proper serialization
        if (result.agentRun && typeof result.agentRun.GetAll === 'function') {
            // Use GetAll() to get the full serialized object including extended properties
            sanitized.agentRun = result.agentRun.GetAll();
        }
        else {
            // shouldn't ever get here
            console.error('❌ Unexpected agent run structure:', result.agentRun);
        }
        return sanitized;
    }
    /**
     * Parse and validate JSON input
     */
    parseJsonInput(jsonString, fieldName) {
        if (!jsonString)
            return {};
        try {
            return JSON.parse(jsonString);
        }
        catch (parseError) {
            throw new Error(`Invalid JSON in ${fieldName}: ${parseError.message}`);
        }
    }
    /**
     * Extract the user message from the messages array
     * Looks for the last user message in the conversation
     */
    extractUserMessage(messages) {
        if (!Array.isArray(messages) || messages.length === 0) {
            return undefined;
        }
        // Find the last user message in the array
        for (let i = messages.length - 1; i >= 0; i--) {
            const msg = messages[i];
            if (msg && msg.role === 'user' && msg.content) {
                return msg.content;
            }
        }
        return undefined;
    }
    /**
     * Validate the agent entity
     */
    async validateAgent(agentId, currentUser) {
        // Use AIEngine to get cached agent data
        await AIEngine.Instance.Config(false, currentUser);
        // Find agent in cached collection
        const agentEntity = AIEngine.Instance.GetAgentByID(agentId);
        if (!agentEntity) {
            throw new Error(`AI Agent with ID ${agentId} not found`);
        }
        // Check if agent is active
        if (agentEntity.Status !== 'Active') {
            throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
        }
        return agentEntity;
    }
    /**
     * Create streaming progress callback
     */
    createProgressCallback(pubSub, sessionId, userPayload, agentRunRef) {
        return (progress) => {
            // Only publish progress for significant steps (not initialization noise)
            const significantSteps = ['prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing'];
            if (!significantSteps.includes(progress.step)) {
                console.log(`🔇 Skipping noise progress: ${progress.step}`);
                return;
            }
            // Get the agent run from the progress metadata or use the ref
            const agentRun = progress.metadata?.agentRun || agentRunRef.current;
            if (!agentRun) {
                console.error('❌ No agent run available for progress callback');
                return;
            }
            console.log('📡 Publishing progress update:', {
                step: progress.step,
                percentage: progress.percentage,
                message: progress.message,
                sessionId,
                agentRunId: agentRun.ID
            });
            // Publish progress updates with the full serialized agent run
            const progressMsg = {
                sessionId,
                agentRunId: agentRun.ID,
                type: 'progress',
                agentRun: agentRun.GetAll(), // Serialize the full agent run
                progress: {
                    currentStep: progress.step,
                    percentage: progress.percentage,
                    message: progress.message,
                    agentName: progress.metadata?.agentName || undefined,
                    agentType: progress.metadata?.agentType || undefined,
                    stepCount: progress.metadata?.stepCount || undefined,
                    hierarchicalStep: progress.metadata?.hierarchicalStep || undefined
                },
                timestamp: new Date()
            };
            this.PublishProgressUpdate(pubSub, progressMsg, userPayload);
        };
    }
    PublishProgressUpdate(pubSub, data, userPayload) {
        pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
            message: JSON.stringify({
                resolver: 'RunAIAgentResolver',
                type: 'ExecutionProgress',
                status: 'ok',
                data,
            }),
            sessionId: userPayload.sessionId,
        });
    }
    PublishStreamingUpdate(pubSub, data, userPayload) {
        pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
            message: JSON.stringify({
                resolver: 'RunAIAgentResolver',
                type: 'StreamingContent',
                status: 'ok',
                data,
            }),
            sessionId: userPayload.sessionId,
        });
    }
    /**
     * Create streaming content callback
     */
    createStreamingCallback(pubSub, sessionId, userPayload, agentRunRef) {
        return (chunk) => {
            // Use the agent run from the ref
            const agentRun = agentRunRef.current;
            if (!agentRun) {
                console.error('❌ No agent run available for streaming callback');
                return;
            }
            console.log('💬 Publishing streaming content:', {
                content: chunk.content.substring(0, 50) + '...',
                isComplete: chunk.isComplete,
                stepType: chunk.stepType,
                sessionId,
                agentRunId: agentRun.ID
            });
            // Publish streaming content with the full serialized agent run
            const streamMsg = {
                sessionId,
                agentRunId: agentRun.ID,
                type: 'streaming',
                agentRun: agentRun.GetAll(), // Include the full serialized agent run
                streaming: {
                    content: chunk.content,
                    isPartial: !chunk.isComplete,
                    stepName: chunk.stepType,
                    agentName: chunk.modelName
                },
                timestamp: new Date()
            };
            this.PublishStreamingUpdate(pubSub, streamMsg, userPayload);
        };
    }
    /**
     * Internal method that handles the core AI agent execution logic.
     * This method is called by both the regular and system user resolvers.
     * @private
     */
    async executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId) {
        const startTime = Date.now();
        try {
            LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
            // Parse and validate messages
            const parsedMessages = this.parseJsonInput(messagesJson, 'messages');
            if (!Array.isArray(parsedMessages)) {
                throw new Error('Messages must be an array');
            }
            // Extract user message from messages array (needed when conversationDetailId not provided)
            const userMessage = this.extractUserMessage(parsedMessages);
            // Parse data contexts
            const parsedData = this.parseJsonInput(data, 'data');
            const parsedTemplateData = this.parseJsonInput(templateData, 'templateData');
            // Get and validate current user
            const currentUser = this.GetUserFromPayload(userPayload);
            if (!currentUser) {
                throw new Error('Unable to determine current user');
            }
            // Validate agent
            const agentEntity = await this.validateAgent(agentId, currentUser);
            // @jordanfanapour IMPORTANT TO-DO for various engine classes (via base engine class) and here for AI Agent Runner and for AI Prompt Runner, need to be able to pass in a IMetadataProvider for it to use
            // for multi-user server environments like this one
            // Create AI agent runner
            const agentRunner = new AgentRunner();
            // Track agent run for streaming (use ref to update later)
            const agentRunRef = { current: null };
            console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
            // Execute the agent in conversation context - handles conversation, artifacts, etc.
            const conversationResult = await agentRunner.RunAgentInConversation({
                agent: agentEntity,
                conversationMessages: parsedMessages,
                payload: payload ? SafeJSONParse(payload) : undefined,
                contextUser: currentUser,
                onProgress: this.createProgressCallback(pubSub, sessionId, userPayload, agentRunRef),
                onStreaming: this.createStreamingCallback(pubSub, sessionId, userPayload, agentRunRef),
                lastRunId: lastRunId,
                autoPopulateLastRunPayload: autoPopulateLastRunPayload,
                configurationId: configurationId,
                data: parsedData,
                context: {
                    dataSource: dataSource
                }
            }, {
                conversationDetailId: conversationDetailId, // Use existing if provided
                userMessage: userMessage, // Provide user message when conversationDetailId not provided
                createArtifacts: createArtifacts || false,
                sourceArtifactId: sourceArtifactId
            });
            const result = conversationResult.agentResult;
            // Use agent response detail ID if available, otherwise fall back to user message detail ID
            const finalConversationDetailId = conversationResult.agentResponseDetailId || conversationResult.userMessageDetailId;
            const artifactInfo = conversationResult.artifactInfo;
            // Update agent run ref once available
            if (result.agentRun) {
                agentRunRef.current = result.agentRun;
            }
            const executionTime = Date.now() - startTime;
            // Create notification if enabled and artifact was created successfully
            if (createNotification && result.success && artifactInfo && artifactInfo.artifactId && artifactInfo.versionId && artifactInfo.versionNumber) {
                await this.createCompletionNotification(result.agentRun, {
                    artifactId: artifactInfo.artifactId,
                    versionId: artifactInfo.versionId,
                    versionNumber: artifactInfo.versionNumber
                }, finalConversationDetailId, currentUser, pubSub, userPayload);
            }
            // Create sanitized payload for JSON serialization
            const sanitizedResult = this.sanitizeAgentResult(result);
            const returnResult = JSON.stringify(sanitizedResult);
            // Publish final events with enriched result data for fire-and-forget clients
            this.publishFinalEvents(pubSub, sessionId, userPayload, result, returnResult);
            // Log completion
            if (result.success) {
                LogStatus(`=== AI AGENT RUN COMPLETED FOR: ${agentEntity.Name} (${executionTime}ms) ===`);
            }
            else {
                LogError(`AI Agent run failed for ${agentEntity.Name}: ${result.agentRun?.ErrorMessage}`);
            }
            return {
                success: result.success,
                errorMessage: result.agentRun?.ErrorMessage || undefined,
                executionTimeMs: executionTime,
                result: returnResult
            };
        }
        catch (error) {
            const executionTime = Date.now() - startTime;
            LogError(`AI Agent run failed:`, undefined, error);
            // Create error payload
            const errorResult = {
                success: false,
                errorMessage: error.message || 'Unknown error occurred',
                executionTimeMs: executionTime
            };
            return {
                success: false,
                errorMessage: errorResult.errorMessage,
                executionTimeMs: executionTime,
                result: JSON.stringify(errorResult)
            };
        }
    }
    /**
     * Publish final streaming events (partial result and completion).
     * The completion event includes the full result JSON so clients using
     * fire-and-forget mode can receive the result via WebSocket.
     */
    publishFinalEvents(pubSub, sessionId, userPayload, result, resultJson) {
        if (result.agentRun) {
            // Get the last step from agent run
            let lastStep = 'Completed';
            if (result.agentRun?.Steps && result.agentRun.Steps.length > 0) {
                // Get the last step from the Steps array
                const lastStepEntity = result.agentRun.Steps[result.agentRun.Steps.length - 1];
                lastStep = lastStepEntity?.StepName || 'Completed';
            }
            // Publish partial result
            const partialResult = {
                currentStep: lastStep,
                partialOutput: result.payload || undefined
            };
            const partialMsg = {
                sessionId,
                agentRunId: result.agentRun.ID,
                type: 'partial_result',
                partialResult,
                timestamp: new Date()
            };
            this.PublishStreamingUpdate(pubSub, partialMsg, userPayload);
        }
        // Publish completion with conversationDetailId for client-side routing.
        // Include result data so fire-and-forget clients can receive the full result via WebSocket.
        const completionData = {
            sessionId,
            agentRunId: result.agentRun?.ID || 'unknown',
            type: 'complete',
            timestamp: new Date(),
            conversationDetailId: result.agentRun?.ConversationDetailID,
            success: result.success,
            errorMessage: result.agentRun?.ErrorMessage || undefined,
            result: resultJson || undefined
        };
        this.PublishStreamingUpdate(pubSub, completionData, userPayload);
    }
    /**
     * Public mutation for regular users to run AI agents with authentication.
     * Supports fire-and-forget mode to avoid Azure proxy timeouts on long-running agent executions.
     */
    async RunAIAgent(agentId, { userPayload, providers, dataSource }, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId, fireAndForget) {
        // Check API key scope authorization for agent execution
        await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
        const p = GetReadWriteProvider(providers);
        if (fireAndForget) {
            // Fire-and-forget mode: start execution in background, return immediately.
            // The client will receive the result via WebSocket PubSub completion event.
            this.executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
            LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
            return {
                success: true,
                result: JSON.stringify({ accepted: true, fireAndForget: true })
            };
        }
        // Synchronous mode (default): wait for execution to complete
        return this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
    }
    /**
     * System user query for running AI agents with elevated privileges.
     * Requires the @RequireSystemUser decorator to ensure only system users can access.
     */
    async RunAIAgentSystemUser(agentId, { userPayload, providers, dataSource }, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId) {
        const p = GetReadWriteProvider(providers);
        return this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
    }
    /**
     * Create a user notification for agent completion with artifact
     * Notification includes navigation link back to the conversation
     */
    async createCompletionNotification(agentRun, artifactInfo, conversationDetailId, contextUser, pubSub, userPayload) {
        try {
            const md = new Metadata();
            // Get agent info for notification message
            await AIEngine.Instance.Config(false, contextUser);
            const agent = AIEngine.Instance.Agents.find(a => UUIDsEqual(a.ID, agentRun.AgentID));
            const agentName = agent?.Name || 'Agent';
            // Load conversation detail to get conversation info
            const detail = await md.GetEntityObject('MJ: Conversation Details', contextUser);
            if (!(await detail.Load(conversationDetailId))) {
                throw new Error(`Failed to load conversation detail ${conversationDetailId}`);
            }
            // Build conversation URL for email/SMS templates
            const baseUrl = process.env.APP_BASE_URL || 'http://localhost:4201';
            const conversationUrl = `${baseUrl}/conversations/${detail.ConversationID}?artifact=${artifactInfo.artifactId}`;
            // Craft message based on versioning
            const message = artifactInfo.versionNumber > 1
                ? `${agentName} has finished processing and created version ${artifactInfo.versionNumber}`
                : `${agentName} has finished processing and created a new artifact`;
            // Use unified notification engine (Config called to ensure loaded)
            const notificationEngine = NotificationEngine.Instance;
            await notificationEngine.Config(false, contextUser);
            const result = await notificationEngine.SendNotification({
                userId: contextUser.ID,
                typeNameOrId: 'Agent Completion',
                title: `${agentName} completed your request`,
                message: message,
                resourceConfiguration: {
                    type: 'conversation',
                    conversationId: detail.ConversationID,
                    messageId: conversationDetailId,
                    artifactId: artifactInfo.artifactId,
                    versionId: artifactInfo.versionId,
                    versionNumber: artifactInfo.versionNumber
                },
                templateData: {
                    agentName: agentName,
                    artifactTitle: artifactInfo.artifactId,
                    conversationUrl: conversationUrl,
                    versionNumber: artifactInfo.versionNumber > 1 ? artifactInfo.versionNumber : undefined
                }
            }, contextUser);
            if (result.success && result.inAppNotificationId) {
                const channels = [];
                if (result.deliveryChannels.inApp)
                    channels.push('InApp');
                if (result.deliveryChannels.email)
                    channels.push('Email');
                if (result.deliveryChannels.sms)
                    channels.push('SMS');
                const channelList = channels.length > 0 ? channels.join(', ') : 'None';
                LogStatus(`📬 Notification sent via ${channelList} (ID: ${result.inAppNotificationId})`);
                // Publish real-time notification event so client updates immediately
                pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
                    userPayload: JSON.stringify(userPayload),
                    message: JSON.stringify({
                        type: 'notification',
                        notificationId: result.inAppNotificationId,
                        action: 'create',
                        title: `${agentName} completed your request`,
                        message: message
                    })
                });
                LogStatus(`📡 Published notification event to client`);
            }
            else if (!result.success) {
                LogError(`Notification failed: ${result.errors?.join(', ')}`);
            }
        }
        catch (error) {
            LogError(`Failed to create completion notification: ${error.message}`);
            // Don't throw - notification failure shouldn't fail the agent run
        }
    }
    /**
     * Optimized mutation that loads conversation history server-side.
     * This avoids sending large attachment data from client to server.
     *
     * @param conversationDetailId - The conversation detail ID (user's message already saved)
     * @param agentId - The agent to execute
     * @param maxHistoryMessages - Maximum number of history messages to include (default: 20)
     */
    async RunAIAgentFromConversationDetail(conversationDetailId, agentId, { userPayload, providers, dataSource }, sessionId, pubSub, maxHistoryMessages, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId, fireAndForget) {
        // Check API key scope authorization for agent execution
        await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
        const p = GetReadWriteProvider(providers);
        const currentUser = this.GetUserFromPayload(userPayload);
        if (!currentUser) {
            return {
                success: false,
                errorMessage: 'Unable to determine current user',
                result: JSON.stringify({ success: false, errorMessage: 'Unable to determine current user' })
            };
        }
        try {
            // Load conversation history with attachments from DB
            const messages = await this.loadConversationHistoryWithAttachments(conversationDetailId, currentUser, maxHistoryMessages || 20);
            // Convert to JSON string for the existing executeAIAgent method
            const messagesJson = JSON.stringify(messages);
            if (fireAndForget) {
                // Fire-and-forget mode: start execution in background, return immediately.
                // The client will receive the result via WebSocket PubSub completion event.
                this.executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
                LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
                return {
                    success: true,
                    result: JSON.stringify({ accepted: true, fireAndForget: true })
                };
            }
            // Synchronous mode (default): wait for execution to complete
            return this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, undefined, // templateData
            lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
        }
        catch (error) {
            const errorMessage = error.message || 'Unknown error loading conversation history';
            LogError(`RunAIAgentFromConversationDetail failed: ${errorMessage}`, undefined, error);
            return {
                success: false,
                errorMessage,
                result: JSON.stringify({ success: false, errorMessage })
            };
        }
    }
    /**
     * Execute agent in background (fire-and-forget).
     * Handles errors by publishing error completion events via PubSub,
     * so the client receives them via WebSocket even though the HTTP response
     * has already been sent.
     */
    executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId) {
        // Execute in background - errors are handled within, not propagated
        this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, undefined, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId).catch((error) => {
            // Background execution failed unexpectedly (executeAIAgent has its own try-catch,
            // so this would only fire for truly unexpected errors).
            const errorMessage = (error instanceof Error) ? error.message : 'Unknown background execution error';
            LogError(`🔥 Fire-and-forget background execution failed: ${errorMessage}`, undefined, error);
            // Publish error completion event so the client knows the agent failed
            const errorCompletionData = {
                sessionId,
                agentRunId: 'unknown',
                type: 'complete',
                timestamp: new Date(),
                conversationDetailId,
                success: false,
                errorMessage,
                result: JSON.stringify({ success: false, errorMessage })
            };
            this.PublishStreamingUpdate(pubSub, errorCompletionData, userPayload);
        });
    }
    /**
     * Load conversation history with attachments from database.
     * Builds ChatMessage[] with multimodal content blocks for attachments.
     */
    async loadConversationHistoryWithAttachments(conversationDetailId, contextUser, maxMessages) {
        const md = new Metadata();
        const rv = new RunView();
        const attachmentService = getAttachmentService();
        // Load the current conversation detail to get the conversation ID
        const currentDetail = await md.GetEntityObject('MJ: Conversation Details', contextUser);
        if (!await currentDetail.Load(conversationDetailId)) {
            throw new Error(`Conversation detail ${conversationDetailId} not found`);
        }
        const conversationId = currentDetail.ConversationID;
        // Load recent conversation details (messages) for this conversation
        const detailsResult = await rv.RunView({
            EntityName: 'MJ: Conversation Details',
            ExtraFilter: `ConversationID='${conversationId}'`,
            OrderBy: '__mj_CreatedAt DESC',
            MaxRows: maxMessages,
            ResultType: 'entity_object'
        }, contextUser);
        if (!detailsResult.Success || !detailsResult.Results) {
            throw new Error('Failed to load conversation history');
        }
        // Reverse to get chronological order (oldest first)
        const details = detailsResult.Results.reverse();
        // Get all message IDs for batch loading attachments
        const messageIds = details.map(d => d.ID);
        // Batch load all attachments for these messages
        const attachmentsByDetailId = await attachmentService.getAttachmentsBatch(messageIds, contextUser);
        // Build ChatMessage array with attachments
        const messages = [];
        for (const detail of details) {
            const role = this.mapDetailRoleToMessageRole(detail.Role);
            const attachments = attachmentsByDetailId.get(detail.ID) || [];
            // Get attachment data with content URLs (handles both inline and FileID storage)
            const attachmentDataPromises = attachments.map(att => attachmentService.getAttachmentData(att, contextUser));
            const attachmentDataResults = await Promise.all(attachmentDataPromises);
            // Filter out nulls and convert to AttachmentData format
            const validAttachments = attachmentDataResults
                .filter((result) => result !== null)
                .map(result => ({
                type: ConversationUtility.GetAttachmentTypeFromMime(result.attachment.MimeType),
                mimeType: result.attachment.MimeType,
                fileName: result.attachment.FileName ?? undefined,
                sizeBytes: result.attachment.FileSizeBytes ?? undefined,
                width: result.attachment.Width ?? undefined,
                height: result.attachment.Height ?? undefined,
                durationSeconds: result.attachment.DurationSeconds ?? undefined,
                content: result.contentUrl
            }));
            // Build message content (with or without attachments)
            let content;
            if (validAttachments.length > 0) {
                // Use ConversationUtility to build multimodal content blocks
                content = ConversationUtility.BuildChatMessageContent(detail.Message || '', validAttachments);
            }
            else {
                content = detail.Message || '';
            }
            messages.push({
                role,
                content
            });
        }
        return messages;
    }
    /**
     * Map ConversationDetail Role to ChatMessage role
     */
    mapDetailRoleToMessageRole(role) {
        const roleLower = (role || '').toLowerCase();
        if (roleLower === 'user')
            return 'user';
        if (roleLower === 'assistant' || roleLower === 'agent' || roleLower === 'ai')
            return 'assistant';
        if (roleLower === 'system')
            return 'system';
        return 'user'; // Default to user
    }
};
__decorate([
    Mutation(() => AIAgentRunResult),
    __param(0, Arg('agentId')),
    __param(1, Ctx()),
    __param(2, Arg('messages')),
    __param(3, Arg('sessionId')),
    __param(4, PubSub()),
    __param(5, Arg('data', { nullable: true })),
    __param(6, Arg('payload', { nullable: true })),
    __param(7, Arg('templateData', { nullable: true })),
    __param(8, Arg('lastRunId', { nullable: true })),
    __param(9, Arg('autoPopulateLastRunPayload', { nullable: true })),
    __param(10, Arg('configurationId', { nullable: true })),
    __param(11, Arg('conversationDetailId', { nullable: true })),
    __param(12, Arg('createArtifacts', { nullable: true })),
    __param(13, Arg('createNotification', { nullable: true })),
    __param(14, Arg('sourceArtifactId', { nullable: true })),
    __param(15, Arg('sourceArtifactVersionId', { nullable: true })),
    __param(16, Arg('fireAndForget', { nullable: true })),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object, String, String, PubSubEngine, String, String, String, String, Boolean, String, String, Boolean, Boolean, String, String, Boolean]),
    __metadata("design:returntype", Promise)
], RunAIAgentResolver.prototype, "RunAIAgent", null);
__decorate([
    RequireSystemUser(),
    Query(() => AIAgentRunResult),
    __param(0, Arg('agentId')),
    __param(1, Ctx()),
    __param(2, Arg('messages')),
    __param(3, Arg('sessionId')),
    __param(4, PubSub()),
    __param(5, Arg('data', { nullable: true })),
    __param(6, Arg('payload', { nullable: true })),
    __param(7, Arg('templateData', { nullable: true })),
    __param(8, Arg('lastRunId', { nullable: true })),
    __param(9, Arg('autoPopulateLastRunPayload', { nullable: true })),
    __param(10, Arg('configurationId', { nullable: true })),
    __param(11, Arg('conversationDetailId', { nullable: true })),
    __param(12, Arg('createArtifacts', { nullable: true })),
    __param(13, Arg('createNotification', { nullable: true })),
    __param(14, Arg('sourceArtifactId', { nullable: true })),
    __param(15, Arg('sourceArtifactVersionId', { nullable: true })),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object, String, String, PubSubEngine, String, String, String, String, Boolean, String, String, Boolean, Boolean, String, String]),
    __metadata("design:returntype", Promise)
], RunAIAgentResolver.prototype, "RunAIAgentSystemUser", null);
__decorate([
    Mutation(() => AIAgentRunResult),
    __param(0, Arg('conversationDetailId')),
    __param(1, Arg('agentId')),
    __param(2, Ctx()),
    __param(3, Arg('sessionId')),
    __param(4, PubSub()),
    __param(5, Arg('maxHistoryMessages', () => Int, { nullable: true })),
    __param(6, Arg('data', { nullable: true })),
    __param(7, Arg('payload', { nullable: true })),
    __param(8, Arg('lastRunId', { nullable: true })),
    __param(9, Arg('autoPopulateLastRunPayload', { nullable: true })),
    __param(10, Arg('configurationId', { nullable: true })),
    __param(11, Arg('createArtifacts', { nullable: true })),
    __param(12, Arg('createNotification', { nullable: true })),
    __param(13, Arg('sourceArtifactId', { nullable: true })),
    __param(14, Arg('sourceArtifactVersionId', { nullable: true })),
    __param(15, Arg('fireAndForget', { nullable: true })),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String, Object, String, PubSubEngine, Number, String, String, String, Boolean, String, Boolean, Boolean, String, String, Boolean]),
    __metadata("design:returntype", Promise)
], RunAIAgentResolver.prototype, "RunAIAgentFromConversationDetail", null);
RunAIAgentResolver = __decorate([
    Resolver()
], RunAIAgentResolver);
export { RunAIAgentResolver };
//# sourceMappingURL=RunAIAgentResolver.js.map