UNPKG

@learnlab/datashop-logger

Version:

TypeScript SDK for logging educational data to Carnegie Mellon's DataShop system

1 lines 48.2 kB
{"version":3,"sources":["../src/utils/SAIBuilder.ts","../src/utils/LogMessageBuilder.ts","../src/utils/guid.ts","../src/errors/DataShopLoggerError.ts","../src/DataShopLogger.ts"],"sourcesContent":["import type { SAI } from '../types';\n\nexport class SAIBuilder {\n private selectionArray: string[] = [];\n private actionArray: string[] = [];\n private inputArray: string[] = [];\n\n constructor(selection?: string | string[], action?: string | string[], input?: string | string[]) {\n if (selection !== undefined) {\n this.setSelection(selection);\n }\n if (action !== undefined) {\n this.setAction(action);\n }\n if (input !== undefined) {\n this.setInput(input);\n }\n }\n\n setSelection(selection: string | string[]): SAIBuilder {\n this.selectionArray = Array.isArray(selection) ? [...selection] : [selection];\n return this;\n }\n\n setAction(action: string | string[]): SAIBuilder {\n this.actionArray = Array.isArray(action) ? [...action] : [action];\n return this;\n }\n\n setInput(input: string | string[]): SAIBuilder {\n this.inputArray = Array.isArray(input) ? [...input] : [input];\n return this;\n }\n\n build(): SAI {\n return {\n selection: this.selectionArray.length === 0 ? [] : this.selectionArray.length === 1 ? this.selectionArray[0]! : this.selectionArray,\n action: this.actionArray.length === 0 ? [] : this.actionArray.length === 1 ? this.actionArray[0]! : this.actionArray,\n input: this.inputArray.length === 0 ? [] : this.inputArray.length === 1 ? this.inputArray[0]! : this.inputArray,\n };\n }\n\n toXMLString(): string {\n let xml = '';\n\n for (const selection of this.selectionArray) {\n xml += `<selection>${this.escapeXML(selection)}</selection>`;\n }\n\n for (let i = 0; i < this.actionArray.length; i++) {\n if (i === 0) {\n xml += `<action>${this.escapeXML(this.actionArray[i]!)}`;\n } else {\n xml += `</action><action>${this.escapeXML(this.actionArray[i]!)}`;\n }\n }\n if (this.actionArray.length > 0) {\n xml += '</action>';\n }\n\n for (const input of this.inputArray) {\n xml += `<input><![CDATA[${input}]]></input>`;\n }\n\n return xml;\n }\n\n private escapeXML(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n }\n}","import type { LogConfiguration, SAI, ActionEvaluation } from '../types';\nimport { SAIBuilder } from './SAIBuilder';\n\nexport class LogMessageBuilder {\n private readonly xmlProlog = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>';\n private readonly DTDVersion = '4';\n private customFields: Map<string, string | number | boolean> = new Map();\n\n constructor(private configuration: LogConfiguration) {}\n\n resetCustomFields(): void {\n this.customFields.clear();\n }\n\n addCustomField(name: string, value: string | number | boolean): void {\n this.customFields.set(name, value);\n }\n\n addCustomFields(fields?: Record<string, unknown>): void {\n if (!fields) return;\n \n for (const [key, value] of Object.entries(fields)) {\n if (value !== undefined && value !== null) {\n this.addCustomField(key, String(value));\n }\n }\n }\n\n formatTimeStamp(date: Date): string {\n return date.toISOString().replace('T', ' ').replace('Z', '');\n }\n \n formatTimeStampOLI(date: Date): string {\n // OLI format: YYYY/MM/DD HH:MM:SS\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n const seconds = String(date.getUTCSeconds()).padStart(2, '0');\n \n return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;\n }\n\n createLogSessionStart(): string {\n const now = new Date();\n \n // log_session_start is a self-closing element with attributes\n let message = `${this.xmlProlog}<log_session_start `;\n message += `timezone=\"UTC\" `;\n message += `date_time=\"${this.formatTimeStampOLI(now)}\" `;\n message += `auth_token=\"${this.configuration.auth_token || ''}\" `;\n message += `session_id=\"${this.configuration.session_id || ''}\" `;\n message += `user_guid=\"${this.configuration.user_guid || ''}\" `;\n message += `class_id=\"\" treatment_id=\"\" assignment_id=\"\" info_type=\"tutor_message.dtd\"/>`;\n \n return message;\n }\n\n createContextMessage(): string {\n const vars = this.configuration;\n const now = new Date();\n \n let message = `<context_message context_message_id=\"${vars.context_message_id || ''}\" name=\"START_PROBLEM\">`;\n \n message += this.makeMetaElement(now);\n \n // Class element - always include it, even if empty\n if (vars.class_name) {\n message += '<class>';\n message += `<name>${this.escapeXML(vars.class_name)}</name>`;\n if (vars.school_name) message += `<school>${this.escapeXML(vars.school_name)}</school>`;\n if (vars.period_name) message += `<period>${this.escapeXML(vars.period_name)}</period>`;\n if (vars.class_description) message += `<description>${this.escapeXML(vars.class_description)}</description>`;\n if (vars.instructor_name) message += `<instructor>${this.escapeXML(vars.instructor_name)}</instructor>`;\n message += '</class>';\n }\n \n // Dataset element\n message += '<dataset>';\n message += `<name><![CDATA[${vars.dataset_name || 'UnassignedDataset'}]]></name>`;\n \n // Build nested dataset levels\n let levelContent = '';\n let levelsFound = 0;\n \n // Check for all dataset levels (1-10 should be enough)\n for (let i = 1; i <= 10; i++) {\n const levelNameKey = `dataset_level_name${i}`;\n const levelTypeKey = `dataset_level_type${i}`;\n const levelName = vars[levelNameKey];\n const levelType = vars[levelTypeKey];\n \n if (levelName && levelType) {\n levelsFound++;\n levelContent += `<level type=\"${this.escapeXML(String(levelType))}\">`;\n levelContent += `<name><![CDATA[${String(levelName)}]]></name>`;\n } else {\n break;\n }\n }\n \n // Add problem element at the deepest level\n if (levelsFound > 0) {\n levelContent += '<problem tutorFlag=\"tutor\">';\n levelContent += `<name><![CDATA[${vars.problem_name || ''}]]></name>`;\n if (vars.problem_context) {\n levelContent += `<context><![CDATA[${vars.problem_context}]]></context>`;\n }\n levelContent += '</problem>';\n \n // Close all level tags in reverse order\n for (let i = 0; i < levelsFound; i++) {\n levelContent += '</level>';\n }\n \n message += levelContent;\n } else {\n // If no dataset levels defined, add problem directly under dataset\n message += '<problem tutorFlag=\"tutor\">';\n message += `<name><![CDATA[${vars.problem_name || ''}]]></name>`;\n if (vars.problem_context) {\n message += `<context><![CDATA[${vars.problem_context}]]></context>`;\n }\n message += '</problem>';\n }\n \n message += '</dataset>';\n \n // Condition section (currently empty, but included for compatibility)\n // In the future, this could support condition configurations\n \n // Custom fields (currently empty for context messages)\n \n message += '</context_message>';\n \n return message;\n }\n\n createSemanticEventToolMessage(\n sai: SAI,\n transactionID: string,\n semanticEventName: string,\n semanticEventSubtype?: string,\n trigger?: string\n ): string {\n const saiBuilder = new SAIBuilder(sai.selection, sai.action, sai.input);\n \n let message = `<tool_message context_message_id=\"${this.configuration.context_message_id || ''}\">`;\n message += this.makeMetaElement(new Date());\n message += `<semantic_event transaction_id=\"${transactionID}\" name=\"${semanticEventName}\"`;\n if (semanticEventSubtype) {\n message += ` subtype=\"${semanticEventSubtype}\"`;\n }\n if (trigger) {\n message += ` trigger=\"${trigger}\"`;\n }\n message += '/>';\n message += `<event_descriptor>`;\n message += saiBuilder.toXMLString();\n message += `</event_descriptor>`;\n \n // Add custom fields (no wrapper, individual elements)\n for (const [name, value] of this.customFields) {\n message += `<custom_field><name>${this.escapeXML(name)}</name><value>${this.escapeXML(String(value))}</value></custom_field>`;\n }\n \n message += `</tool_message>`;\n \n return message;\n }\n\n createTutorMessage(\n sai: SAI,\n transactionID: string,\n semanticEventName: string,\n evaluation: ActionEvaluation,\n feedback: string,\n semanticEventSubtype?: string,\n skills?: Array<{ name: string; category?: string }>\n ): string {\n const saiBuilder = new SAIBuilder(sai.selection, sai.action, sai.input);\n \n let message = `<tutor_message context_message_id=\"${this.configuration.context_message_id || ''}\">`;\n message += this.makeMetaElement(new Date());\n message += `<semantic_event transaction_id=\"${transactionID}\" name=\"${semanticEventName}\"`;\n if (semanticEventSubtype) {\n message += ` subtype=\"${semanticEventSubtype}\"`;\n }\n message += '/>';\n message += `<event_descriptor>`;\n message += saiBuilder.toXMLString();\n message += `</event_descriptor>`;\n \n // Action evaluation\n message += '<action_evaluation';\n if (evaluation.classification) {\n message += ` classification=\"${evaluation.classification}\"`;\n }\n if (evaluation.currentHintNumber !== undefined) {\n message += ` current_hint_number=\"${evaluation.currentHintNumber}\"`;\n }\n if (evaluation.totalHintsAvailable !== undefined) {\n message += ` total_hints_available=\"${evaluation.totalHintsAvailable}\"`;\n }\n message += `>${evaluation.evaluation}</action_evaluation>`;\n \n // Tutor advice/feedback\n if (feedback) {\n message += `<tutor_advice>${feedback}</tutor_advice>`;\n }\n \n // Skills/Knowledge Components\n if (skills && skills.length > 0) {\n message += '<skills>';\n for (const skill of skills) {\n message += '<skill>';\n message += `<name>${this.escapeXML(skill.name)}</name>`;\n if (skill.category) {\n message += `<category>${this.escapeXML(skill.category)}</category>`;\n }\n message += '</skill>';\n }\n message += '</skills>';\n }\n \n // Add custom fields (no wrapper, individual elements)\n for (const [name, value] of this.customFields) {\n message += `<custom_field><name>${this.escapeXML(name)}</name><value>${this.escapeXML(String(value))}</value></custom_field>`;\n }\n \n message += `</tutor_message>`;\n \n return message;\n }\n\n wrapForDataShop(message: string): string {\n // log_session_start messages should already have the wrapper from createLogSessionStart\n if (message.includes('<log_session_start')) {\n return message;\n }\n return `${this.xmlProlog}<tutor_related_message_sequence version_number=\"${this.DTDVersion}\">${message}</tutor_related_message_sequence>`;\n }\n \n wrapForOLI(message: string): string {\n const now = new Date();\n const vars = this.configuration;\n \n // URL encode the inner message\n const encodedMessage = encodeURIComponent(message);\n \n let wrapper = `${this.xmlProlog}<log_action `;\n wrapper += `auth_token=\"${encodeURIComponent(vars.auth_token || '')}\" `;\n wrapper += `session_id=\"${vars.session_id || ''}\" `;\n wrapper += `action_id=\"EVALUATE_QUESTION\" `;\n wrapper += `user_guid=\"\" `; // leave blank if not log_session_start\n wrapper += `date_time=\"${this.formatTimeStampOLI(now)}\" `;\n wrapper += `timezone=\"UTC\" `;\n wrapper += `source_id=\"${vars.source_id || 'tutor'}\" `;\n wrapper += `external_object_id=\"${vars.activity_context_guid || ''}\" `;\n wrapper += `info_type=\"tutor_message.dtd\">`;\n wrapper += encodedMessage;\n wrapper += `</log_action>`;\n \n return wrapper;\n }\n\n private makeMetaElement(timestamp: Date): string {\n let meta = '<meta>';\n meta += `<user_id>${this.escapeXML(this.configuration.user_guid || '')}</user_id>`;\n meta += `<session_id>${this.escapeXML(this.configuration.session_id || '')}</session_id>`;\n meta += `<time>${this.formatTimeStamp(timestamp)} UTC</time>`;\n meta += `<time_zone>UTC</time_zone>`;\n meta += '</meta>';\n return meta;\n }\n\n private escapeXML(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n }\n}","export function generateGUID(): string {\n // Check for crypto.randomUUID in both global and globalThis contexts\n const cryptoObj = (typeof globalThis !== 'undefined' && globalThis.crypto) || \n (typeof global !== 'undefined' && global.crypto) ||\n (typeof window !== 'undefined' && window.crypto);\n \n if (cryptoObj && cryptoObj.randomUUID) {\n return cryptoObj.randomUUID();\n }\n \n // Fallback for environments without crypto.randomUUID\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function generateTransactionID(): string {\n return `T${generateGUID()}`;\n}\n\nexport function generateContextMessageID(): string {\n return `C${generateGUID()}`;\n}","export default class DataShopLoggerError extends Error {\n public readonly code: string;\n public readonly details?: unknown;\n\n constructor(message: string, code: string, details?: unknown) {\n super(message);\n this.name = 'DataShopLoggerError';\n this.code = code;\n this.details = details;\n \n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, DataShopLoggerError);\n }\n }\n}\n\nexport class ConfigurationError extends DataShopLoggerError {\n constructor(message: string, details?: unknown) {\n super(message, 'CONFIGURATION_ERROR', details);\n this.name = 'ConfigurationError';\n }\n}\n\nexport class NetworkError extends DataShopLoggerError {\n constructor(message: string, details?: unknown) {\n super(message, 'NETWORK_ERROR', details);\n this.name = 'NetworkError';\n }\n}\n\nexport class ValidationError extends DataShopLoggerError {\n constructor(message: string, details?: unknown) {\n super(message, 'VALIDATION_ERROR', details);\n this.name = 'ValidationError';\n }\n}","import type {\n IDataShopLogger,\n LogConfiguration,\n LoggingLibraryOptions,\n SAI,\n ActionEvaluation,\n Skill,\n LogAttemptParams,\n LogAttemptSAIParams,\n LogHintRequestParams,\n LogResponseParams,\n LogResponseSAIParams,\n LogHintResponseParams,\n ResetParams,\n SetLogFormatParams,\n SetLoggingURLParams,\n SetContextNameParams,\n SetContextMessageIDParams,\n SetUserIDParams,\n SetProblemNameParams,\n SetProblemContextParams,\n SetDatasetNameParams,\n SetSchoolParams,\n SetPeriodParams,\n SetInstructorParams,\n SetDescriptionParams,\n SetLogClassNameParams,\n SetDatasetLevelNameParams,\n SetDatasetLevelTypeParams,\n SetUseSessionLogParams,\n SetLogListenerParams,\n} from \"./types\";\nimport { LogMessageBuilder } from \"./utils/LogMessageBuilder\";\nimport {\n generateGUID,\n generateTransactionID,\n generateContextMessageID,\n} from \"./utils/guid\";\nimport { ConfigurationError, NetworkError } from \"./errors/DataShopLoggerError\";\n\nexport class DataShopLogger implements IDataShopLogger {\n private configuration: LogConfiguration;\n private logFormat: \"DATASHOP\" | \"XAPI\" = \"DATASHOP\";\n private useSessionLog: boolean = true;\n private lastTransactionID: string = \"\";\n private lastSAI: SAI | null = null;\n private messageBuilder: LogMessageBuilder;\n private logListener?: (message: string) => void;\n\n // Default values\n private readonly defaultConfiguration: Partial<LogConfiguration> = {\n dataset_name: \"UnassignedDataset\",\n source_id: \"tutor\",\n };\n\n constructor(options?: LoggingLibraryOptions) {\n this.configuration = {\n ...this.defaultConfiguration,\n ...options?.configuration,\n };\n\n if (options?.logFormat) {\n this.logFormat = options.logFormat;\n }\n\n if (options?.useSessionLog !== undefined) {\n this.useSessionLog = options.useSessionLog;\n }\n\n this.messageBuilder = new LogMessageBuilder(this.configuration);\n this.initializeSession();\n }\n\n private initializeSession(): void {\n if (!this.configuration.session_id) {\n this.configuration.session_id = `ctat_session_${generateGUID()}`;\n }\n\n if (!this.configuration.context_message_id) {\n this.configuration.context_message_id = generateContextMessageID();\n }\n\n if (!this.configuration.user_guid) {\n this.configuration.user_guid = generateGUID();\n }\n }\n\n start(): string {\n this.initializeSession();\n\n if (this.useSessionLog) {\n const sessionStartMessage = this.messageBuilder.createLogSessionStart();\n this.sendMessage(sessionStartMessage);\n }\n\n const contextMessage = this.messageBuilder.createContextMessage();\n this.sendMessage(contextMessage);\n\n return this.configuration.session_id!;\n }\n\n resume(sessionId: string): void {\n // Resume an existing session without sending log_session_start\n this.configuration.session_id = sessionId;\n \n // Only send context message when resuming\n const contextMessage = this.messageBuilder.createContextMessage();\n this.sendMessage(contextMessage);\n }\n\n // New object-based API\n reset(params: ResetParams): void;\n // Backward compatibility overload\n reset(configuration?: LogConfiguration): void;\n // Implementation\n reset(paramsOrConfig?: ResetParams | LogConfiguration): void {\n let config: LogConfiguration | undefined;\n\n // Check if using new object-based API\n if (\n paramsOrConfig &&\n typeof paramsOrConfig === \"object\" &&\n \"configuration\" in paramsOrConfig\n ) {\n config = (paramsOrConfig as ResetParams).configuration;\n }\n // Backward compatibility\n else {\n config = paramsOrConfig as LogConfiguration | undefined;\n }\n\n this.configuration = {\n ...this.defaultConfiguration,\n ...config,\n };\n this.messageBuilder = new LogMessageBuilder(this.configuration);\n this.initializeSession();\n }\n\n // New object-based API methods\n logInterfaceAttempt(params: LogAttemptParams): string;\n // Backward compatibility overload\n logInterfaceAttempt(\n selection: string | string[],\n action: string | string[],\n input: string | string[],\n customFields?: Record<string, unknown>\n ): string;\n // Implementation\n logInterfaceAttempt(\n paramsOrSelection: LogAttemptParams | string | string[],\n action?: string | string[],\n input?: string | string[],\n customFields?: Record<string, unknown>\n ): string {\n // Check if using new object-based API\n if (\n typeof paramsOrSelection === \"object\" &&\n !Array.isArray(paramsOrSelection) &&\n \"selection\" in paramsOrSelection\n ) {\n const params = paramsOrSelection;\n const sai: SAI = {\n selection: params.selection,\n action: params.action,\n input: params.input,\n };\n return this.logInterfaceAttemptSAI({\n sai,\n customFields: params.customFields,\n });\n }\n // Backward compatibility: old positional parameters\n else {\n const sai: SAI = {\n selection: paramsOrSelection,\n action: action!,\n input: input!,\n };\n return this.logInterfaceAttemptSAI({ sai, customFields });\n }\n }\n\n // New object-based API\n logInterfaceAttemptSAI(params: LogAttemptSAIParams): string;\n // Backward compatibility overload\n logInterfaceAttemptSAI(\n sai: SAI,\n customFields?: Record<string, unknown>\n ): string;\n // Implementation\n logInterfaceAttemptSAI(\n paramsOrSai: LogAttemptSAIParams | SAI,\n customFields?: Record<string, unknown>\n ): string {\n let sai: SAI;\n let fields: Record<string, unknown> | undefined;\n\n // Check if using new object-based API\n if (\"sai\" in paramsOrSai) {\n sai = paramsOrSai.sai;\n fields = paramsOrSai.customFields;\n }\n // Backward compatibility: old API\n else {\n sai = paramsOrSai;\n fields = customFields;\n }\n\n const transactionID = generateTransactionID();\n this.lastTransactionID = transactionID;\n this.lastSAI = sai;\n\n this.messageBuilder.resetCustomFields();\n this.messageBuilder.addCustomFields(fields);\n this.messageBuilder.addCustomField(\n \"tool_event_time\",\n this.messageBuilder.formatTimeStamp(new Date()) + \" UTC\"\n );\n\n const message = this.messageBuilder.createSemanticEventToolMessage(\n sai,\n transactionID,\n \"ATTEMPT\",\n undefined,\n undefined\n );\n\n this.sendMessage(message);\n return transactionID;\n }\n\n // New object-based API\n logInterfaceHintRequest(params: LogHintRequestParams): string;\n // Backward compatibility overload\n logInterfaceHintRequest(\n selection: string | string[],\n action: string | string[],\n input: string | string[],\n customFields?: Record<string, unknown>\n ): string;\n // Implementation\n logInterfaceHintRequest(\n paramsOrSelection: LogHintRequestParams | string | string[],\n action?: string | string[],\n input?: string | string[],\n customFields?: Record<string, unknown>\n ): string {\n let sai: SAI;\n let fields: Record<string, unknown> | undefined;\n\n // Check if using new object-based API\n if (\n typeof paramsOrSelection === \"object\" &&\n !Array.isArray(paramsOrSelection) &&\n \"selection\" in paramsOrSelection\n ) {\n const params = paramsOrSelection;\n sai = {\n selection: params.selection,\n action: params.action,\n input: params.input,\n };\n fields = params.customFields;\n }\n // Backward compatibility: old positional parameters\n else {\n sai = {\n selection: paramsOrSelection,\n action: action!,\n input: input!,\n };\n fields = customFields;\n }\n\n const transactionID = generateTransactionID();\n this.lastTransactionID = transactionID;\n\n this.messageBuilder.resetCustomFields();\n this.messageBuilder.addCustomFields(fields);\n this.messageBuilder.addCustomField(\n \"tool_event_time\",\n this.messageBuilder.formatTimeStamp(new Date()) + \" UTC\"\n );\n\n const message = this.messageBuilder.createSemanticEventToolMessage(\n sai,\n transactionID,\n \"HINT_REQUEST\",\n undefined,\n undefined\n );\n\n this.sendMessage(message);\n return transactionID;\n }\n\n // New object-based API\n logHintResponse(params: LogHintResponseParams): void;\n // Backward compatibility overload\n logHintResponse(\n transactionID: string,\n selection: string | string[],\n action: string | string[],\n input: string | string[],\n currentHintNumber: number,\n totalHintsAvailable: number,\n hintText: string,\n customFields?: Record<string, unknown>\n ): void;\n // Implementation\n logHintResponse(\n paramsOrTransactionID: LogHintResponseParams | string,\n selection?: string | string[],\n action?: string | string[],\n input?: string | string[],\n currentHintNumber?: number,\n totalHintsAvailable?: number,\n hintText?: string,\n customFields?: Record<string, unknown>\n ): void {\n // Check if using new object-based API\n if (\n typeof paramsOrTransactionID === \"object\" &&\n \"transactionId\" in paramsOrTransactionID\n ) {\n const params = paramsOrTransactionID;\n const evaluation: ActionEvaluation = {\n evaluation: \"HINT\",\n currentHintNumber: params.currentHintNumber,\n totalHintsAvailable: params.totalHintsAvailable,\n };\n\n this.logResponse({\n transactionId: params.transactionId,\n selection: params.selection,\n action: params.action,\n input: params.input,\n semanticName: \"HINT_MSG\",\n evaluation,\n advice: params.hintText,\n customFields: params.customFields,\n });\n }\n // Backward compatibility: old positional parameters\n else {\n const evaluation: ActionEvaluation = {\n evaluation: \"HINT\",\n currentHintNumber: currentHintNumber!,\n totalHintsAvailable: totalHintsAvailable!,\n };\n\n this.logResponse({\n transactionId: paramsOrTransactionID,\n selection: selection!,\n action: action!,\n input: input!,\n semanticName: \"HINT_MSG\",\n evaluation,\n advice: hintText!,\n customFields,\n });\n }\n }\n\n // New object-based API\n logResponse(params: LogResponseParams): void;\n // Backward compatibility overload\n logResponse(\n transactionID: string,\n selection: string | string[],\n action: string | string[],\n input: string | string[],\n semanticName: string,\n evaluation: string | ActionEvaluation,\n advice: string,\n customFields?: Record<string, unknown>,\n skills?: Skill[]\n ): void;\n // Implementation\n logResponse(\n paramsOrTransactionID: LogResponseParams | string,\n selection?: string | string[],\n action?: string | string[],\n input?: string | string[],\n semanticName?: string,\n evaluation?: string | ActionEvaluation,\n advice?: string,\n customFields?: Record<string, unknown>,\n skills?: Skill[]\n ): void {\n // Check if using new object-based API\n if (\n typeof paramsOrTransactionID === \"object\" &&\n \"transactionId\" in paramsOrTransactionID\n ) {\n const params = paramsOrTransactionID;\n const sai: SAI = {\n selection: params.selection,\n action: params.action,\n input: params.input,\n };\n this.logResponseSAI({\n transactionId: params.transactionId,\n sai,\n semanticName: params.semanticName,\n evaluation: params.evaluation,\n advice: params.advice,\n customFields: params.customFields,\n skills: params.skills,\n });\n }\n // Backward compatibility: old positional parameters\n else {\n const sai: SAI = {\n selection: selection!,\n action: action!,\n input: input!,\n };\n this.logResponseSAI({\n transactionId: paramsOrTransactionID,\n sai,\n semanticName: semanticName!,\n evaluation: evaluation!,\n advice: advice!,\n customFields,\n skills,\n });\n }\n }\n\n // New object-based API\n logResponseSAI(params: LogResponseSAIParams): void;\n // Backward compatibility overload\n logResponseSAI(\n transactionID: string,\n sai: SAI,\n semanticName: string,\n evaluation: string | ActionEvaluation,\n advice: string,\n customFields?: Record<string, unknown>,\n skills?: Skill[]\n ): void;\n // Implementation\n logResponseSAI(\n paramsOrTransactionID: LogResponseSAIParams | string,\n sai?: SAI,\n semanticName?: string,\n evaluation?: string | ActionEvaluation,\n advice?: string,\n customFields?: Record<string, unknown>,\n skills?: Skill[]\n ): void {\n let actualParams: LogResponseSAIParams;\n\n // Check if using new object-based API\n if (\n typeof paramsOrTransactionID === \"object\" &&\n \"sai\" in paramsOrTransactionID\n ) {\n actualParams = paramsOrTransactionID;\n }\n // Backward compatibility\n else {\n actualParams = {\n transactionId: paramsOrTransactionID,\n sai: sai!,\n semanticName: semanticName!,\n evaluation: evaluation!,\n advice: advice!,\n customFields,\n skills,\n };\n }\n\n const evalObj: ActionEvaluation =\n typeof actualParams.evaluation === \"string\"\n ? {\n evaluation:\n actualParams.evaluation as ActionEvaluation[\"evaluation\"],\n }\n : actualParams.evaluation;\n\n this.lastSAI = actualParams.sai;\n\n this.messageBuilder.resetCustomFields();\n this.messageBuilder.addCustomFields(actualParams.customFields);\n this.messageBuilder.addCustomField(\n \"tutor_event_time\",\n this.messageBuilder.formatTimeStamp(new Date()) + \" UTC\"\n );\n\n const formattedFeedback = actualParams.advice\n ? `<![CDATA[${actualParams.advice}]]>`\n : \"\";\n\n const message = this.messageBuilder.createTutorMessage(\n actualParams.sai,\n actualParams.transactionId || this.lastTransactionID,\n actualParams.semanticName,\n evalObj,\n formattedFeedback,\n undefined,\n actualParams.skills\n );\n\n this.sendMessage(message);\n }\n\n private sendMessage(message: string): void {\n if (this.logFormat === \"DATASHOP\") {\n let finalMessage: string;\n \n // Wrap message for OLI format unless it's a log_session_start message\n if (message.includes('<log_session_start')) {\n // log_session_start messages are sent as-is\n finalMessage = message;\n } else {\n // Other messages need to be wrapped in tutor_related_message_sequence and then in log_action\n const wrappedMessage = this.messageBuilder.wrapForDataShop(message);\n finalMessage = this.messageBuilder.wrapForOLI(wrappedMessage);\n }\n\n if (!this.configuration.log_service_url) {\n throw new ConfigurationError(\"log_service_url is not configured\");\n }\n\n // Use sendBeacon if available, otherwise fall back to fetch\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n navigator.sendBeacon(\n this.configuration.log_service_url,\n finalMessage\n );\n } else if (typeof fetch !== \"undefined\") {\n // Non-blocking fetch for Node.js or modern browsers\n // Use text/plain to match sendBeacon behavior\n fetch(this.configuration.log_service_url, {\n method: \"POST\",\n body: finalMessage,\n headers: {\n \"Content-Type\": \"text/plain\",\n },\n keepalive: true,\n }).catch(() => {\n // Silently fail - DataShop logging should not break the application\n });\n } else {\n throw new NetworkError(\"No suitable method for sending log messages\");\n }\n\n // Call log listener if registered\n if (this.logListener) {\n this.logListener(finalMessage);\n }\n } else {\n throw new ConfigurationError(`Unsupported log format: ${this.logFormat}`);\n }\n }\n\n // Configuration methods with object parameters\n setLogFormat(params: SetLogFormatParams): void {\n this.logFormat = params.format;\n }\n\n getLogFormat(): \"DATASHOP\" | \"XAPI\" {\n return this.logFormat;\n }\n\n setLoggingURL(params: SetLoggingURLParams): void {\n this.configuration.log_service_url = params.url;\n }\n\n setLoggingURLQA(): void {\n this.setLoggingURL({ url: \"https://pslc-qa.andrew.cmu.edu/log/server\" });\n }\n\n setLoggingURLProduction(): void {\n this.setLoggingURL({ url: \"https://learnlab.web.cmu.edu/log/server\" });\n }\n\n setContextName(params: SetContextNameParams): void {\n this.configuration.context_name = params.name;\n }\n\n getContextName(): string {\n return (this.configuration.context_name || \"START_PROBLEM\") as string;\n }\n\n setContextMessageID(params: SetContextMessageIDParams): void {\n this.configuration.context_message_id = params.id;\n }\n\n getContextMessageID(): string {\n return this.configuration.context_message_id || \"\";\n }\n\n setUserID(params: SetUserIDParams): void {\n this.configuration.user_guid = params.id;\n }\n\n setProblemName(params: SetProblemNameParams): void {\n this.configuration.problem_name = params.name;\n }\n\n setProblemContext(params: SetProblemContextParams): void {\n this.configuration.problem_context = params.context;\n }\n\n setDatasetName(params: SetDatasetNameParams): void {\n this.configuration.dataset_name = params.name;\n }\n\n setSchool(params: SetSchoolParams): void {\n this.configuration.school_name = params.school;\n }\n\n setPeriod(params: SetPeriodParams): void {\n this.configuration.period_name = params.period;\n }\n\n setInstructor(params: SetInstructorParams): void {\n this.configuration.instructor_name = params.instructor;\n }\n\n setDescription(params: SetDescriptionParams): void {\n this.configuration.class_description = params.description;\n }\n\n setLogClassName(params: SetLogClassNameParams): void {\n this.configuration.class_name = params.className;\n }\n\n setDatasetLevelName(params: SetDatasetLevelNameParams): void {\n this.configuration[`dataset_level_name${params.level}`] = params.name;\n }\n\n setDatasetLevelType(params: SetDatasetLevelTypeParams): void {\n this.configuration[`dataset_level_type${params.level}`] = params.type;\n }\n\n setUseSessionLog(params: SetUseSessionLogParams): void {\n this.useSessionLog = params.use;\n }\n\n getLastSAI(): SAI | null {\n return this.lastSAI;\n }\n\n getSessionId(): string | undefined {\n return this.configuration.session_id;\n }\n\n getUserGuid(): string | undefined {\n return this.configuration.user_guid;\n }\n\n getContextMessageId(): string | undefined {\n return this.configuration.context_message_id;\n }\n\n endSession(): void {\n // Generate new session for next use\n this.configuration.session_id = `ctat_session_${generateGUID()}`;\n }\n\n setLogListener(params: SetLogListenerParams): void {\n this.logListener = params.listener;\n }\n}\n"],"mappings":"AAEO,IAAMA,EAAN,KAAiB,CAKtB,YAAYC,EAA+BC,EAA4BC,EAA2B,CAJlG,KAAQ,eAA2B,CAAC,EACpC,KAAQ,YAAwB,CAAC,EACjC,KAAQ,WAAuB,CAAC,EAG1BF,IAAc,QAChB,KAAK,aAAaA,CAAS,EAEzBC,IAAW,QACb,KAAK,UAAUA,CAAM,EAEnBC,IAAU,QACZ,KAAK,SAASA,CAAK,CAEvB,CAEA,aAAaF,EAA0C,CACrD,YAAK,eAAiB,MAAM,QAAQA,CAAS,EAAI,CAAC,GAAGA,CAAS,EAAI,CAACA,CAAS,EACrE,IACT,CAEA,UAAUC,EAAuC,CAC/C,YAAK,YAAc,MAAM,QAAQA,CAAM,EAAI,CAAC,GAAGA,CAAM,EAAI,CAACA,CAAM,EACzD,IACT,CAEA,SAASC,EAAsC,CAC7C,YAAK,WAAa,MAAM,QAAQA,CAAK,EAAI,CAAC,GAAGA,CAAK,EAAI,CAACA,CAAK,EACrD,IACT,CAEA,OAAa,CACX,MAAO,CACL,UAAW,KAAK,eAAe,SAAW,EAAI,CAAC,EAAI,KAAK,eAAe,SAAW,EAAI,KAAK,eAAe,CAAC,EAAK,KAAK,eACrH,OAAQ,KAAK,YAAY,SAAW,EAAI,CAAC,EAAI,KAAK,YAAY,SAAW,EAAI,KAAK,YAAY,CAAC,EAAK,KAAK,YACzG,MAAO,KAAK,WAAW,SAAW,EAAI,CAAC,EAAI,KAAK,WAAW,SAAW,EAAI,KAAK,WAAW,CAAC,EAAK,KAAK,UACvG,CACF,CAEA,aAAsB,CACpB,IAAIC,EAAM,GAEV,QAAWH,KAAa,KAAK,eAC3BG,GAAO,cAAc,KAAK,UAAUH,CAAS,CAAC,eAGhD,QAASI,EAAI,EAAGA,EAAI,KAAK,YAAY,OAAQA,IACvCA,IAAM,EACRD,GAAO,WAAW,KAAK,UAAU,KAAK,YAAYC,CAAC,CAAE,CAAC,GAEtDD,GAAO,oBAAoB,KAAK,UAAU,KAAK,YAAYC,CAAC,CAAE,CAAC,GAG/D,KAAK,YAAY,OAAS,IAC5BD,GAAO,aAGT,QAAWD,KAAS,KAAK,WACvBC,GAAO,mBAAmBD,CAAK,cAGjC,OAAOC,CACT,CAEQ,UAAUE,EAAqB,CACrC,OAAOA,EACJ,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,EACtB,QAAQ,KAAM,QAAQ,CAC3B,CACF,ECxEO,IAAMC,EAAN,KAAwB,CAK7B,YAAoBC,EAAiC,CAAjC,mBAAAA,EAJpB,KAAiB,UAAY,yCAC7B,KAAiB,WAAa,IAC9B,KAAQ,aAAuD,IAAI,GAEb,CAEtD,mBAA0B,CACxB,KAAK,aAAa,MAAM,CAC1B,CAEA,eAAeC,EAAcC,EAAwC,CACnE,KAAK,aAAa,IAAID,EAAMC,CAAK,CACnC,CAEA,gBAAgBC,EAAwC,CACtD,GAAKA,EAEL,OAAW,CAACC,EAAKF,CAAK,IAAK,OAAO,QAAQC,CAAM,EACnBD,GAAU,MACnC,KAAK,eAAeE,EAAK,OAAOF,CAAK,CAAC,CAG5C,CAEA,gBAAgBG,EAAoB,CAClC,OAAOA,EAAK,YAAY,EAAE,QAAQ,IAAK,GAAG,EAAE,QAAQ,IAAK,EAAE,CAC7D,CAEA,mBAAmBA,EAAoB,CAErC,IAAMC,EAAOD,EAAK,eAAe,EAC3BE,EAAQ,OAAOF,EAAK,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,EACtDG,EAAM,OAAOH,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EAC/CI,EAAQ,OAAOJ,EAAK,YAAY,CAAC,EAAE,SAAS,EAAG,GAAG,EAClDK,EAAU,OAAOL,EAAK,cAAc,CAAC,EAAE,SAAS,EAAG,GAAG,EACtDM,EAAU,OAAON,EAAK,cAAc,CAAC,EAAE,SAAS,EAAG,GAAG,EAE5D,MAAO,GAAGC,CAAI,IAAIC,CAAK,IAAIC,CAAG,IAAIC,CAAK,IAAIC,CAAO,IAAIC,CAAO,EAC/D,CAEA,uBAAgC,CAC9B,IAAMC,EAAM,IAAI,KAGZC,EAAU,GAAG,KAAK,SAAS,sBAC/B,OAAAA,GAAW,kBACXA,GAAW,cAAc,KAAK,mBAAmBD,CAAG,CAAC,KACrDC,GAAW,eAAe,KAAK,cAAc,YAAc,EAAE,KAC7DA,GAAW,eAAe,KAAK,cAAc,YAAc,EAAE,KAC7DA,GAAW,cAAc,KAAK,cAAc,WAAa,EAAE,KAC3DA,GAAW,+EAEJA,CACT,CAEA,sBAA+B,CAC7B,IAAMC,EAAO,KAAK,cACZF,EAAM,IAAI,KAEZC,EAAU,wCAAwCC,EAAK,oBAAsB,EAAE,0BAEnFD,GAAW,KAAK,gBAAgBD,CAAG,EAG/BE,EAAK,aACPD,GAAW,UACXA,GAAW,SAAS,KAAK,UAAUC,EAAK,UAAU,CAAC,UAC/CA,EAAK,cAAaD,GAAW,WAAW,KAAK,UAAUC,EAAK,WAAW,CAAC,aACxEA,EAAK,cAAaD,GAAW,WAAW,KAAK,UAAUC,EAAK,WAAW,CAAC,aACxEA,EAAK,oBAAmBD,GAAW,gBAAgB,KAAK,UAAUC,EAAK,iBAAiB,CAAC,kBACzFA,EAAK,kBAAiBD,GAAW,eAAe,KAAK,UAAUC,EAAK,eAAe,CAAC,iBACxFD,GAAW,YAIbA,GAAW,YACXA,GAAW,kBAAkBC,EAAK,cAAgB,mBAAmB,aAGrE,IAAIC,EAAe,GACfC,EAAc,EAGlB,QAASC,EAAI,EAAGA,GAAK,GAAIA,IAAK,CAC5B,IAAMC,EAAe,qBAAqBD,CAAC,GACrCE,EAAe,qBAAqBF,CAAC,GACrCG,EAAYN,EAAKI,CAAY,EAC7BG,EAAYP,EAAKK,CAAY,EAEnC,GAAIC,GAAaC,EACfL,IACAD,GAAgB,gBAAgB,KAAK,UAAU,OAAOM,CAAS,CAAC,CAAC,KACjEN,GAAgB,kBAAkB,OAAOK,CAAS,CAAC,iBAEnD,MAEJ,CAGA,GAAIJ,EAAc,EAAG,CACnBD,GAAgB,8BAChBA,GAAgB,kBAAkBD,EAAK,cAAgB,EAAE,aACrDA,EAAK,kBACPC,GAAgB,qBAAqBD,EAAK,eAAe,iBAE3DC,GAAgB,aAGhB,QAASE,EAAI,EAAGA,EAAID,EAAaC,IAC/BF,GAAgB,WAGlBF,GAAWE,CACb,MAEEF,GAAW,8BACXA,GAAW,kBAAkBC,EAAK,cAAgB,EAAE,aAChDA,EAAK,kBACPD,GAAW,qBAAqBC,EAAK,eAAe,iBAEtDD,GAAW,aAGb,OAAAA,GAAW,aAOXA,GAAW,qBAEJA,CACT,CAEA,+BACES,EACAC,EACAC,EACAC,EACAC,EACQ,CACR,IAAMC,EAAa,IAAIC,EAAWN,EAAI,UAAWA,EAAI,OAAQA,EAAI,KAAK,EAElET,EAAU,qCAAqC,KAAK,cAAc,oBAAsB,EAAE,KAC9FA,GAAW,KAAK,gBAAgB,IAAI,IAAM,EAC1CA,GAAW,mCAAmCU,CAAa,WAAWC,CAAiB,IACnFC,IACFZ,GAAW,aAAaY,CAAoB,KAE1CC,IACFb,GAAW,aAAaa,CAAO,KAEjCb,GAAW,KACXA,GAAW,qBACXA,GAAWc,EAAW,YAAY,EAClCd,GAAW,sBAGX,OAAW,CAACZ,EAAMC,CAAK,IAAK,KAAK,aAC/BW,GAAW,uBAAuB,KAAK,UAAUZ,CAAI,CAAC,iBAAiB,KAAK,UAAU,OAAOC,CAAK,CAAC,CAAC,0BAGtG,OAAAW,GAAW,kBAEJA,CACT,CAEA,mBACES,EACAC,EACAC,EACAK,EACAC,EACAL,EACAM,EACQ,CACR,IAAMJ,EAAa,IAAIC,EAAWN,EAAI,UAAWA,EAAI,OAAQA,EAAI,KAAK,EAElET,EAAU,sCAAsC,KAAK,cAAc,oBAAsB,EAAE,KA8B/F,GA7BAA,GAAW,KAAK,gBAAgB,IAAI,IAAM,EAC1CA,GAAW,mCAAmCU,CAAa,WAAWC,CAAiB,IACnFC,IACFZ,GAAW,aAAaY,CAAoB,KAE9CZ,GAAW,KACXA,GAAW,qBACXA,GAAWc,EAAW,YAAY,EAClCd,GAAW,sBAGXA,GAAW,qBACPgB,EAAW,iBACbhB,GAAW,oBAAoBgB,EAAW,cAAc,KAEtDA,EAAW,oBAAsB,SACnChB,GAAW,yBAAyBgB,EAAW,iBAAiB,KAE9DA,EAAW,sBAAwB,SACrChB,GAAW,2BAA2BgB,EAAW,mBAAmB,KAEtEhB,GAAW,IAAIgB,EAAW,UAAU,uBAGhCC,IACFjB,GAAW,iBAAiBiB,CAAQ,mBAIlCC,GAAUA,EAAO,OAAS,EAAG,CAC/BlB,GAAW,WACX,QAAWmB,KAASD,EAClBlB,GAAW,UACXA,GAAW,SAAS,KAAK,UAAUmB,EAAM,IAAI,CAAC,UAC1CA,EAAM,WACRnB,GAAW,aAAa,KAAK,UAAUmB,EAAM,QAAQ,CAAC,eAExDnB,GAAW,WAEbA,GAAW,WACb,CAGA,OAAW,CAACZ,EAAMC,CAAK,IAAK,KAAK,aAC/BW,GAAW,uBAAuB,KAAK,UAAUZ,CAAI,CAAC,iBAAiB,KAAK,UAAU,OAAOC,CAAK,CAAC,CAAC,0BAGtG,OAAAW,GAAW,mBAEJA,CACT,CAEA,gBAAgBA,EAAyB,CAEvC,OAAIA,EAAQ,SAAS,oBAAoB,EAChCA,EAEF,GAAG,KAAK,SAAS,mDAAmD,KAAK,UAAU,KAAKA,CAAO,mCACxG,CAEA,WAAWA,EAAyB,CAClC,IAAMD,EAAM,IAAI,KACVE,EAAO,KAAK,cAGZmB,EAAiB,mBAAmBpB,CAAO,EAE7CqB,EAAU,GAAG,KAAK,SAAS,eAC/B,OAAAA,GAAW,eAAe,mBAAmBpB,EAAK,YAAc,EAAE,CAAC,KACnEoB,GAAW,eAAepB,EAAK,YAAc,EAAE,KAC/CoB,GAAW,iCACXA,GAAW,gBACXA,GAAW,cAAc,KAAK,mBAAmBtB,CAAG,CAAC,KACrDsB,GAAW,kBACXA,GAAW,cAAcpB,EAAK,WAAa,OAAO,KAClDoB,GAAW,uBAAuBpB,EAAK,uBAAyB,EAAE,KAClEoB,GAAW,iCACXA,GAAWD,EACXC,GAAW,gBAEJA,CACT,CAEQ,gBAAgBC,EAAyB,CAC/C,IAAIC,EAAO,SACX,OAAAA,GAAQ,YAAY,KAAK,UAAU,KAAK,cAAc,WAAa,EAAE,CAAC,aACtEA,GAAQ,eAAe,KAAK,UAAU,KAAK,cAAc,YAAc,EAAE,CAAC,gBAC1EA,GAAQ,SAAS,KAAK,gBAAgBD,CAAS,CAAC,cAChDC,GAAQ,6BACRA,GAAQ,UACDA,CACT,CAEQ,UAAUC,EAAqB,CACrC,OAAOA,EACJ,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,EACtB,QAAQ,KAAM,QAAQ,CAC3B,CACF,EC7RO,SAASC,GAAuB,CAErC,IAAMC,EAAa,OAAO,WAAe,KAAe,WAAW,QAChD,OAAO,OAAW,KAAe,OAAO,QACxC,OAAO,OAAW,KAAe,OAAO,OAE3D,OAAIA,GAAaA,EAAU,WAClBA,EAAU,WAAW,EAIvB,uCAAuC,QAAQ,QAAUC,GAAM,CACpE,IAAMC,EAAK,KAAK,OAAO,EAAI,GAAM,EAEjC,OADUD,IAAM,IAAMC,EAAKA,EAAI,EAAO,GAC7B,SAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,GAAgC,CAC9C,MAAO,IAAIJ,EAAa,CAAC,EAC3B,CAEO,SAASK,GAAmC,CACjD,MAAO,IAAIL,EAAa,CAAC,EAC3B,CCxBA,IAAqBM,EAArB,MAAqBC,UAA4B,KAAM,CAIrD,YAAYC,EAAiBC,EAAcC,EAAmB,CAC5D,MAAMF,CAAO,EACb,KAAK,KAAO,sBACZ,KAAK,KAAOC,EACZ,KAAK,QAAUC,EAEX,MAAM,mBACR,MAAM,kBAAkB,KAAMH,CAAmB,CAErD,CACF,EAEaI,EAAN,cAAiCL,CAAoB,CAC1D,YAAYE,EAAiBE,EAAmB,CAC9C,MAAMF,EAAS,sBAAuBE,CAAO,EAC7C,KAAK,KAAO,oBACd,CACF,EAEaE,EAAN,cAA2BN,CAAoB,CACpD,YAAYE,EAAiBE,EAAmB,CAC9C,MAAMF,EAAS,gBAAiBE,CAAO,EACvC,KAAK,KAAO,cACd,CACF,ECYO,IAAMG,EAAN,KAAgD,CAerD,YAAYC,EAAiC,CAb7C,KAAQ,UAAiC,WACzC,KAAQ,cAAyB,GACjC,KAAQ,kBAA4B,GACpC,KAAQ,QAAsB,KAK9B,KAAiB,qBAAkD,CACjE,aAAc,oBACd,UAAW,OACb,EAGE,KAAK,cAAgB,CACnB,GAAG,KAAK,qBACR,GAAGA,GAAS,aACd,EAEIA,GAAS,YACX,KAAK,UAAYA,EAAQ,WAGvBA,GAAS,gBAAkB,SAC7B,KAAK,cAAgBA,EAAQ,eAG/B,KAAK,eAAiB,IAAIC,EAAkB,KAAK,aAAa,EAC9D,KAAK,kBAAkB,CACzB,CAEQ,mBAA0B,CAC3B,KAAK,cAAc,aACtB,KAAK,cAAc,WAAa,gBAAgBC,EAAa,CAAC,IAG3D,KAAK,cAAc,qBACtB,KAAK,cAAc,mBAAqBC,EAAyB,GAG9D,KAAK,cAAc,YACtB,KAAK,cAAc,UAAYD,EAAa,EAEhD,CAEA,OAAgB,CAGd,GAFA,KAAK,kBAAkB,EAEnB,KAAK,cAAe,CACtB,IAAME,EAAsB,KAAK,eAAe,sBAAsB,EACtE,KAAK,YAAYA,CAAmB,CACtC,CAEA,IAAMC,EAAiB,KAAK,eAAe,qBAAqB,EAChE,YAAK,YAAYA,CAAc,EAExB,KAAK,cAAc,UAC5B,CAEA,OAAOC,EAAyB,CAE9B,KAAK,cAAc,WAAaA,EAGhC,IAAMD,EAAiB,KAAK,eAAe,qBAAqB,EAChE,KAAK,YAAYA,CAAc,CACjC,CAOA,MAAME,EAAuD,CAC3D,IAAIC,EAIFD,GACA,OAAOA,GAAmB,UAC1B,kBAAmBA,EAEnBC,EAAUD,EAA+B,cAIzCC,EAASD,EAGX,KAAK,cAAgB,CACnB,GAAG,KAAK,qBACR,GAAGC,CACL,EACA,KAAK,eAAiB,IAAIP,EAAkB,KAAK,aAAa,EAC9D,KAAK,kBAAkB,CACzB,CAYA,oBACEQ,EACAC,EACAC,EACAC,EACQ,CAER,GACE,OAAOH,GAAsB,UAC7B,CAAC,MAAM,QAAQA,CAAiB,GAChC,cAAeA,EACf,CACA,IAAMI,EAASJ,EACTK,EAAW,CACf,UAAWD,EAAO,UAClB,OAAQA,EAAO,OACf,MAAOA,EAAO,KAChB,EACA,OAAO,KAAK,uBAAuB,CACjC,IAAAC,EACA,aAAcD,EAAO,YACvB,CAAC,CACH,KAEK,CACH,IAAMC,EAAW,CACf,UAAWL,EACX,OAAQC,EACR,MAAOC,CACT,EACA,OAAO,KAAK,uBAAuB,CAAE,IAAAG,EAAK,aAAAF,CAAa,CAAC,CAC1D,CACF,CAUA,uBACEG,EACAH,EACQ,CACR,IAAIE,EACAE,EAGA,QAASD,GACXD,EAAMC,EAAY,IAClBC,EAASD,EAAY,eAIrBD,EAAMC,EACNC,EAASJ,GAGX,IAAMK,EAAgBC,EAAsB,EAC5C,KAAK,kBAAoBD,EACzB,KAAK,QAAUH,EAEf,KAAK,eAAe,kBAAkB,EACtC,KAAK,eAAe,gBAAgBE,CAAM,EAC1C,KAAK,eAAe,eAClB,kBACA,KAAK,eAAe,gBAAgB,IAAI,IAAM,EAAI,MACpD,EAEA,IAAMG,EAAU,KAAK,eAAe,+BAClCL,EACAG,EACA,UACA,OACA,MACF,EAEA,YAAK,YAAYE,CAAO,EACjBF,CACT,CAYA,wBACER,EACAC,EACAC,EACAC,EACQ,CACR,IAAIE,EACAE,EAGJ,GACE,OAAOP,GAAsB,UAC7B,CAAC,MAAM,QAAQA,CAAiB,GAChC,cAAeA,EACf,CACA,IAAMI,EAASJ,EACfK,EAAM,CACJ,UAAWD,EAAO,UAClB,OAAQA,EAAO,OACf,MAAOA,EAAO,KAChB,EACAG,EAASH,EAAO,YAClB,MAGEC,EAAM,CACJ,UAAWL,EACX,OAAQC,EACR,MAAOC,CACT,EACAK,EAASJ,EAGX,IAAMK,EAAgBC,EAAsB,EAC5C,KAAK,kBAAoBD,EAEzB,KAAK,eAAe,kBAAkB,EACtC,KAAK,eAAe,gBAAgBD,CAAM,EAC1C,KAAK,eAAe,eAClB,kBACA,KAAK,eAAe,gBAAgB,IAAI,IAAM,EAAI,MACpD,EAEA,IAAMG,EAAU,KAAK,eAAe,+BAClCL,EACAG,EACA,eACA,OACA,MACF,EAEA,YAAK,YAAYE,CAAO,EACjBF,CACT,CAgBA,gBACEG,EACAC,EACAX,EACAC,EACAW,EACAC,EACAC,EACAZ,EACM,CAEN,GACE,OAAOQ,GAA0B,UACjC,kBAAmBA,EACnB,CACA,IAAMP,EAASO,EACTK,EAA+B,CACnC,WAAY,OACZ,kBAAmBZ,EAAO,kBAC1B,oBAAqBA,EAAO,mBAC9B,EAEA,KAAK,YAAY,CACf,cAAeA,EAAO,cACtB,UAAWA,EAAO,UAClB,OAAQA,EAAO,OACf,MAAOA,EAAO,MACd,aAAc,WACd,WAAAY,EACA,OAAQZ,EAAO,SACf,aAAcA,EAAO,YACvB,CAAC,CACH,KAEK,CACH,IAAMY,EAA+B,CACnC,WAAY,OACZ,kBAAmBH,EACnB,oBAAqBC,CACvB,EAEA,KAAK,YAAY,CACf,cAAeH,EACf,UAAWC,EACX,OAAQX,EACR,MAAOC,EACP,aAAc,WACd,WAAAc,EACA,OAAQD,EACR,aAAAZ,CACF,CAAC,CACH,CACF,CAiBA,YACEQ,EACAC,EACAX,EACAC,EACAe,EACAD,EACAE,EACAf,EACAgB,EACM,CAEN,GACE,OAAOR,GAA0B,UACjC,kBAAmBA,EACnB,CACA,IAAMP,EAASO,EACTN,EAAW,CACf,UAAWD,EAAO,UAClB,OAAQA,EAAO,OACf,MAAOA,EAAO,KAChB,EACA,KAAK,eAAe,CAClB,cAAeA,EAAO,cACtB,IAAAC,EACA,aAAcD,EAAO,aACrB,WAAYA,EAAO,WACnB,OAAQA,EAAO,OACf,aAAcA,EAAO,aACrB,OAAQA,EAAO,MACjB,CAAC,CACH,KAEK,CACH,IAAMC,EAAW,CACf,UAAWO,EACX,OAAQX,EACR,MAAOC,CACT,EACA,KAAK,eAAe,CAClB,cAAeS,EACf,IAAAN,EACA,aAAcY,EACd,WAAYD,EACZ,OAAQE,EACR,aAAAf,EACA,OAAAgB,CACF,CAAC,CACH,CACF,CAeA,eACER,EACAN,EACAY,EACAD,EACAE,EACAf,EACAgB,EACM,CACN,IAAIC,EAIF,OAAOT,GAA0B,UACjC,QAASA,EAETS,EAAeT,EAIfS,EAAe,CACb,cAAeT,EACf,IAAKN,EACL,aAAcY,EACd,WAAYD,EACZ,OAAQE,EACR,aAAAf,EACA,OAAAgB,CACF,EAGF,IAAME,EACJ,OAAOD,EAAa,YAAe,SAC/B,CACE,WACEA,EAAa,UACjB,EACAA,EAAa,WAEnB,KAAK,QAAUA,EAAa,IAE5B,KAAK,eAAe,kBAAkB,EACtC,KAAK,eAAe,gBAAgBA,EAAa,YAAY,EAC7D,KAAK,eAAe,eAClB,mBACA,KAAK,eAAe,gBAAgB,IAAI,IAAM,EAAI,MACpD,EAEA,IAAME,EAAoBF,EAAa,OACnC,YAAYA,EAAa,MAAM,MAC/B,GAEEV,EAAU,KAAK,eAAe,mBAClCU,EAAa,IACbA,EAAa,eAAiB,KAAK,kBACnCA,EAAa,aACbC,EACAC,EACA,OACAF,EAAa,MACf,EAEA,KAAK,YAAYV,CAAO,CAC1B,CAEQ,YAAYA,EAAuB,CACzC,GAAI,KAAK,YAAc,WAAY,CACjC,IAAIa,EAGJ,GAAIb,EAAQ,SAAS,oBAAoB,EAEvCa,EAAeb,MACV,CAEL,IAAMc,EAAiB,KAAK,eAAe,gBAAgBd,CAAO,EAClEa,EAAe,KAAK,eAAe,WAAWC,CAAc,CAC9D,CAEA,GAAI,CAAC,KAAK,cAAc,gBACtB,MAAM,IAAIC,EAAmB,mCAAmC,EAIlE,GAAI,OAAO,UAAc,KAAe,UAAU,WAChD,UAAU,WACR,KAAK,cAAc,gBACnBF,CACF,UACS,OAAO,MAAU,IAG1B,MAAM,KAAK,cAAc,gBAAiB,CACxC,OAAQ,OACR,KAAMA,EACN,QAAS,CACP,eAAgB,YAClB,EACA,UAAW,EACb,CAAC,EAAE,MAAM,IAAM,CAEf,CAAC,MAED,OAAM,IAAIG,EAAa,6CAA6C,EAIlE,KAAK,aACP,KAAK,YAAYH,CAAY,CAEjC,KACE,OAAM,IAAIE,EAAmB,2BAA2B,KAAK,SAAS,EAAE,CAE5E,CAGA,aAAarB,EAAkC,CAC7C,KAAK,UAAYA,EAAO,MAC1B,CAEA,cAAoC,CAClC,OAAO,KAAK,SACd,CAEA,cAAcA,EAAmC,CAC/C,KAAK,cAAc,gBAAkBA,EAAO,GAC9C,CAEA,iBAAwB,CACtB,KAAK,cAAc,CAAE,IAAK,2CAA4C,CAAC,CACzE,CAEA,yBAAgC,CAC9B,KAAK,cAAc,CAAE,IAAK,yCAA0C,CAAC,CACvE,CAEA,eAAeA,EAAoC,CACjD,KAAK,cAAc,aAAeA,EAAO,IAC3C,CAEA,gBAAyB,CACvB,OAAQ,KAAK,cAAc,cAAgB,eAC7C,CAEA,oBAAoBA,EAAyC,CAC3D,KAAK,cAAc,mBAAqBA,EAAO,EACjD,CAEA,qBAA8B,CAC5B,OAAO,KAAK,cAAc,oBAAsB,EAClD,CAEA,UAAUA,EAA+B,CACvC,KAAK,cAAc,UAAYA,EAAO,EACxC,CAEA,eAAeA,EAAoC,CACjD,KAAK,cAAc,aAAeA,EAAO,IAC3C,CAEA,kBAAkBA,EAAuC,CACvD,KAAK,cAAc,gBAAkBA,EAAO,OAC9C,CAEA,eAAeA,EAAoC,CACjD,KAAK,cAAc,aAAeA,EAAO,IAC3C,CAEA,UAAUA,EAA+B,CACvC,KAAK,cAAc,YAAcA,EAAO,MAC1C,CAEA,UAAUA,EAA+B,CACvC,KAAK,cAAc,YAAcA,EAAO,MAC1C,CAEA,cAAcA,EAAmC,CAC/C,KAAK,cAAc,gBAAkBA,EAAO,UAC9C,CAEA,eAAeA,EAAoC,CACjD,KAAK,cAAc,kBAAoBA,EAAO,WAChD,CAEA,gBAAgBA,EAAqC,CACnD,KAAK,cAAc,WAAaA,EAAO,SACzC,CAEA,oBAAoBA,EAAyC,CAC3D,KAAK,cAAc,qBAAqBA,EAAO,KAAK,EAAE,EAAIA,EAAO,IACnE,CAEA,oBAAoBA,EAAyC,CAC3D,KAAK,cAAc,qBAAqBA,EAAO,KAAK,EAAE,EAAIA,EAAO,IACnE,CAEA,iBAAiBA,EAAsC,CACrD,KAAK,cAAgBA,EAAO,GAC9B,CAEA,YAAyB,CACvB,OAAO,KAAK,OACd,CAEA,cAAmC,CACjC,OAAO,KAAK,cAAc,UAC5B,CAEA,aAAkC,CAChC,OAAO,KAAK,cAAc,SAC5B,CAEA,qBAA0C,CACxC,OAAO,KAAK,cAAc,kBAC5B,CAEA,YAAmB,CAEjB,KAAK,cAAc,WAAa,gBAAgBX,EAAa,CAAC,EAChE,CAEA,eAAeW,EAAoC,CACjD,KAAK,YAAcA,EAAO,QAC5B,CACF","names":["SAIBuilder","selection","action","input","xml","i","str","LogMessageBuilder","configuration","name","value","fields","key","date","year","month","day","hours","minutes","seconds","now","message","vars","levelContent","levelsFound","i","levelNameKey","levelTypeKey","levelName","levelType","sai","transactionID","semanticEventName","semanticEventSubtype","trigger","saiBuilder","SAIBuilder","evaluation","feedback","skills","skill","encodedMessage","wrapper","timestamp","meta","str","generateGUID","cryptoObj","c","r","generateTransactionID","generateContextMessageID","DataShopLoggerError","_DataShopLoggerError","message","code","details","ConfigurationError","NetworkError","DataShopLogger","options","LogMessageBuilder","generateGUID","generateContextMessageID","sessionStartMessage","contextMessage","sessionId","paramsOrConfig","config","paramsOrSelection","action","input","customFields","params","sai","paramsOrSai","fields","transactionID","generateTransactionID","message","paramsOrTransactionID","selection","currentHintNumber","totalHintsAvailable","hintText","evaluation","semanticName","advice","skills","actualParams","evalObj","formattedFeedback","finalMessage","wrappedMessage","ConfigurationError","NetworkError"]}