@memberjunction/ng-core-entity-forms 2.51.0 → 2.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +1 -1
  2. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts +19 -2
  3. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
  4. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +797 -508
  5. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  6. package/dist/lib/custom/Entities/entities-form.component.js +14 -16
  7. package/dist/lib/custom/Entities/entities-form.component.js.map +1 -1
  8. package/dist/lib/custom/EntityActions/entityaction.form.component.js +10 -12
  9. package/dist/lib/custom/EntityActions/entityaction.form.component.js.map +1 -1
  10. package/dist/lib/custom/Templates/template-params-grid.component.d.ts +37 -0
  11. package/dist/lib/custom/Templates/template-params-grid.component.d.ts.map +1 -0
  12. package/dist/lib/custom/Templates/template-params-grid.component.js +537 -0
  13. package/dist/lib/custom/Templates/template-params-grid.component.js.map +1 -0
  14. package/dist/lib/custom/Templates/templates-form.component.js +20 -25
  15. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  16. package/dist/lib/custom/ai-test-harness/agent-execution-monitor.component.d.ts.map +1 -0
  17. package/dist/lib/custom/{AIAgents → ai-test-harness}/agent-execution-monitor.component.js +18 -5
  18. package/dist/lib/custom/ai-test-harness/agent-execution-monitor.component.js.map +1 -0
  19. package/dist/lib/custom/ai-test-harness/agent-execution-node.component.d.ts.map +1 -0
  20. package/dist/lib/custom/{AIAgents → ai-test-harness}/agent-execution-node.component.js +4 -4
  21. package/dist/lib/custom/ai-test-harness/agent-execution-node.component.js.map +1 -0
  22. package/dist/lib/custom/ai-test-harness/ai-test-harness-dialog.component.d.ts.map +1 -0
  23. package/dist/lib/custom/{AIAgents → ai-test-harness}/ai-test-harness-dialog.component.js +1 -1
  24. package/dist/lib/custom/ai-test-harness/ai-test-harness-dialog.component.js.map +1 -0
  25. package/dist/lib/custom/{AIAgents → ai-test-harness}/ai-test-harness.component.d.ts +97 -7
  26. package/dist/lib/custom/ai-test-harness/ai-test-harness.component.d.ts.map +1 -0
  27. package/dist/lib/custom/ai-test-harness/ai-test-harness.component.js +3204 -0
  28. package/dist/lib/custom/ai-test-harness/ai-test-harness.component.js.map +1 -0
  29. package/dist/lib/custom/ai-test-harness/json-viewer-window.component.d.ts +8 -0
  30. package/dist/lib/custom/ai-test-harness/json-viewer-window.component.d.ts.map +1 -0
  31. package/dist/lib/custom/ai-test-harness/json-viewer-window.component.js +57 -0
  32. package/dist/lib/custom/ai-test-harness/json-viewer-window.component.js.map +1 -0
  33. package/dist/lib/custom/custom-forms.module.d.ts +26 -24
  34. package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
  35. package/dist/lib/custom/custom-forms.module.js +19 -9
  36. package/dist/lib/custom/custom-forms.module.js.map +1 -1
  37. package/dist/lib/custom/test-harness-dialog.service.js +1 -1
  38. package/dist/lib/custom/test-harness-dialog.service.js.map +1 -1
  39. package/dist/lib/generated/Entities/AIAction/aiaction.form.component.js +6 -8
  40. package/dist/lib/generated/Entities/AIAction/aiaction.form.component.js.map +1 -1
  41. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js +19 -21
  42. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js.map +1 -1
  43. package/dist/lib/generated/Entities/AIAgentAction/aiagentaction.form.component.js +3 -5
  44. package/dist/lib/generated/Entities/AIAgentAction/aiagentaction.form.component.js.map +1 -1
  45. package/dist/lib/generated/Entities/AIAgentLearningCycle/aiagentlearningcycle.form.component.js +3 -5
  46. package/dist/lib/generated/Entities/AIAgentLearningCycle/aiagentlearningcycle.form.component.js.map +1 -1
  47. package/dist/lib/generated/Entities/AIAgentModel/aiagentmodel.form.component.js +3 -5
  48. package/dist/lib/generated/Entities/AIAgentModel/aiagentmodel.form.component.js.map +1 -1
  49. package/dist/lib/generated/Entities/AIAgentNote/aiagentnote.form.component.js +3 -5
  50. package/dist/lib/generated/Entities/AIAgentNote/aiagentnote.form.component.js.map +1 -1
  51. package/dist/lib/generated/Entities/AIAgentNoteType/aiagentnotetype.form.component.js +5 -7
  52. package/dist/lib/generated/Entities/AIAgentNoteType/aiagentnotetype.form.component.js.map +1 -1
  53. package/dist/lib/generated/Entities/AIAgentPrompt/aiagentprompt.form.component.js +3 -5
  54. package/dist/lib/generated/Entities/AIAgentPrompt/aiagentprompt.form.component.js.map +1 -1
  55. package/dist/lib/generated/Entities/AIAgentRequest/aiagentrequest.form.component.js +3 -5
  56. package/dist/lib/generated/Entities/AIAgentRequest/aiagentrequest.form.component.js.map +1 -1
  57. package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js +9 -11
  58. package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js.map +1 -1
  59. package/dist/lib/generated/Entities/AIConfigurationParam/aiconfigurationparam.form.component.js +3 -5
  60. package/dist/lib/generated/Entities/AIConfigurationParam/aiconfigurationparam.form.component.js.map +1 -1
  61. package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js +21 -23
  62. package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js.map +1 -1
  63. package/dist/lib/generated/Entities/AIModelAction/aimodelaction.form.component.js +3 -5
  64. package/dist/lib/generated/Entities/AIModelAction/aimodelaction.form.component.js.map +1 -1
  65. package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js +6 -8
  66. package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js.map +1 -1
  67. package/dist/lib/generated/Entities/AIModelVendor/aimodelvendor.form.component.js +3 -5
  68. package/dist/lib/generated/Entities/AIModelVendor/aimodelvendor.form.component.js.map +1 -1
  69. package/dist/lib/generated/Entities/AIPrompt/aiprompt.form.component.js +21 -23
  70. package/dist/lib/generated/Entities/AIPrompt/aiprompt.form.component.js.map +1 -1
  71. package/dist/lib/generated/Entities/AIPrompt/sections/details.component.d.ts.map +1 -1
  72. package/dist/lib/generated/Entities/AIPrompt/sections/details.component.js +94 -4
  73. package/dist/lib/generated/Entities/AIPrompt/sections/details.component.js.map +1 -1
  74. package/dist/lib/generated/Entities/AIPromptCategory/aipromptcategory.form.component.js +6 -8
  75. package/dist/lib/generated/Entities/AIPromptCategory/aipromptcategory.form.component.js.map +1 -1
  76. package/dist/lib/generated/Entities/AIPromptModel/aipromptmodel.form.component.js +3 -5
  77. package/dist/lib/generated/Entities/AIPromptModel/aipromptmodel.form.component.js.map +1 -1
  78. package/dist/lib/generated/Entities/AIPromptRun/aipromptrun.form.component.js +6 -8
  79. package/dist/lib/generated/Entities/AIPromptRun/aipromptrun.form.component.js.map +1 -1
  80. package/dist/lib/generated/Entities/AIPromptRun/sections/details.component.d.ts.map +1 -1
  81. package/dist/lib/generated/Entities/AIPromptRun/sections/details.component.js +103 -4
  82. package/dist/lib/generated/Entities/AIPromptRun/sections/details.component.js.map +1 -1
  83. package/dist/lib/generated/Entities/AIPromptType/aiprompttype.form.component.js +5 -7
  84. package/dist/lib/generated/Entities/AIPromptType/aiprompttype.form.component.js.map +1 -1
  85. package/dist/lib/generated/Entities/AIResultCache/airesultcache.form.component.js +3 -5
  86. package/dist/lib/generated/Entities/AIResultCache/airesultcache.form.component.js.map +1 -1
  87. package/dist/lib/generated/Entities/AIVendor/aivendor.form.component.js +14 -16
  88. package/dist/lib/generated/Entities/AIVendor/aivendor.form.component.js.map +1 -1
  89. package/dist/lib/generated/Entities/AIVendorType/aivendortype.form.component.js +3 -5
  90. package/dist/lib/generated/Entities/AIVendorType/aivendortype.form.component.js.map +1 -1
  91. package/dist/lib/generated/Entities/AIVendorTypeDefinition/aivendortypedefinition.form.component.js +6 -8
  92. package/dist/lib/generated/Entities/AIVendorTypeDefinition/aivendortypedefinition.form.component.js.map +1 -1
  93. package/dist/lib/generated/Entities/Action/action.form.component.js +24 -15
  94. package/dist/lib/generated/Entities/Action/action.form.component.js.map +1 -1
  95. package/dist/lib/generated/Entities/Action/sections/code.component.js +3 -4
  96. package/dist/lib/generated/Entities/Action/sections/code.component.js.map +1 -1
  97. package/dist/lib/generated/Entities/Action/sections/details.component.d.ts.map +1 -1
  98. package/dist/lib/generated/Entities/Action/sections/details.component.js +24 -4
  99. package/dist/lib/generated/Entities/Action/sections/details.component.js.map +1 -1
  100. package/dist/lib/generated/Entities/ActionAuthorization/actionauthorization.form.component.js +3 -5
  101. package/dist/lib/generated/Entities/ActionAuthorization/actionauthorization.form.component.js.map +1 -1
  102. package/dist/lib/generated/Entities/ActionCategory/actioncategory.form.component.js +6 -8
  103. package/dist/lib/generated/Entities/ActionCategory/actioncategory.form.component.js.map +1 -1
  104. package/dist/lib/generated/Entities/ActionContext/actioncontext.form.component.js +3 -5
  105. package/dist/lib/generated/Entities/ActionContext/actioncontext.form.component.js.map +1 -1
  106. package/dist/lib/generated/Entities/ActionContextType/actioncontexttype.form.component.js +5 -7
  107. package/dist/lib/generated/Entities/ActionContextType/actioncontexttype.form.component.js.map +1 -1
  108. package/dist/lib/generated/Entities/ActionExecutionLog/actionexecutionlog.form.component.js +3 -5
  109. package/dist/lib/generated/Entities/ActionExecutionLog/actionexecutionlog.form.component.js.map +1 -1
  110. package/dist/lib/generated/Entities/ActionFilter/actionfilter.form.component.js +5 -7
  111. package/dist/lib/generated/Entities/ActionFilter/actionfilter.form.component.js.map +1 -1
  112. package/dist/lib/generated/Entities/ActionLibrary/actionlibrary.form.component.js +3 -5
  113. package/dist/lib/generated/Entities/ActionLibrary/actionlibrary.form.component.js.map +1 -1
  114. package/dist/lib/generated/Entities/ActionParam/actionparam.form.component.js +6 -8
  115. package/dist/lib/generated/Entities/ActionParam/actionparam.form.component.js.map +1 -1
  116. package/dist/lib/generated/Entities/ActionResultCode/actionresultcode.form.component.js +3 -5
  117. package/dist/lib/generated/Entities/ActionResultCode/actionresultcode.form.component.js.map +1 -1
  118. package/dist/lib/generated/Entities/Application/application.form.component.js +9 -11
  119. package/dist/lib/generated/Entities/Application/application.form.component.js.map +1 -1
  120. package/dist/lib/generated/Entities/ApplicationEntity/applicationentity.form.component.js +3 -5
  121. package/dist/lib/generated/Entities/ApplicationEntity/applicationentity.form.component.js.map +1 -1
  122. package/dist/lib/generated/Entities/ApplicationSetting/applicationsetting.form.component.js +3 -5
  123. package/dist/lib/generated/Entities/ApplicationSetting/applicationsetting.form.component.js.map +1 -1
  124. package/dist/lib/generated/Entities/ArtifactType/artifacttype.form.component.js +5 -7
  125. package/dist/lib/generated/Entities/ArtifactType/artifacttype.form.component.js.map +1 -1
  126. package/dist/lib/generated/Entities/AuditLog/auditlog.form.component.js +3 -5
  127. package/dist/lib/generated/Entities/AuditLog/auditlog.form.component.js.map +1 -1
  128. package/dist/lib/generated/Entities/AuditLogType/auditlogtype.form.component.js +6 -8
  129. package/dist/lib/generated/Entities/AuditLogType/auditlogtype.form.component.js.map +1 -1
  130. package/dist/lib/generated/Entities/Authorization/authorization.form.component.js +9 -11
  131. package/dist/lib/generated/Entities/Authorization/authorization.form.component.js.map +1 -1
  132. package/dist/lib/generated/Entities/AuthorizationRole/authorizationrole.form.component.js +3 -5
  133. package/dist/lib/generated/Entities/AuthorizationRole/authorizationrole.form.component.js.map +1 -1
  134. package/dist/lib/generated/Entities/CommunicationBaseMessageType/communicationbasemessagetype.form.component.js +6 -8
  135. package/dist/lib/generated/Entities/CommunicationBaseMessageType/communicationbasemessagetype.form.component.js.map +1 -1
  136. package/dist/lib/generated/Entities/CommunicationLog/communicationlog.form.component.js +3 -5
  137. package/dist/lib/generated/Entities/CommunicationLog/communicationlog.form.component.js.map +1 -1
  138. package/dist/lib/generated/Entities/CommunicationProvider/communicationprovider.form.component.js +7 -9
  139. package/dist/lib/generated/Entities/CommunicationProvider/communicationprovider.form.component.js.map +1 -1
  140. package/dist/lib/generated/Entities/CommunicationProviderMessageType/communicationprovidermessagetype.form.component.js +5 -7
  141. package/dist/lib/generated/Entities/CommunicationProviderMessageType/communicationprovidermessagetype.form.component.js.map +1 -1
  142. package/dist/lib/generated/Entities/CommunicationRun/communicationrun.form.component.js +5 -7
  143. package/dist/lib/generated/Entities/CommunicationRun/communicationrun.form.component.js.map +1 -1
  144. package/dist/lib/generated/Entities/Company/company.form.component.js +7 -9
  145. package/dist/lib/generated/Entities/Company/company.form.component.js.map +1 -1
  146. package/dist/lib/generated/Entities/CompanyIntegration/companyintegration.form.component.js +8 -10
  147. package/dist/lib/generated/Entities/CompanyIntegration/companyintegration.form.component.js.map +1 -1
  148. package/dist/lib/generated/Entities/CompanyIntegrationRecordMap/companyintegrationrecordmap.form.component.js +3 -5
  149. package/dist/lib/generated/Entities/CompanyIntegrationRecordMap/companyintegrationrecordmap.form.component.js.map +1 -1
  150. package/dist/lib/generated/Entities/CompanyIntegrationRun/companyintegrationrun.form.component.js +7 -9
  151. package/dist/lib/generated/Entities/CompanyIntegrationRun/companyintegrationrun.form.component.js.map +1 -1
  152. package/dist/lib/generated/Entities/CompanyIntegrationRunAPILog/companyintegrationrunapilog.form.component.js +3 -5
  153. package/dist/lib/generated/Entities/CompanyIntegrationRunAPILog/companyintegrationrunapilog.form.component.js.map +1 -1
  154. package/dist/lib/generated/Entities/CompanyIntegrationRunDetail/companyintegrationrundetail.form.component.js +5 -7
  155. package/dist/lib/generated/Entities/CompanyIntegrationRunDetail/companyintegrationrundetail.form.component.js.map +1 -1
  156. package/dist/lib/generated/Entities/ContentFileType/contentfiletype.form.component.js +6 -8
  157. package/dist/lib/generated/Entities/ContentFileType/contentfiletype.form.component.js.map +1 -1
  158. package/dist/lib/generated/Entities/ContentItem/contentitem.form.component.js +6 -8
  159. package/dist/lib/generated/Entities/ContentItem/contentitem.form.component.js.map +1 -1
  160. package/dist/lib/generated/Entities/ContentItemAttribute/contentitemattribute.form.component.js +3 -5
  161. package/dist/lib/generated/Entities/ContentItemAttribute/contentitemattribute.form.component.js.map +1 -1
  162. package/dist/lib/generated/Entities/ContentItemTag/contentitemtag.form.component.js +3 -5
  163. package/dist/lib/generated/Entities/ContentItemTag/contentitemtag.form.component.js.map +1 -1
  164. package/dist/lib/generated/Entities/ContentProcessRun/contentprocessrun.form.component.js +3 -5
  165. package/dist/lib/generated/Entities/ContentProcessRun/contentprocessrun.form.component.js.map +1 -1
  166. package/dist/lib/generated/Entities/ContentSource/contentsource.form.component.js +7 -9
  167. package/dist/lib/generated/Entities/ContentSource/contentsource.form.component.js.map +1 -1
  168. package/dist/lib/generated/Entities/ContentSourceParam/contentsourceparam.form.component.js +3 -5
  169. package/dist/lib/generated/Entities/ContentSourceParam/contentsourceparam.form.component.js.map +1 -1
  170. package/dist/lib/generated/Entities/ContentSourceType/contentsourcetype.form.component.js +6 -8
  171. package/dist/lib/generated/Entities/ContentSourceType/contentsourcetype.form.component.js.map +1 -1
  172. package/dist/lib/generated/Entities/ContentSourceTypeParam/contentsourcetypeparam.form.component.js +3 -5
  173. package/dist/lib/generated/Entities/ContentSourceTypeParam/contentsourcetypeparam.form.component.js.map +1 -1
  174. package/dist/lib/generated/Entities/ContentType/contenttype.form.component.js +6 -8
  175. package/dist/lib/generated/Entities/ContentType/contenttype.form.component.js.map +1 -1
  176. package/dist/lib/generated/Entities/ContentTypeAttribute/contenttypeattribute.form.component.js +3 -5
  177. package/dist/lib/generated/Entities/ContentTypeAttribute/contenttypeattribute.form.component.js.map +1 -1
  178. package/dist/lib/generated/Entities/Conversation/conversation.form.component.js +8 -10
  179. package/dist/lib/generated/Entities/Conversation/conversation.form.component.js.map +1 -1
  180. package/dist/lib/generated/Entities/ConversationArtifact/conversationartifact.form.component.js +7 -9
  181. package/dist/lib/generated/Entities/ConversationArtifact/conversationartifact.form.component.js.map +1 -1
  182. package/dist/lib/generated/Entities/ConversationArtifactPermission/conversationartifactpermission.form.component.js +3 -5
  183. package/dist/lib/generated/Entities/ConversationArtifactPermission/conversationartifactpermission.form.component.js.map +1 -1
  184. package/dist/lib/generated/Entities/ConversationArtifactVersion/conversationartifactversion.form.component.js +5 -7
  185. package/dist/lib/generated/Entities/ConversationArtifactVersion/conversationartifactversion.form.component.js.map +1 -1
  186. package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js +5 -7
  187. package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js.map +1 -1
  188. package/dist/lib/generated/Entities/Dashboard/dashboard.form.component.js +6 -8
  189. package/dist/lib/generated/Entities/Dashboard/dashboard.form.component.js.map +1 -1
  190. package/dist/lib/generated/Entities/DashboardCategory/dashboardcategory.form.component.js +6 -8
  191. package/dist/lib/generated/Entities/DashboardCategory/dashboardcategory.form.component.js.map +1 -1
  192. package/dist/lib/generated/Entities/DashboardUserPreference/dashboarduserpreference.form.component.js +3 -5
  193. package/dist/lib/generated/Entities/DashboardUserPreference/dashboarduserpreference.form.component.js.map +1 -1
  194. package/dist/lib/generated/Entities/DashboardUserState/dashboarduserstate.form.component.js +3 -5
  195. package/dist/lib/generated/Entities/DashboardUserState/dashboarduserstate.form.component.js.map +1 -1
  196. package/dist/lib/generated/Entities/DataContext/datacontext.form.component.js +7 -9
  197. package/dist/lib/generated/Entities/DataContext/datacontext.form.component.js.map +1 -1
  198. package/dist/lib/generated/Entities/DataContextItem/datacontextitem.form.component.js +3 -5
  199. package/dist/lib/generated/Entities/DataContextItem/datacontextitem.form.component.js.map +1 -1
  200. package/dist/lib/generated/Entities/Dataset/dataset.form.component.js +5 -7
  201. package/dist/lib/generated/Entities/Dataset/dataset.form.component.js.map +1 -1
  202. package/dist/lib/generated/Entities/DatasetItem/datasetitem.form.component.js +3 -5
  203. package/dist/lib/generated/Entities/DatasetItem/datasetitem.form.component.js.map +1 -1
  204. package/dist/lib/generated/Entities/DuplicateRun/duplicaterun.form.component.js +5 -7
  205. package/dist/lib/generated/Entities/DuplicateRun/duplicaterun.form.component.js.map +1 -1
  206. package/dist/lib/generated/Entities/DuplicateRunDetail/duplicaterundetail.form.component.js +5 -7
  207. package/dist/lib/generated/Entities/DuplicateRunDetail/duplicaterundetail.form.component.js.map +1 -1
  208. package/dist/lib/generated/Entities/DuplicateRunDetailMatch/duplicaterundetailmatch.form.component.js +3 -5
  209. package/dist/lib/generated/Entities/DuplicateRunDetailMatch/duplicaterundetailmatch.form.component.js.map +1 -1
  210. package/dist/lib/generated/Entities/Employee/employee.form.component.js +9 -11
  211. package/dist/lib/generated/Entities/Employee/employee.form.component.js.map +1 -1
  212. package/dist/lib/generated/Entities/EmployeeCompanyIntegration/employeecompanyintegration.form.component.js +3 -5
  213. package/dist/lib/generated/Entities/EmployeeCompanyIntegration/employeecompanyintegration.form.component.js.map +1 -1
  214. package/dist/lib/generated/Entities/EmployeeRole/employeerole.form.component.js +3 -5
  215. package/dist/lib/generated/Entities/EmployeeRole/employeerole.form.component.js.map +1 -1
  216. package/dist/lib/generated/Entities/EmployeeSkill/employeeskill.form.component.js +3 -5
  217. package/dist/lib/generated/Entities/EmployeeSkill/employeeskill.form.component.js.map +1 -1
  218. package/dist/lib/generated/Entities/Entity/entity.form.component.js +41 -43
  219. package/dist/lib/generated/Entities/Entity/entity.form.component.js.map +1 -1
  220. package/dist/lib/generated/Entities/Entity/sections/ui.component.js +3 -4
  221. package/dist/lib/generated/Entities/Entity/sections/ui.component.js.map +1 -1
  222. package/dist/lib/generated/Entities/EntityAIAction/entityaiaction.form.component.js +3 -5
  223. package/dist/lib/generated/Entities/EntityAIAction/entityaiaction.form.component.js.map +1 -1
  224. package/dist/lib/generated/Entities/EntityAction/entityaction.form.component.js +7 -9
  225. package/dist/lib/generated/Entities/EntityAction/entityaction.form.component.js.map +1 -1
  226. package/dist/lib/generated/Entities/EntityActionFilter/entityactionfilter.form.component.js +3 -5
  227. package/dist/lib/generated/Entities/EntityActionFilter/entityactionfilter.form.component.js.map +1 -1
  228. package/dist/lib/generated/Entities/EntityActionInvocation/entityactioninvocation.form.component.js +3 -5
  229. package/dist/lib/generated/Entities/EntityActionInvocation/entityactioninvocation.form.component.js.map +1 -1
  230. package/dist/lib/generated/Entities/EntityActionInvocationType/entityactioninvocationtype.form.component.js +5 -7
  231. package/dist/lib/generated/Entities/EntityActionInvocationType/entityactioninvocationtype.form.component.js.map +1 -1
  232. package/dist/lib/generated/Entities/EntityActionParam/entityactionparam.form.component.js +3 -5
  233. package/dist/lib/generated/Entities/EntityActionParam/entityactionparam.form.component.js.map +1 -1
  234. package/dist/lib/generated/Entities/EntityCommunicationField/entitycommunicationfield.form.component.js +3 -5
  235. package/dist/lib/generated/Entities/EntityCommunicationField/entitycommunicationfield.form.component.js.map +1 -1
  236. package/dist/lib/generated/Entities/EntityCommunicationMessageType/entitycommunicationmessagetype.form.component.js +5 -7
  237. package/dist/lib/generated/Entities/EntityCommunicationMessageType/entitycommunicationmessagetype.form.component.js.map +1 -1
  238. package/dist/lib/generated/Entities/EntityDocument/entitydocument.form.component.js +7 -9
  239. package/dist/lib/generated/Entities/EntityDocument/entitydocument.form.component.js.map +1 -1
  240. package/dist/lib/generated/Entities/EntityDocumentRun/entitydocumentrun.form.component.js +3 -5
  241. package/dist/lib/generated/Entities/EntityDocumentRun/entitydocumentrun.form.component.js.map +1 -1
  242. package/dist/lib/generated/Entities/EntityDocumentSetting/entitydocumentsetting.form.component.js +3 -5
  243. package/dist/lib/generated/Entities/EntityDocumentSetting/entitydocumentsetting.form.component.js.map +1 -1
  244. package/dist/lib/generated/Entities/EntityDocumentType/entitydocumenttype.form.component.js +5 -7
  245. package/dist/lib/generated/Entities/EntityDocumentType/entitydocumenttype.form.component.js.map +1 -1
  246. package/dist/lib/generated/Entities/EntityField/entityfield.form.component.js +5 -7
  247. package/dist/lib/generated/Entities/EntityField/entityfield.form.component.js.map +1 -1
  248. package/dist/lib/generated/Entities/EntityFieldValue/entityfieldvalue.form.component.js +3 -5
  249. package/dist/lib/generated/Entities/EntityFieldValue/entityfieldvalue.form.component.js.map +1 -1
  250. package/dist/lib/generated/Entities/EntityPermission/entitypermission.form.component.js +3 -5
  251. package/dist/lib/generated/Entities/EntityPermission/entitypermission.form.component.js.map +1 -1
  252. package/dist/lib/generated/Entities/EntityRecordDocument/entityrecorddocument.form.component.js +3 -5
  253. package/dist/lib/generated/Entities/EntityRecordDocument/entityrecorddocument.form.component.js.map +1 -1
  254. package/dist/lib/generated/Entities/EntityRelationship/entityrelationship.form.component.js +3 -5
  255. package/dist/lib/generated/Entities/EntityRelationship/entityrelationship.form.component.js.map +1 -1
  256. package/dist/lib/generated/Entities/EntityRelationshipDisplayComponent/entityrelationshipdisplaycomponent.form.component.js +5 -7
  257. package/dist/lib/generated/Entities/EntityRelationshipDisplayComponent/entityrelationshipdisplaycomponent.form.component.js.map +1 -1
  258. package/dist/lib/generated/Entities/EntitySetting/entitysetting.form.component.js +3 -5
  259. package/dist/lib/generated/Entities/EntitySetting/entitysetting.form.component.js.map +1 -1
  260. package/dist/lib/generated/Entities/ErrorLog/errorlog.form.component.js +3 -5
  261. package/dist/lib/generated/Entities/ErrorLog/errorlog.form.component.js.map +1 -1
  262. package/dist/lib/generated/Entities/ExplorerNavigationItem/explorernavigationitem.form.component.js +3 -5
  263. package/dist/lib/generated/Entities/ExplorerNavigationItem/explorernavigationitem.form.component.js.map +1 -1
  264. package/dist/lib/generated/Entities/File/file.form.component.js +5 -7
  265. package/dist/lib/generated/Entities/File/file.form.component.js.map +1 -1
  266. package/dist/lib/generated/Entities/FileCategory/filecategory.form.component.js +6 -8
  267. package/dist/lib/generated/Entities/FileCategory/filecategory.form.component.js.map +1 -1
  268. package/dist/lib/generated/Entities/FileEntityRecordLink/fileentityrecordlink.form.component.js +3 -5
  269. package/dist/lib/generated/Entities/FileEntityRecordLink/fileentityrecordlink.form.component.js.map +1 -1
  270. package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js +5 -7
  271. package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js.map +1 -1
  272. package/dist/lib/generated/Entities/GeneratedCode/generatedcode.form.component.js +3 -5
  273. package/dist/lib/generated/Entities/GeneratedCode/generatedcode.form.component.js.map +1 -1
  274. package/dist/lib/generated/Entities/GeneratedCodeCategory/generatedcodecategory.form.component.js +6 -8
  275. package/dist/lib/generated/Entities/GeneratedCodeCategory/generatedcodecategory.form.component.js.map +1 -1
  276. package/dist/lib/generated/Entities/Integration/integration.form.component.js +7 -9
  277. package/dist/lib/generated/Entities/Integration/integration.form.component.js.map +1 -1
  278. package/dist/lib/generated/Entities/IntegrationURLFormat/integrationurlformat.form.component.js +3 -5
  279. package/dist/lib/generated/Entities/IntegrationURLFormat/integrationurlformat.form.component.js.map +1 -1
  280. package/dist/lib/generated/Entities/Library/library.form.component.js +6 -8
  281. package/dist/lib/generated/Entities/Library/library.form.component.js.map +1 -1
  282. package/dist/lib/generated/Entities/LibraryItem/libraryitem.form.component.js +3 -5
  283. package/dist/lib/generated/Entities/LibraryItem/libraryitem.form.component.js.map +1 -1
  284. package/dist/lib/generated/Entities/List/list.form.component.js +6 -8
  285. package/dist/lib/generated/Entities/List/list.form.component.js.map +1 -1
  286. package/dist/lib/generated/Entities/ListCategory/listcategory.form.component.js +6 -8
  287. package/dist/lib/generated/Entities/ListCategory/listcategory.form.component.js.map +1 -1
  288. package/dist/lib/generated/Entities/ListDetail/listdetail.form.component.js +3 -5
  289. package/dist/lib/generated/Entities/ListDetail/listdetail.form.component.js.map +1 -1
  290. package/dist/lib/generated/Entities/OutputDeliveryType/outputdeliverytype.form.component.js +5 -7
  291. package/dist/lib/generated/Entities/OutputDeliveryType/outputdeliverytype.form.component.js.map +1 -1
  292. package/dist/lib/generated/Entities/OutputFormatType/outputformattype.form.component.js +5 -7
  293. package/dist/lib/generated/Entities/OutputFormatType/outputformattype.form.component.js.map +1 -1
  294. package/dist/lib/generated/Entities/OutputTriggerType/outputtriggertype.form.component.js +5 -7
  295. package/dist/lib/generated/Entities/OutputTriggerType/outputtriggertype.form.component.js.map +1 -1
  296. package/dist/lib/generated/Entities/Query/query.form.component.js +8 -10
  297. package/dist/lib/generated/Entities/Query/query.form.component.js.map +1 -1
  298. package/dist/lib/generated/Entities/QueryCategory/querycategory.form.component.js +6 -8
  299. package/dist/lib/generated/Entities/QueryCategory/querycategory.form.component.js.map +1 -1
  300. package/dist/lib/generated/Entities/QueryEntity/queryentity.form.component.js +3 -5
  301. package/dist/lib/generated/Entities/QueryEntity/queryentity.form.component.js.map +1 -1
  302. package/dist/lib/generated/Entities/QueryField/queryfield.form.component.js +3 -5
  303. package/dist/lib/generated/Entities/QueryField/queryfield.form.component.js.map +1 -1
  304. package/dist/lib/generated/Entities/QueryPermission/querypermission.form.component.js +3 -5
  305. package/dist/lib/generated/Entities/QueryPermission/querypermission.form.component.js.map +1 -1
  306. package/dist/lib/generated/Entities/Queue/queue.form.component.js +5 -7
  307. package/dist/lib/generated/Entities/Queue/queue.form.component.js.map +1 -1
  308. package/dist/lib/generated/Entities/QueueTask/queuetask.form.component.js +3 -5
  309. package/dist/lib/generated/Entities/QueueTask/queuetask.form.component.js.map +1 -1
  310. package/dist/lib/generated/Entities/QueueType/queuetype.form.component.js +5 -7
  311. package/dist/lib/generated/Entities/QueueType/queuetype.form.component.js.map +1 -1
  312. package/dist/lib/generated/Entities/Recommendation/recommendation.form.component.js +5 -7
  313. package/dist/lib/generated/Entities/Recommendation/recommendation.form.component.js.map +1 -1
  314. package/dist/lib/generated/Entities/RecommendationItem/recommendationitem.form.component.js +3 -5
  315. package/dist/lib/generated/Entities/RecommendationItem/recommendationitem.form.component.js.map +1 -1
  316. package/dist/lib/generated/Entities/RecommendationProvider/recommendationprovider.form.component.js +5 -7
  317. package/dist/lib/generated/Entities/RecommendationProvider/recommendationprovider.form.component.js.map +1 -1
  318. package/dist/lib/generated/Entities/RecommendationRun/recommendationrun.form.component.js +5 -7
  319. package/dist/lib/generated/Entities/RecommendationRun/recommendationrun.form.component.js.map +1 -1
  320. package/dist/lib/generated/Entities/RecordChange/recordchange.form.component.js +3 -5
  321. package/dist/lib/generated/Entities/RecordChange/recordchange.form.component.js.map +1 -1
  322. package/dist/lib/generated/Entities/RecordChangeReplayRun/recordchangereplayrun.form.component.js +5 -7
  323. package/dist/lib/generated/Entities/RecordChangeReplayRun/recordchangereplayrun.form.component.js.map +1 -1
  324. package/dist/lib/generated/Entities/RecordMergeDeletionLog/recordmergedeletionlog.form.component.js +3 -5
  325. package/dist/lib/generated/Entities/RecordMergeDeletionLog/recordmergedeletionlog.form.component.js.map +1 -1
  326. package/dist/lib/generated/Entities/RecordMergeLog/recordmergelog.form.component.js +6 -8
  327. package/dist/lib/generated/Entities/RecordMergeLog/recordmergelog.form.component.js.map +1 -1
  328. package/dist/lib/generated/Entities/Report/report.form.component.js +7 -9
  329. package/dist/lib/generated/Entities/Report/report.form.component.js.map +1 -1
  330. package/dist/lib/generated/Entities/ReportCategory/reportcategory.form.component.js +6 -8
  331. package/dist/lib/generated/Entities/ReportCategory/reportcategory.form.component.js.map +1 -1
  332. package/dist/lib/generated/Entities/ReportSnapshot/reportsnapshot.form.component.js +3 -5
  333. package/dist/lib/generated/Entities/ReportSnapshot/reportsnapshot.form.component.js.map +1 -1
  334. package/dist/lib/generated/Entities/ReportUserState/reportuserstate.form.component.js +3 -5
  335. package/dist/lib/generated/Entities/ReportUserState/reportuserstate.form.component.js.map +1 -1
  336. package/dist/lib/generated/Entities/ReportVersion/reportversion.form.component.js +3 -5
  337. package/dist/lib/generated/Entities/ReportVersion/reportversion.form.component.js.map +1 -1
  338. package/dist/lib/generated/Entities/ResourceLink/resourcelink.form.component.js +3 -5
  339. package/dist/lib/generated/Entities/ResourceLink/resourcelink.form.component.js.map +1 -1
  340. package/dist/lib/generated/Entities/ResourcePermission/resourcepermission.form.component.js +3 -5
  341. package/dist/lib/generated/Entities/ResourcePermission/resourcepermission.form.component.js.map +1 -1
  342. package/dist/lib/generated/Entities/ResourceType/resourcetype.form.component.js +8 -10
  343. package/dist/lib/generated/Entities/ResourceType/resourcetype.form.component.js.map +1 -1
  344. package/dist/lib/generated/Entities/Role/role.form.component.js +10 -12
  345. package/dist/lib/generated/Entities/Role/role.form.component.js.map +1 -1
  346. package/dist/lib/generated/Entities/RowLevelSecurityFilter/rowlevelsecurityfilter.form.component.js +5 -7
  347. package/dist/lib/generated/Entities/RowLevelSecurityFilter/rowlevelsecurityfilter.form.component.js.map +1 -1
  348. package/dist/lib/generated/Entities/ScheduledAction/scheduledaction.form.component.js +5 -7
  349. package/dist/lib/generated/Entities/ScheduledAction/scheduledaction.form.component.js.map +1 -1
  350. package/dist/lib/generated/Entities/ScheduledActionParam/scheduledactionparam.form.component.js +3 -5
  351. package/dist/lib/generated/Entities/ScheduledActionParam/scheduledactionparam.form.component.js.map +1 -1
  352. package/dist/lib/generated/Entities/SchemaInfo/schemainfo.form.component.js +3 -5
  353. package/dist/lib/generated/Entities/SchemaInfo/schemainfo.form.component.js.map +1 -1
  354. package/dist/lib/generated/Entities/Skill/skill.form.component.js +6 -8
  355. package/dist/lib/generated/Entities/Skill/skill.form.component.js.map +1 -1
  356. package/dist/lib/generated/Entities/Tag/tag.form.component.js +6 -8
  357. package/dist/lib/generated/Entities/Tag/tag.form.component.js.map +1 -1
  358. package/dist/lib/generated/Entities/TaggedItem/taggeditem.form.component.js +3 -5
  359. package/dist/lib/generated/Entities/TaggedItem/taggeditem.form.component.js.map +1 -1
  360. package/dist/lib/generated/Entities/Template/template.form.component.js +8 -10
  361. package/dist/lib/generated/Entities/Template/template.form.component.js.map +1 -1
  362. package/dist/lib/generated/Entities/TemplateCategory/templatecategory.form.component.js +6 -8
  363. package/dist/lib/generated/Entities/TemplateCategory/templatecategory.form.component.js.map +1 -1
  364. package/dist/lib/generated/Entities/TemplateContent/templatecontent.form.component.d.ts.map +1 -1
  365. package/dist/lib/generated/Entities/TemplateContent/templatecontent.form.component.js +19 -10
  366. package/dist/lib/generated/Entities/TemplateContent/templatecontent.form.component.js.map +1 -1
  367. package/dist/lib/generated/Entities/TemplateContentType/templatecontenttype.form.component.js +5 -7
  368. package/dist/lib/generated/Entities/TemplateContentType/templatecontenttype.form.component.js.map +1 -1
  369. package/dist/lib/generated/Entities/TemplateParam/sections/details.component.d.ts.map +1 -1
  370. package/dist/lib/generated/Entities/TemplateParam/sections/details.component.js +15 -4
  371. package/dist/lib/generated/Entities/TemplateParam/sections/details.component.js.map +1 -1
  372. package/dist/lib/generated/Entities/TemplateParam/templateparam.form.component.js +3 -5
  373. package/dist/lib/generated/Entities/TemplateParam/templateparam.form.component.js.map +1 -1
  374. package/dist/lib/generated/Entities/User/user.form.component.js +46 -48
  375. package/dist/lib/generated/Entities/User/user.form.component.js.map +1 -1
  376. package/dist/lib/generated/Entities/UserApplication/userapplication.form.component.js +5 -7
  377. package/dist/lib/generated/Entities/UserApplication/userapplication.form.component.js.map +1 -1
  378. package/dist/lib/generated/Entities/UserApplicationEntity/userapplicationentity.form.component.js +3 -5
  379. package/dist/lib/generated/Entities/UserApplicationEntity/userapplicationentity.form.component.js.map +1 -1
  380. package/dist/lib/generated/Entities/UserFavorite/userfavorite.form.component.js +3 -5
  381. package/dist/lib/generated/Entities/UserFavorite/userfavorite.form.component.js.map +1 -1
  382. package/dist/lib/generated/Entities/UserNotification/usernotification.form.component.js +3 -5
  383. package/dist/lib/generated/Entities/UserNotification/usernotification.form.component.js.map +1 -1
  384. package/dist/lib/generated/Entities/UserRecordLog/userrecordlog.form.component.js +3 -5
  385. package/dist/lib/generated/Entities/UserRecordLog/userrecordlog.form.component.js.map +1 -1
  386. package/dist/lib/generated/Entities/UserRole/userrole.form.component.js +3 -5
  387. package/dist/lib/generated/Entities/UserRole/userrole.form.component.js.map +1 -1
  388. package/dist/lib/generated/Entities/UserView/userview.form.component.js +7 -9
  389. package/dist/lib/generated/Entities/UserView/userview.form.component.js.map +1 -1
  390. package/dist/lib/generated/Entities/UserViewCategory/userviewcategory.form.component.js +6 -8
  391. package/dist/lib/generated/Entities/UserViewCategory/userviewcategory.form.component.js.map +1 -1
  392. package/dist/lib/generated/Entities/UserViewRun/userviewrun.form.component.js +5 -7
  393. package/dist/lib/generated/Entities/UserViewRun/userviewrun.form.component.js.map +1 -1
  394. package/dist/lib/generated/Entities/UserViewRunDetail/userviewrundetail.form.component.js +3 -5
  395. package/dist/lib/generated/Entities/UserViewRunDetail/userviewrundetail.form.component.js.map +1 -1
  396. package/dist/lib/generated/Entities/VectorDatabase/vectordatabase.form.component.js +6 -8
  397. package/dist/lib/generated/Entities/VectorDatabase/vectordatabase.form.component.js.map +1 -1
  398. package/dist/lib/generated/Entities/VectorIndex/vectorindex.form.component.js +5 -7
  399. package/dist/lib/generated/Entities/VectorIndex/vectorindex.form.component.js.map +1 -1
  400. package/dist/lib/generated/Entities/VersionInstallation/versioninstallation.form.component.js +3 -5
  401. package/dist/lib/generated/Entities/VersionInstallation/versioninstallation.form.component.js.map +1 -1
  402. package/dist/lib/generated/Entities/Workflow/workflow.form.component.js +6 -8
  403. package/dist/lib/generated/Entities/Workflow/workflow.form.component.js.map +1 -1
  404. package/dist/lib/generated/Entities/WorkflowEngine/workflowengine.form.component.js +5 -7
  405. package/dist/lib/generated/Entities/WorkflowEngine/workflowengine.form.component.js.map +1 -1
  406. package/dist/lib/generated/Entities/WorkflowRun/workflowrun.form.component.js +3 -5
  407. package/dist/lib/generated/Entities/WorkflowRun/workflowrun.form.component.js.map +1 -1
  408. package/dist/lib/generated/Entities/Workspace/workspace.form.component.js +5 -7
  409. package/dist/lib/generated/Entities/Workspace/workspace.form.component.js.map +1 -1
  410. package/dist/lib/generated/Entities/WorkspaceItem/workspaceitem.form.component.js +3 -5
  411. package/dist/lib/generated/Entities/WorkspaceItem/workspaceitem.form.component.js.map +1 -1
  412. package/dist/public-api.d.ts +2 -2
  413. package/dist/public-api.d.ts.map +1 -1
  414. package/dist/public-api.js +2 -2
  415. package/dist/public-api.js.map +1 -1
  416. package/package.json +12 -12
  417. package/dist/lib/custom/AIAgents/agent-execution-monitor.component.d.ts.map +0 -1
  418. package/dist/lib/custom/AIAgents/agent-execution-monitor.component.js.map +0 -1
  419. package/dist/lib/custom/AIAgents/agent-execution-node.component.d.ts.map +0 -1
  420. package/dist/lib/custom/AIAgents/agent-execution-node.component.js.map +0 -1
  421. package/dist/lib/custom/AIAgents/ai-test-harness-dialog.component.d.ts.map +0 -1
  422. package/dist/lib/custom/AIAgents/ai-test-harness-dialog.component.js.map +0 -1
  423. package/dist/lib/custom/AIAgents/ai-test-harness.component.d.ts.map +0 -1
  424. package/dist/lib/custom/AIAgents/ai-test-harness.component.js +0 -2658
  425. package/dist/lib/custom/AIAgents/ai-test-harness.component.js.map +0 -1
  426. package/dist/lib/custom/AIPrompts/ai-prompt-execution-dialog.component.d.ts +0 -99
  427. package/dist/lib/custom/AIPrompts/ai-prompt-execution-dialog.component.d.ts.map +0 -1
  428. package/dist/lib/custom/AIPrompts/ai-prompt-execution-dialog.component.js +0 -830
  429. package/dist/lib/custom/AIPrompts/ai-prompt-execution-dialog.component.js.map +0 -1
  430. /package/dist/lib/custom/{AIAgents → ai-test-harness}/agent-execution-monitor.component.d.ts +0 -0
  431. /package/dist/lib/custom/{AIAgents → ai-test-harness}/agent-execution-node.component.d.ts +0 -0
  432. /package/dist/lib/custom/{AIAgents → ai-test-harness}/ai-test-harness-dialog.component.d.ts +0 -0
@@ -1,2658 +0,0 @@
1
- import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
- import { Metadata } from '@memberjunction/core';
3
- import { MJNotificationService } from '@memberjunction/ng-notifications';
4
- import { Subject } from 'rxjs';
5
- /**
6
- * Result interface for AI agent execution operations.
7
- * Contains comprehensive information about the execution outcome, timing, and data.
8
- */
9
- import { AIEngineBase } from '@memberjunction/ai-engine-base';
10
- import * as i0 from "@angular/core";
11
- import * as i1 from "@angular/platform-browser";
12
- import * as i2 from "@angular/common";
13
- import * as i3 from "./agent-execution-monitor.component";
14
- import * as i4 from "@angular/forms";
15
- import * as i5 from "@progress/kendo-angular-layout";
16
- import * as i6 from "@progress/kendo-angular-dialog";
17
- import * as i7 from "@progress/kendo-angular-inputs";
18
- import * as i8 from "@progress/kendo-angular-dropdowns";
19
- import * as i9 from "@progress/kendo-angular-buttons";
20
- import * as i10 from "@memberjunction/ng-code-editor";
21
- const _c0 = ["messagesContainer"];
22
- const _c1 = ["fileInput"];
23
- const _c2 = ["messageInput"];
24
- const _c3 = ["saveDialogInput"];
25
- const _forTrack0 = ($index, $item) => $item.id;
26
- const _c4 = () => ({ text: "String", value: "string" });
27
- const _c5 = () => ({ text: "Number", value: "number" });
28
- const _c6 = () => ({ text: "Boolean", value: "boolean" });
29
- const _c7 = () => ({ text: "Object", value: "object" });
30
- const _c8 = (a0, a1, a2, a3) => [a0, a1, a2, a3];
31
- function AITestHarnessComponent_div_0_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
32
- i0.ɵɵelementStart(0, "p");
33
- i0.ɵɵtext(1);
34
- i0.ɵɵelementEnd();
35
- } if (rf & 2) {
36
- const ctx_r1 = i0.ɵɵnextContext(3);
37
- i0.ɵɵadvance();
38
- i0.ɵɵtextInterpolate(ctx_r1.entity.Description);
39
- } }
40
- function AITestHarnessComponent_div_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
41
- const _r1 = i0.ɵɵgetCurrentView();
42
- i0.ɵɵelementStart(0, "div", 10)(1, "div", 14);
43
- i0.ɵɵelement(2, "i", 15);
44
- i0.ɵɵelementStart(3, "div")(4, "h3");
45
- i0.ɵɵtext(5);
46
- i0.ɵɵelementEnd();
47
- i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_2_Conditional_6_Template, 2, 1, "p");
48
- i0.ɵɵelementEnd()();
49
- i0.ɵɵelementStart(7, "div", 16)(8, "button", 17);
50
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearConversation()); });
51
- i0.ɵɵelement(9, "i", 18);
52
- i0.ɵɵtext(10, " Clear ");
53
- i0.ɵɵelementEnd();
54
- i0.ɵɵelementStart(11, "button", 19);
55
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.saveConversation()); });
56
- i0.ɵɵelement(12, "i", 20);
57
- i0.ɵɵtext(13, " Save ");
58
- i0.ɵɵelementEnd();
59
- i0.ɵɵelementStart(14, "button", 21);
60
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.exportConversation()); });
61
- i0.ɵɵelement(15, "i", 22);
62
- i0.ɵɵtext(16, " Export ");
63
- i0.ɵɵelementEnd();
64
- i0.ɵɵelementStart(17, "button", 23);
65
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.importConversation()); });
66
- i0.ɵɵelement(18, "i", 24);
67
- i0.ɵɵtext(19, " Import ");
68
- i0.ɵɵelementEnd();
69
- i0.ɵɵelementStart(20, "input", 25, 0);
70
- i0.ɵɵlistener("change", function AITestHarnessComponent_div_0_Conditional_2_Template_input_change_20_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onFileSelected($event)); });
71
- i0.ɵɵelementEnd();
72
- i0.ɵɵelementStart(22, "button", 26);
73
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_22_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleSidebar()); });
74
- i0.ɵɵelement(23, "i", 15);
75
- i0.ɵɵelementEnd()()();
76
- } if (rf & 2) {
77
- const ctx_r1 = i0.ɵɵnextContext(2);
78
- i0.ɵɵadvance(2);
79
- i0.ɵɵclassProp("fa-robot", ctx_r1.mode === "agent")("fa-comment-dots", ctx_r1.mode === "prompt");
80
- i0.ɵɵadvance(3);
81
- i0.ɵɵtextInterpolate(ctx_r1.getEntityName());
82
- i0.ɵɵadvance();
83
- i0.ɵɵconditional(ctx_r1.entity.Description ? 6 : -1);
84
- i0.ɵɵadvance(2);
85
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting || ctx_r1.conversationMessages.length === 0);
86
- i0.ɵɵadvance(3);
87
- i0.ɵɵproperty("disabled", ctx_r1.conversationMessages.length === 0);
88
- i0.ɵɵadvance(3);
89
- i0.ɵɵproperty("disabled", ctx_r1.conversationMessages.length === 0);
90
- i0.ɵɵadvance(9);
91
- i0.ɵɵclassProp("fa-chevron-right", !ctx_r1.showSidebar)("fa-chevron-left", ctx_r1.showSidebar);
92
- } }
93
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
94
- i0.ɵɵelementStart(0, "div", 29);
95
- i0.ɵɵelement(1, "i", 46);
96
- i0.ɵɵelementStart(2, "h4");
97
- i0.ɵɵtext(3, "Start a conversation");
98
- i0.ɵɵelementEnd();
99
- i0.ɵɵelementStart(4, "p");
100
- i0.ɵɵtext(5, "Send a message to begin testing the AI agent");
101
- i0.ɵɵelementEnd()();
102
- } }
103
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
104
- i0.ɵɵelement(0, "i", 59);
105
- i0.ɵɵtext(1, " You ");
106
- } }
107
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
108
- i0.ɵɵelement(0, "i", 60);
109
- i0.ɵɵtext(1);
110
- } if (rf & 2) {
111
- const ctx_r1 = i0.ɵɵnextContext(4);
112
- i0.ɵɵadvance();
113
- i0.ɵɵtextInterpolate1(" ", ctx_r1.getEntityName() || "Assistant", " ");
114
- } }
115
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template(rf, ctx) { if (rf & 1) {
116
- i0.ɵɵelementStart(0, "span", 50);
117
- i0.ɵɵelement(1, "i", 35);
118
- i0.ɵɵtext(2);
119
- i0.ɵɵelementEnd();
120
- } if (rf & 2) {
121
- const message_r5 = i0.ɵɵnextContext().$implicit;
122
- const ctx_r1 = i0.ɵɵnextContext(3);
123
- i0.ɵɵadvance(2);
124
- i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r5.elapsedTime), " ");
125
- } }
126
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template(rf, ctx) { if (rf & 1) {
127
- i0.ɵɵelementStart(0, "span", 51);
128
- i0.ɵɵtext(1);
129
- i0.ɵɵelementEnd();
130
- } if (rf & 2) {
131
- const message_r5 = i0.ɵɵnextContext().$implicit;
132
- const ctx_r1 = i0.ɵɵnextContext(3);
133
- i0.ɵɵproperty("title", ctx_r1.getExecutionSummary(message_r5));
134
- i0.ɵɵadvance();
135
- i0.ɵɵtextInterpolate(ctx_r1.formatExecutionTime(message_r5.executionTime));
136
- } }
137
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template(rf, ctx) { if (rf & 1) {
138
- const _r6 = i0.ɵɵgetCurrentView();
139
- i0.ɵɵelementStart(0, "button", 61);
140
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const message_r5 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showRawJsonDialog(message_r5)); });
141
- i0.ɵɵelement(1, "i", 62);
142
- i0.ɵɵelementEnd();
143
- } }
144
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Template(rf, ctx) { if (rf & 1) {
145
- i0.ɵɵelementStart(0, "div", 56)(1, "span", 63);
146
- i0.ɵɵtext(2);
147
- i0.ɵɵelementStart(3, "span", 64);
148
- i0.ɵɵtext(4, "|");
149
- i0.ɵɵelementEnd()()();
150
- } if (rf & 2) {
151
- const message_r5 = i0.ɵɵnextContext().$implicit;
152
- i0.ɵɵadvance(2);
153
- i0.ɵɵtextInterpolate(message_r5.streamingContent);
154
- } }
155
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_14_Template(rf, ctx) { if (rf & 1) {
156
- i0.ɵɵelement(0, "div", 57);
157
- } if (rf & 2) {
158
- const message_r5 = i0.ɵɵnextContext().$implicit;
159
- const ctx_r1 = i0.ɵɵnextContext(3);
160
- i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r5), i0.ɵɵsanitizeHtml);
161
- } }
162
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Template(rf, ctx) { if (rf & 1) {
163
- i0.ɵɵelementStart(0, "div", 58);
164
- i0.ɵɵelement(1, "i", 65);
165
- i0.ɵɵtext(2);
166
- i0.ɵɵelementEnd();
167
- } if (rf & 2) {
168
- const message_r5 = i0.ɵɵnextContext().$implicit;
169
- i0.ɵɵadvance(2);
170
- i0.ɵɵtextInterpolate1(" ", message_r5.error, " ");
171
- } }
172
- function AITestHarnessComponent_div_0_Conditional_4_For_7_Template(rf, ctx) { if (rf & 1) {
173
- const _r4 = i0.ɵɵgetCurrentView();
174
- i0.ɵɵelementStart(0, "div", 30)(1, "div", 47)(2, "span", 48);
175
- i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Template, 2, 1);
176
- i0.ɵɵelementEnd();
177
- i0.ɵɵelementStart(5, "span", 49);
178
- i0.ɵɵtext(6);
179
- i0.ɵɵelementEnd();
180
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template, 3, 1, "span", 50)(8, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template, 2, 2, "span", 51)(9, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template, 2, 0, "button", 52);
181
- i0.ɵɵelementEnd();
182
- i0.ɵɵelementStart(10, "div", 53)(11, "button", 54);
183
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_For_7_Template_button_click_11_listener() { const message_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.copyMessage(message_r5)); });
184
- i0.ɵɵelement(12, "i", 55);
185
- i0.ɵɵelementEnd();
186
- i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Template, 5, 1, "div", 56)(14, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_14_Template, 1, 1, "div", 57)(15, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Template, 3, 1, "div", 58);
187
- i0.ɵɵelementEnd()();
188
- } if (rf & 2) {
189
- const message_r5 = ctx.$implicit;
190
- const ctx_r1 = i0.ɵɵnextContext(3);
191
- i0.ɵɵproperty("ngClass", ctx_r1.getMessageClass(message_r5));
192
- i0.ɵɵadvance(3);
193
- i0.ɵɵconditional(message_r5.role === "user" ? 3 : 4);
194
- i0.ɵɵadvance(3);
195
- i0.ɵɵtextInterpolate(ctx_r1.formatTimestamp(message_r5.timestamp));
196
- i0.ɵɵadvance();
197
- i0.ɵɵconditional(message_r5.isStreaming && message_r5.elapsedTime !== undefined ? 7 : message_r5.executionTime ? 8 : -1);
198
- i0.ɵɵadvance(2);
199
- i0.ɵɵconditional(ctx_r1.showRawToggle(message_r5) ? 9 : -1);
200
- i0.ɵɵadvance(4);
201
- i0.ɵɵconditional(message_r5.isStreaming ? 13 : 14);
202
- i0.ɵɵadvance(2);
203
- i0.ɵɵconditional(message_r5.error ? 15 : -1);
204
- } }
205
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_13_Template(rf, ctx) { if (rf & 1) {
206
- i0.ɵɵelement(0, "i", 35);
207
- } }
208
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_14_Template(rf, ctx) { if (rf & 1) {
209
- i0.ɵɵelement(0, "i", 36);
210
- } }
211
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template(rf, ctx) { if (rf & 1) {
212
- const _r7 = i0.ɵɵgetCurrentView();
213
- i0.ɵɵelementStart(0, "button", 40);
214
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("agentVariables")); });
215
- i0.ɵɵelement(1, "i", 62);
216
- i0.ɵɵtext(2, " Agent Variables ");
217
- i0.ɵɵelementEnd();
218
- i0.ɵɵelementStart(3, "button", 66);
219
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("executionMonitor")); });
220
- i0.ɵɵelement(4, "i", 67);
221
- i0.ɵɵtext(5, " Execution Monitor ");
222
- i0.ɵɵelementEnd();
223
- } if (rf & 2) {
224
- const ctx_r1 = i0.ɵɵnextContext(3);
225
- i0.ɵɵclassProp("active", ctx_r1.activeTab === "agentVariables");
226
- i0.ɵɵproperty("disabled", ctx_r1.executionMonitorMode === "live" && ctx_r1.activeTab !== "agentVariables");
227
- i0.ɵɵadvance(3);
228
- i0.ɵɵclassProp("active", ctx_r1.activeTab === "executionMonitor");
229
- } }
230
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template(rf, ctx) { if (rf & 1) {
231
- const _r8 = i0.ɵɵgetCurrentView();
232
- i0.ɵɵelementStart(0, "button", 66);
233
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("templateVariables")); });
234
- i0.ɵɵelement(1, "i", 62);
235
- i0.ɵɵtext(2, " Template Variables ");
236
- i0.ɵɵelementEnd();
237
- i0.ɵɵelementStart(3, "button", 66);
238
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("modelSettings")); });
239
- i0.ɵɵelement(4, "i", 68);
240
- i0.ɵɵtext(5, " Model Settings ");
241
- i0.ɵɵelementEnd();
242
- } if (rf & 2) {
243
- const ctx_r1 = i0.ɵɵnextContext(3);
244
- i0.ɵɵclassProp("active", ctx_r1.activeTab === "templateVariables");
245
- i0.ɵɵadvance(3);
246
- i0.ɵɵclassProp("active", ctx_r1.activeTab === "modelSettings");
247
- } }
248
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template(rf, ctx) { if (rf & 1) {
249
- i0.ɵɵelementStart(0, "span", 42);
250
- i0.ɵɵtext(1);
251
- i0.ɵɵelementEnd();
252
- } if (rf & 2) {
253
- const ctx_r1 = i0.ɵɵnextContext(3);
254
- i0.ɵɵadvance();
255
- i0.ɵɵtextInterpolate(ctx_r1.savedConversations.length);
256
- } }
257
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Conditional_7_Template(rf, ctx) { if (rf & 1) {
258
- i0.ɵɵelementStart(0, "div", 71)(1, "p");
259
- i0.ɵɵtext(2, "No variables defined. Click \"Add Variable\" to get started.");
260
- i0.ɵɵelementEnd()();
261
- } }
262
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template(rf, ctx) { if (rf & 1) {
263
- const _r10 = i0.ɵɵgetCurrentView();
264
- i0.ɵɵelementStart(0, "div", 72)(1, "kendo-textbox", 75);
265
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_textbox_ngModelChange_1_listener($event) { const variable_r11 = i0.ɵɵrestoreView(_r10).$implicit; i0.ɵɵtwoWayBindingSet(variable_r11.name, $event) || (variable_r11.name = $event); return i0.ɵɵresetView($event); });
266
- i0.ɵɵelementEnd();
267
- i0.ɵɵelementStart(2, "kendo-dropdownlist", 76);
268
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { const variable_r11 = i0.ɵɵrestoreView(_r10).$implicit; i0.ɵɵtwoWayBindingSet(variable_r11.type, $event) || (variable_r11.type = $event); return i0.ɵɵresetView($event); });
269
- i0.ɵɵelementEnd();
270
- i0.ɵɵelementStart(3, "kendo-textbox", 77);
271
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_textbox_ngModelChange_3_listener($event) { const variable_r11 = i0.ɵɵrestoreView(_r10).$implicit; i0.ɵɵtwoWayBindingSet(variable_r11.value, $event) || (variable_r11.value = $event); return i0.ɵɵresetView($event); });
272
- i0.ɵɵelementEnd();
273
- i0.ɵɵelementStart(4, "button", 78);
274
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_button_click_4_listener() { const $index_r12 = i0.ɵɵrestoreView(_r10).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeAgentVariable($index_r12)); });
275
- i0.ɵɵelement(5, "i", 79);
276
- i0.ɵɵelementEnd()();
277
- } if (rf & 2) {
278
- const variable_r11 = ctx.$implicit;
279
- const ctx_r1 = i0.ɵɵnextContext(4);
280
- i0.ɵɵadvance();
281
- i0.ɵɵtwoWayProperty("ngModel", variable_r11.name);
282
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
283
- i0.ɵɵadvance();
284
- i0.ɵɵtwoWayProperty("ngModel", variable_r11.type);
285
- i0.ɵɵproperty("data", i0.ɵɵpureFunction4(14, _c8, i0.ɵɵpureFunction0(10, _c4), i0.ɵɵpureFunction0(11, _c5), i0.ɵɵpureFunction0(12, _c6), i0.ɵɵpureFunction0(13, _c7)))("valuePrimitive", true)("disabled", ctx_r1.isExecuting);
286
- i0.ɵɵadvance();
287
- i0.ɵɵtwoWayProperty("ngModel", variable_r11.value);
288
- i0.ɵɵproperty("placeholder", variable_r11.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
289
- i0.ɵɵadvance();
290
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
291
- } }
292
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template(rf, ctx) { if (rf & 1) {
293
- const _r9 = i0.ɵɵgetCurrentView();
294
- i0.ɵɵelementStart(0, "div", 44)(1, "div", 69)(2, "h4");
295
- i0.ɵɵtext(3, "Agent Variables");
296
- i0.ɵɵelementEnd();
297
- i0.ɵɵelementStart(4, "p");
298
- i0.ɵɵtext(5, "Variables available during agent execution and template rendering");
299
- i0.ɵɵelementEnd()();
300
- i0.ɵɵelementStart(6, "div", 70);
301
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Conditional_7_Template, 3, 0, "div", 71);
302
- i0.ɵɵrepeaterCreate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template, 6, 19, "div", 72, i0.ɵɵrepeaterTrackByIndex);
303
- i0.ɵɵelementEnd();
304
- i0.ɵɵelementStart(10, "button", 73);
305
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.addAgentVariable()); });
306
- i0.ɵɵelement(11, "i", 74);
307
- i0.ɵɵtext(12, " Add Variable ");
308
- i0.ɵɵelementEnd()();
309
- } if (rf & 2) {
310
- const ctx_r1 = i0.ɵɵnextContext(3);
311
- i0.ɵɵadvance(7);
312
- i0.ɵɵconditional(ctx_r1.agentVariables.length === 0 ? 7 : -1);
313
- i0.ɵɵadvance();
314
- i0.ɵɵrepeater(ctx_r1.agentVariables);
315
- i0.ɵɵadvance(2);
316
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
317
- } }
318
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template(rf, ctx) { if (rf & 1) {
319
- i0.ɵɵelementStart(0, "div", 45);
320
- i0.ɵɵelement(1, "mj-agent-execution-monitor", 80);
321
- i0.ɵɵelementEnd();
322
- } if (rf & 2) {
323
- const ctx_r1 = i0.ɵɵnextContext(3);
324
- i0.ɵɵadvance();
325
- i0.ɵɵproperty("mode", ctx_r1.executionMonitorMode)("executionData", ctx_r1.currentExecutionData)("autoExpand", true);
326
- } }
327
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template(rf, ctx) { if (rf & 1) {
328
- const _r14 = i0.ɵɵgetCurrentView();
329
- i0.ɵɵelementStart(0, "div", 72)(1, "kendo-textbox", 75);
330
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_textbox_ngModelChange_1_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.name, $event) || (variable_r15.name = $event); return i0.ɵɵresetView($event); });
331
- i0.ɵɵelementEnd();
332
- i0.ɵɵelementStart(2, "kendo-dropdownlist", 76);
333
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.type, $event) || (variable_r15.type = $event); return i0.ɵɵresetView($event); });
334
- i0.ɵɵelementEnd();
335
- i0.ɵɵelementStart(3, "kendo-textbox", 77);
336
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_textbox_ngModelChange_3_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.value, $event) || (variable_r15.value = $event); return i0.ɵɵresetView($event); });
337
- i0.ɵɵelementEnd();
338
- i0.ɵɵelementStart(4, "button", 82);
339
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_button_click_4_listener() { const $index_r16 = i0.ɵɵrestoreView(_r14).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeTemplateVariable($index_r16)); });
340
- i0.ɵɵelement(5, "i", 79);
341
- i0.ɵɵelementEnd()();
342
- } if (rf & 2) {
343
- const variable_r15 = ctx.$implicit;
344
- const ctx_r1 = i0.ɵɵnextContext(4);
345
- i0.ɵɵadvance();
346
- i0.ɵɵtwoWayProperty("ngModel", variable_r15.name);
347
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
348
- i0.ɵɵadvance();
349
- i0.ɵɵtwoWayProperty("ngModel", variable_r15.type);
350
- i0.ɵɵproperty("data", i0.ɵɵpureFunction4(13, _c8, i0.ɵɵpureFunction0(9, _c4), i0.ɵɵpureFunction0(10, _c5), i0.ɵɵpureFunction0(11, _c6), i0.ɵɵpureFunction0(12, _c7)))("valuePrimitive", true)("disabled", ctx_r1.isExecuting);
351
- i0.ɵɵadvance();
352
- i0.ɵɵtwoWayProperty("ngModel", variable_r15.value);
353
- i0.ɵɵproperty("placeholder", variable_r15.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
354
- } }
355
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf, ctx) { if (rf & 1) {
356
- const _r13 = i0.ɵɵgetCurrentView();
357
- i0.ɵɵelementStart(0, "div", 44)(1, "div", 69)(2, "h4");
358
- i0.ɵɵtext(3, "Template Variables");
359
- i0.ɵɵelementEnd();
360
- i0.ɵɵelementStart(4, "p");
361
- i0.ɵɵtext(5, "Variables for prompt template rendering");
362
- i0.ɵɵelementEnd()();
363
- i0.ɵɵelementStart(6, "div", 70);
364
- i0.ɵɵrepeaterCreate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template, 6, 18, "div", 72, i0.ɵɵrepeaterTrackByIndex);
365
- i0.ɵɵelementEnd();
366
- i0.ɵɵelementStart(9, "button", 81);
367
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.addTemplateVariable()); });
368
- i0.ɵɵelement(10, "i", 74);
369
- i0.ɵɵtext(11, " Add Variable ");
370
- i0.ɵɵelementEnd()();
371
- } if (rf & 2) {
372
- const ctx_r1 = i0.ɵɵnextContext(3);
373
- i0.ɵɵadvance(7);
374
- i0.ɵɵrepeater(ctx_r1.templateVariables);
375
- } }
376
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf, ctx) { if (rf & 1) {
377
- const _r17 = i0.ɵɵgetCurrentView();
378
- i0.ɵɵelementStart(0, "div", 44)(1, "div", 69)(2, "h4");
379
- i0.ɵɵtext(3, "Model Settings");
380
- i0.ɵɵelementEnd();
381
- i0.ɵɵelementStart(4, "p");
382
- i0.ɵɵtext(5, "Configure AI model parameters");
383
- i0.ɵɵelementEnd()();
384
- i0.ɵɵelementStart(6, "div", 83)(7, "div", 84)(8, "label");
385
- i0.ɵɵtext(9, "AI Model");
386
- i0.ɵɵelementEnd();
387
- i0.ɵɵelementStart(10, "kendo-dropdownlist", 85);
388
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedModelId, $event) || (ctx_r1.selectedModelId = $event); return i0.ɵɵresetView($event); });
389
- i0.ɵɵelementEnd()();
390
- i0.ɵɵelementStart(11, "div", 84)(12, "label");
391
- i0.ɵɵtext(13);
392
- i0.ɵɵelementEnd();
393
- i0.ɵɵelementStart(14, "kendo-slider", 86);
394
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_slider_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.temperature, $event) || (ctx_r1.temperature = $event); return i0.ɵɵresetView($event); });
395
- i0.ɵɵelementEnd();
396
- i0.ɵɵelementStart(15, "div", 87);
397
- i0.ɵɵtext(16, " Lower values make output more focused and deterministic ");
398
- i0.ɵɵelementEnd()();
399
- i0.ɵɵelementStart(17, "div", 84)(18, "label");
400
- i0.ɵɵtext(19, "Response Format");
401
- i0.ɵɵelementEnd();
402
- i0.ɵɵelementStart(20, "kendo-dropdownlist", 88);
403
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedResponseFormat, $event) || (ctx_r1.selectedResponseFormat = $event); return i0.ɵɵresetView($event); });
404
- i0.ɵɵelementEnd();
405
- i0.ɵɵelementStart(21, "div", 87);
406
- i0.ɵɵtext(22, " Expected format for AI response (defaults to prompt setting) ");
407
- i0.ɵɵelementEnd()();
408
- i0.ɵɵelementStart(23, "div", 84)(24, "label");
409
- i0.ɵɵtext(25, "Max Tokens");
410
- i0.ɵɵelementEnd();
411
- i0.ɵɵelementStart(26, "kendo-numerictextbox", 89);
412
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_26_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.maxTokens, $event) || (ctx_r1.maxTokens = $event); return i0.ɵɵresetView($event); });
413
- i0.ɵɵelementEnd();
414
- i0.ɵɵelementStart(27, "div", 87);
415
- i0.ɵɵtext(28, " Maximum length of generated response ");
416
- i0.ɵɵelementEnd()()()();
417
- } if (rf & 2) {
418
- const ctx_r1 = i0.ɵɵnextContext(3);
419
- i0.ɵɵadvance(10);
420
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedModelId);
421
- i0.ɵɵproperty("data", ctx_r1.availableModels)("valuePrimitive", true);
422
- i0.ɵɵadvance(3);
423
- i0.ɵɵtextInterpolate1("Temperature (", ctx_r1.temperature, ")");
424
- i0.ɵɵadvance();
425
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.temperature);
426
- i0.ɵɵproperty("min", 0)("max", 2)("smallStep", 0.1)("showButtons", false);
427
- i0.ɵɵadvance(6);
428
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedResponseFormat);
429
- i0.ɵɵproperty("data", ctx_r1.responseFormatOptions);
430
- i0.ɵɵadvance(6);
431
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.maxTokens);
432
- i0.ɵɵproperty("min", 100)("max", 8000)("step", 100);
433
- } }
434
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template(rf, ctx) { if (rf & 1) {
435
- const _r18 = i0.ɵɵgetCurrentView();
436
- i0.ɵɵelementStart(0, "button", 94);
437
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.newConversation()); });
438
- i0.ɵɵelement(1, "i", 74);
439
- i0.ɵɵtext(2, " New ");
440
- i0.ɵɵelementEnd();
441
- } }
442
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template(rf, ctx) { if (rf & 1) {
443
- i0.ɵɵelementStart(0, "div", 92);
444
- i0.ɵɵelement(1, "i", 95);
445
- i0.ɵɵelementStart(2, "p");
446
- i0.ɵɵtext(3, "No saved conversations");
447
- i0.ɵɵelementEnd()();
448
- } }
449
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template(rf, ctx) { if (rf & 1) {
450
- const _r19 = i0.ɵɵgetCurrentView();
451
- i0.ɵɵelementStart(0, "div", 96);
452
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template_div_click_0_listener() { const conv_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.loadConversation(conv_r20)); });
453
- i0.ɵɵelementStart(1, "div", 97)(2, "h5");
454
- i0.ɵɵtext(3);
455
- i0.ɵɵelementEnd();
456
- i0.ɵɵelementStart(4, "p");
457
- i0.ɵɵtext(5);
458
- i0.ɵɵelementEnd();
459
- i0.ɵɵelementStart(6, "span", 98);
460
- i0.ɵɵtext(7);
461
- i0.ɵɵpipe(8, "date");
462
- i0.ɵɵelementEnd()();
463
- i0.ɵɵelementStart(9, "button", 99);
464
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template_button_click_9_listener($event) { const conv_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.deleteConversation(conv_r20, $event)); });
465
- i0.ɵɵelement(10, "i", 100);
466
- i0.ɵɵelementEnd()();
467
- } if (rf & 2) {
468
- const conv_r20 = ctx.$implicit;
469
- const ctx_r1 = i0.ɵɵnextContext(4);
470
- i0.ɵɵclassProp("current", conv_r20.id === ctx_r1.currentConversationId);
471
- i0.ɵɵadvance(3);
472
- i0.ɵɵtextInterpolate(conv_r20.name);
473
- i0.ɵɵadvance(2);
474
- i0.ɵɵtextInterpolate1("", conv_r20.messages.length, " messages");
475
- i0.ɵɵadvance(2);
476
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(8, 5, conv_r20.updatedAt, "short"));
477
- } }
478
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template(rf, ctx) { if (rf & 1) {
479
- i0.ɵɵelementStart(0, "div", 44)(1, "div", 69)(2, "h4");
480
- i0.ɵɵtext(3, "Saved Conversations");
481
- i0.ɵɵelementEnd();
482
- i0.ɵɵelementStart(4, "p");
483
- i0.ɵɵtext(5, "Previously saved test sessions");
484
- i0.ɵɵelementEnd();
485
- i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template, 3, 0, "button", 90);
486
- i0.ɵɵelementEnd();
487
- i0.ɵɵelementStart(7, "div", 91);
488
- i0.ɵɵtemplate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template, 4, 0, "div", 92);
489
- i0.ɵɵrepeaterCreate(9, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template, 11, 8, "div", 93, _forTrack0);
490
- i0.ɵɵelementEnd()();
491
- } if (rf & 2) {
492
- const ctx_r1 = i0.ɵɵnextContext(3);
493
- i0.ɵɵadvance(6);
494
- i0.ɵɵconditional(ctx_r1.currentConversationId ? 6 : -1);
495
- i0.ɵɵadvance(2);
496
- i0.ɵɵconditional(ctx_r1.savedConversations.length === 0 ? 8 : -1);
497
- i0.ɵɵadvance();
498
- i0.ɵɵrepeater(ctx_r1.savedConversations);
499
- } }
500
- function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
501
- const _r3 = i0.ɵɵgetCurrentView();
502
- i0.ɵɵelementStart(0, "kendo-splitter", 12)(1, "kendo-splitter-pane", 27)(2, "div", 13)(3, "div", 28, 1);
503
- i0.ɵɵtemplate(5, AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template, 6, 0, "div", 29);
504
- i0.ɵɵrepeaterCreate(6, AITestHarnessComponent_div_0_Conditional_4_For_7_Template, 16, 7, "div", 30, _forTrack0);
505
- i0.ɵɵelementEnd();
506
- i0.ɵɵelementStart(8, "div", 31)(9, "div", 32)(10, "kendo-textarea", 33, 2);
507
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Template_kendo_textarea_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
508
- i0.ɵɵlistener("keypress", function AITestHarnessComponent_div_0_Conditional_4_Template_kendo_textarea_keypress_10_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
509
- i0.ɵɵelementEnd();
510
- i0.ɵɵelementStart(12, "button", 34);
511
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
512
- i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_Conditional_13_Template, 1, 0, "i", 35)(14, AITestHarnessComponent_div_0_Conditional_4_Conditional_14_Template, 1, 0, "i", 36);
513
- i0.ɵɵelementEnd()()()()();
514
- i0.ɵɵelementStart(15, "kendo-splitter-pane", 37)(16, "div", 38)(17, "div", 39);
515
- i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template, 6, 5)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template, 6, 4);
516
- i0.ɵɵelementStart(20, "button", 40);
517
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.selectTab("savedConversations")); });
518
- i0.ɵɵelement(21, "i", 41);
519
- i0.ɵɵtext(22, " Saved ");
520
- i0.ɵɵtemplate(23, AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template, 2, 1, "span", 42);
521
- i0.ɵɵelementEnd()();
522
- i0.ɵɵelementStart(24, "div", 43);
523
- i0.ɵɵtemplate(25, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template, 13, 2, "div", 44)(26, AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template, 2, 3, "div", 45)(27, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template, 12, 0, "div", 44)(28, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template, 29, 15, "div", 44)(29, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template, 11, 2, "div", 44);
524
- i0.ɵɵelementEnd()()()();
525
- } if (rf & 2) {
526
- const ctx_r1 = i0.ɵɵnextContext(2);
527
- i0.ɵɵadvance();
528
- i0.ɵɵproperty("collapsible", false)("resizable", true)("min", "400px");
529
- i0.ɵɵadvance(4);
530
- i0.ɵɵconditional(ctx_r1.conversationMessages.length === 0 ? 5 : -1);
531
- i0.ɵɵadvance();
532
- i0.ɵɵrepeater(ctx_r1.conversationMessages);
533
- i0.ɵɵadvance(4);
534
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.currentUserMessage);
535
- i0.ɵɵproperty("rows", 3)("disabled", ctx_r1.isExecuting);
536
- i0.ɵɵadvance(2);
537
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting || !ctx_r1.currentUserMessage.trim());
538
- i0.ɵɵadvance();
539
- i0.ɵɵconditional(ctx_r1.isExecuting ? 13 : 14);
540
- i0.ɵɵadvance(2);
541
- i0.ɵɵproperty("collapsible", false)("resizable", true)("size", "30%")("min", "300px");
542
- i0.ɵɵadvance(3);
543
- i0.ɵɵconditional(ctx_r1.mode === "agent" ? 18 : 19);
544
- i0.ɵɵadvance(2);
545
- i0.ɵɵclassProp("active", ctx_r1.activeTab === "savedConversations");
546
- i0.ɵɵproperty("disabled", ctx_r1.executionMonitorMode === "live" && ctx_r1.activeTab !== "savedConversations");
547
- i0.ɵɵadvance(3);
548
- i0.ɵɵconditional(ctx_r1.savedConversations.length > 0 ? 23 : -1);
549
- i0.ɵɵadvance(2);
550
- i0.ɵɵconditional(ctx_r1.activeTab === "agentVariables" ? 25 : -1);
551
- i0.ɵɵadvance();
552
- i0.ɵɵconditional(ctx_r1.activeTab === "executionMonitor" ? 26 : -1);
553
- i0.ɵɵadvance();
554
- i0.ɵɵconditional(ctx_r1.activeTab === "templateVariables" ? 27 : -1);
555
- i0.ɵɵadvance();
556
- i0.ɵɵconditional(ctx_r1.activeTab === "modelSettings" ? 28 : -1);
557
- i0.ɵɵadvance();
558
- i0.ɵɵconditional(ctx_r1.activeTab === "savedConversations" ? 29 : -1);
559
- } }
560
- function AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
561
- i0.ɵɵelementStart(0, "div", 29);
562
- i0.ɵɵelement(1, "i", 46);
563
- i0.ɵɵelementStart(2, "h4");
564
- i0.ɵɵtext(3, "Start a conversation");
565
- i0.ɵɵelementEnd();
566
- i0.ɵɵelementStart(4, "p");
567
- i0.ɵɵtext(5, "Send a message to begin testing the AI agent");
568
- i0.ɵɵelementEnd()();
569
- } }
570
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
571
- i0.ɵɵelement(0, "i", 59);
572
- i0.ɵɵtext(1, " You ");
573
- } }
574
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
575
- i0.ɵɵelement(0, "i", 60);
576
- i0.ɵɵtext(1);
577
- } if (rf & 2) {
578
- const ctx_r1 = i0.ɵɵnextContext(4);
579
- i0.ɵɵadvance();
580
- i0.ɵɵtextInterpolate1(" ", ctx_r1.getEntityName() || "Assistant", " ");
581
- } }
582
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template(rf, ctx) { if (rf & 1) {
583
- i0.ɵɵelementStart(0, "span", 50);
584
- i0.ɵɵelement(1, "i", 35);
585
- i0.ɵɵtext(2);
586
- i0.ɵɵelementEnd();
587
- } if (rf & 2) {
588
- const message_r23 = i0.ɵɵnextContext().$implicit;
589
- const ctx_r1 = i0.ɵɵnextContext(3);
590
- i0.ɵɵadvance(2);
591
- i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r23.elapsedTime), " ");
592
- } }
593
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template(rf, ctx) { if (rf & 1) {
594
- i0.ɵɵelementStart(0, "span", 51);
595
- i0.ɵɵtext(1);
596
- i0.ɵɵelementEnd();
597
- } if (rf & 2) {
598
- const message_r23 = i0.ɵɵnextContext().$implicit;
599
- const ctx_r1 = i0.ɵɵnextContext(3);
600
- i0.ɵɵproperty("title", ctx_r1.getExecutionSummary(message_r23));
601
- i0.ɵɵadvance();
602
- i0.ɵɵtextInterpolate(ctx_r1.formatExecutionTime(message_r23.executionTime));
603
- } }
604
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template(rf, ctx) { if (rf & 1) {
605
- const _r24 = i0.ɵɵgetCurrentView();
606
- i0.ɵɵelementStart(0, "button", 61);
607
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r24); const message_r23 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showRawJsonDialog(message_r23)); });
608
- i0.ɵɵelement(1, "i", 62);
609
- i0.ɵɵelementEnd();
610
- } }
611
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template(rf, ctx) { if (rf & 1) {
612
- const _r25 = i0.ɵɵgetCurrentView();
613
- i0.ɵɵelementStart(0, "button", 102);
614
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r25); const message_r23 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showMessageExecutionHistory(message_r23)); });
615
- i0.ɵɵelement(1, "i", 67);
616
- i0.ɵɵelementEnd();
617
- } }
618
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_14_Template(rf, ctx) { if (rf & 1) {
619
- i0.ɵɵelementStart(0, "div", 56)(1, "span", 63);
620
- i0.ɵɵtext(2);
621
- i0.ɵɵelementStart(3, "span", 64);
622
- i0.ɵɵtext(4, "|");
623
- i0.ɵɵelementEnd()()();
624
- } if (rf & 2) {
625
- const message_r23 = i0.ɵɵnextContext().$implicit;
626
- i0.ɵɵadvance(2);
627
- i0.ɵɵtextInterpolate(message_r23.streamingContent);
628
- } }
629
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template(rf, ctx) { if (rf & 1) {
630
- i0.ɵɵelement(0, "div", 57);
631
- } if (rf & 2) {
632
- const message_r23 = i0.ɵɵnextContext().$implicit;
633
- const ctx_r1 = i0.ɵɵnextContext(3);
634
- i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r23), i0.ɵɵsanitizeHtml);
635
- } }
636
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template(rf, ctx) { if (rf & 1) {
637
- i0.ɵɵelementStart(0, "div", 58);
638
- i0.ɵɵelement(1, "i", 65);
639
- i0.ɵɵtext(2);
640
- i0.ɵɵelementEnd();
641
- } if (rf & 2) {
642
- const message_r23 = i0.ɵɵnextContext().$implicit;
643
- i0.ɵɵadvance(2);
644
- i0.ɵɵtextInterpolate1(" ", message_r23.error, " ");
645
- } }
646
- function AITestHarnessComponent_div_0_Conditional_5_For_5_Template(rf, ctx) { if (rf & 1) {
647
- const _r22 = i0.ɵɵgetCurrentView();
648
- i0.ɵɵelementStart(0, "div", 30)(1, "div", 47)(2, "span", 48);
649
- i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template, 2, 1);
650
- i0.ɵɵelementEnd();
651
- i0.ɵɵelementStart(5, "span", 49);
652
- i0.ɵɵtext(6);
653
- i0.ɵɵelementEnd();
654
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template, 3, 1, "span", 50)(8, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template, 2, 2, "span", 51)(9, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template, 2, 0, "button", 52)(10, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template, 2, 0, "button", 101);
655
- i0.ɵɵelementEnd();
656
- i0.ɵɵelementStart(11, "div", 53)(12, "button", 54);
657
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Template_button_click_12_listener() { const message_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.copyMessage(message_r23)); });
658
- i0.ɵɵelement(13, "i", 55);
659
- i0.ɵɵelementEnd();
660
- i0.ɵɵtemplate(14, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_14_Template, 5, 1, "div", 56)(15, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template, 1, 1, "div", 57)(16, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template, 3, 1, "div", 58);
661
- i0.ɵɵelementEnd()();
662
- } if (rf & 2) {
663
- const message_r23 = ctx.$implicit;
664
- const ctx_r1 = i0.ɵɵnextContext(3);
665
- i0.ɵɵproperty("ngClass", ctx_r1.getMessageClass(message_r23));
666
- i0.ɵɵadvance(3);
667
- i0.ɵɵconditional(message_r23.role === "user" ? 3 : 4);
668
- i0.ɵɵadvance(3);
669
- i0.ɵɵtextInterpolate(ctx_r1.formatTimestamp(message_r23.timestamp));
670
- i0.ɵɵadvance();
671
- i0.ɵɵconditional(message_r23.isStreaming && message_r23.elapsedTime !== undefined ? 7 : message_r23.executionTime ? 8 : -1);
672
- i0.ɵɵadvance(2);
673
- i0.ɵɵconditional(ctx_r1.showRawToggle(message_r23) ? 9 : -1);
674
- i0.ɵɵadvance();
675
- i0.ɵɵconditional(message_r23.executionData && ctx_r1.mode === "agent" && message_r23.role === "assistant" ? 10 : -1);
676
- i0.ɵɵadvance(4);
677
- i0.ɵɵconditional(message_r23.isStreaming ? 14 : 15);
678
- i0.ɵɵadvance(2);
679
- i0.ɵɵconditional(message_r23.error ? 16 : -1);
680
- } }
681
- function AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
682
- i0.ɵɵelement(0, "i", 35);
683
- } }
684
- function AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template(rf, ctx) { if (rf & 1) {
685
- i0.ɵɵelement(0, "i", 36);
686
- } }
687
- function AITestHarnessComponent_div_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
688
- const _r21 = i0.ɵɵgetCurrentView();
689
- i0.ɵɵelementStart(0, "div", 13)(1, "div", 28, 1);
690
- i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template, 6, 0, "div", 29);
691
- i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Template, 17, 8, "div", 30, _forTrack0);
692
- i0.ɵɵelementEnd();
693
- i0.ɵɵelementStart(6, "div", 31)(7, "div", 32)(8, "kendo-textarea", 33, 2);
694
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
695
- i0.ɵɵlistener("keypress", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_keypress_8_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
696
- i0.ɵɵelementEnd();
697
- i0.ɵɵelementStart(10, "button", 34);
698
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
699
- i0.ɵɵtemplate(11, AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template, 1, 0, "i", 35)(12, AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template, 1, 0, "i", 36);
700
- i0.ɵɵelementEnd()()()();
701
- } if (rf & 2) {
702
- const ctx_r1 = i0.ɵɵnextContext(2);
703
- i0.ɵɵadvance(3);
704
- i0.ɵɵconditional(ctx_r1.conversationMessages.length === 0 ? 3 : -1);
705
- i0.ɵɵadvance();
706
- i0.ɵɵrepeater(ctx_r1.conversationMessages);
707
- i0.ɵɵadvance(4);
708
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.currentUserMessage);
709
- i0.ɵɵproperty("rows", 3)("disabled", ctx_r1.isExecuting);
710
- i0.ɵɵadvance(2);
711
- i0.ɵɵproperty("disabled", ctx_r1.isExecuting || !ctx_r1.currentUserMessage.trim());
712
- i0.ɵɵadvance();
713
- i0.ɵɵconditional(ctx_r1.isExecuting ? 11 : 12);
714
- } }
715
- function AITestHarnessComponent_div_0_Template(rf, ctx) { if (rf & 1) {
716
- i0.ɵɵelementStart(0, "div", 8)(1, "div", 9);
717
- i0.ɵɵtemplate(2, AITestHarnessComponent_div_0_Conditional_2_Template, 24, 13, "div", 10);
718
- i0.ɵɵelementEnd();
719
- i0.ɵɵelementStart(3, "div", 11);
720
- i0.ɵɵtemplate(4, AITestHarnessComponent_div_0_Conditional_4_Template, 30, 23, "kendo-splitter", 12)(5, AITestHarnessComponent_div_0_Conditional_5_Template, 13, 6, "div", 13);
721
- i0.ɵɵelementEnd()();
722
- } if (rf & 2) {
723
- const ctx_r1 = i0.ɵɵnextContext();
724
- i0.ɵɵadvance(2);
725
- i0.ɵɵconditional(ctx_r1.entity ? 2 : -1);
726
- i0.ɵɵadvance(2);
727
- i0.ɵɵconditional(ctx_r1.showSidebar ? 4 : 5);
728
- } }
729
- function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
730
- const _r26 = i0.ɵɵgetCurrentView();
731
- i0.ɵɵelementStart(0, "kendo-dialog", 103);
732
- i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_1_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
733
- i0.ɵɵelementStart(1, "div", 104)(2, "p");
734
- i0.ɵɵtext(3, "Enter a name for this conversation:");
735
- i0.ɵɵelementEnd();
736
- i0.ɵɵelementStart(4, "input", 105, 3);
737
- i0.ɵɵlistener("keyup", function AITestHarnessComponent_Conditional_1_Template_input_keyup_4_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateTempConversation()); });
738
- i0.ɵɵelementEnd()();
739
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 106);
740
- i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
741
- i0.ɵɵtext(8, "Cancel");
742
- i0.ɵɵelementEnd();
743
- i0.ɵɵelementStart(9, "button", 107);
744
- i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmSaveConversation()); });
745
- i0.ɵɵtext(10, " Save ");
746
- i0.ɵɵelementEnd()()();
747
- } if (rf & 2) {
748
- const ctx_r1 = i0.ɵɵnextContext();
749
- i0.ɵɵproperty("title", "Save Conversation")("width", 400);
750
- i0.ɵɵadvance(9);
751
- i0.ɵɵproperty("primary", true)("disabled", ctx_r1.tempConversationName === "");
752
- } }
753
- function AITestHarnessComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
754
- const _r27 = i0.ɵɵgetCurrentView();
755
- i0.ɵɵelementStart(0, "kendo-dialog", 108);
756
- i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_2_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
757
- i0.ɵɵelementStart(1, "div", 104)(2, "p");
758
- i0.ɵɵtext(3, "Loading this conversation will replace the current one. Any unsaved changes will be lost.");
759
- i0.ɵɵelementEnd();
760
- i0.ɵɵelementStart(4, "p");
761
- i0.ɵɵtext(5, "Do you want to continue?");
762
- i0.ɵɵelementEnd()();
763
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 106);
764
- i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
765
- i0.ɵɵtext(8, "Cancel");
766
- i0.ɵɵelementEnd();
767
- i0.ɵɵelementStart(9, "button", 109);
768
- i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmLoadConversation()); });
769
- i0.ɵɵtext(10, " Load Conversation ");
770
- i0.ɵɵelementEnd()()();
771
- } if (rf & 2) {
772
- i0.ɵɵproperty("title", "Replace Current Conversation?")("width", 400);
773
- i0.ɵɵadvance(9);
774
- i0.ɵɵproperty("primary", true);
775
- } }
776
- function AITestHarnessComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
777
- const _r28 = i0.ɵɵgetCurrentView();
778
- i0.ɵɵelementStart(0, "kendo-window", 110);
779
- i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_3_Template_kendo_window_close_0_listener() { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeJsonDialog()); });
780
- i0.ɵɵelementStart(1, "div", 111)(2, "div", 112)(3, "button", 113);
781
- i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_3_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.copyJsonContent()); });
782
- i0.ɵɵelement(4, "i", 55);
783
- i0.ɵɵelementEnd()();
784
- i0.ɵɵelementStart(5, "div", 114)(6, "mj-code-editor", 115);
785
- i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_3_Template_mj_code_editor_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.currentJsonContent, $event) || (ctx_r1.currentJsonContent = $event); return i0.ɵɵresetView($event); });
786
- i0.ɵɵelementEnd()()()();
787
- } if (rf & 2) {
788
- const ctx_r1 = i0.ɵɵnextContext();
789
- i0.ɵɵproperty("title", "Raw JSON Response")("width", 900)("height", 700)("minWidth", 600)("minHeight", 400)("resizable", true)("draggable", true)("state", "default")("keepContent", true);
790
- i0.ɵɵadvance(6);
791
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.currentJsonContent);
792
- i0.ɵɵproperty("readonly", true)("language", "json")("lineWrapping", true);
793
- } }
794
- /**
795
- * Comprehensive test harness component for AI Agent development and testing.
796
- * Provides a full-featured chat interface with conversation management, data context configuration,
797
- * template data management, streaming responses, conversation persistence, and import/export capabilities.
798
- *
799
- * ## Key Features:
800
- * - **Interactive Chat**: Real-time conversation with AI agents
801
- * - **Streaming Support**: Live streaming of agent responses with elapsed time tracking
802
- * - **Data Context Management**: Configure variables passed to agent during execution
803
- * - **Template Data Management**: Manage template variables for agent prompts
804
- * - **Conversation Persistence**: Save/load conversations with full state restoration
805
- * - **Import/Export**: JSON-based conversation backup and sharing
806
- * - **Content Formatting**: Automatic detection and rendering of Markdown, JSON, and plain text
807
- * - **Raw Content Toggle**: View both processed and raw AI responses
808
- * - **Error Handling**: Comprehensive error display and user feedback
809
- *
810
- * ## Usage:
811
- * ```html
812
- * <mj-ai-agent-test-harness
813
- * [aiAgent]="myAgent"
814
- * [isVisible]="true"
815
- * (visibilityChange)="onVisibilityChanged($event)">
816
- * </mj-ai-agent-test-harness>
817
- * ```
818
- *
819
- * @example
820
- * ```typescript
821
- * // Using with agent entity
822
- * const agent = await metadata.GetEntityObject<AIAgentEntity>('AI Agents');
823
- * await agent.Load('agent-id');
824
- * this.testHarness.aiAgent = agent;
825
- * this.testHarness.isVisible = true;
826
- * ```
827
- */
828
- export class AITestHarnessComponent {
829
- /**
830
- * Creates a new AI Test Harness component instance.
831
- * @param sanitizer - Angular DomSanitizer for safe HTML rendering of formatted content
832
- */
833
- constructor(sanitizer) {
834
- this.sanitizer = sanitizer;
835
- /** The mode of operation - either 'agent' or 'prompt' */
836
- this.mode = 'agent';
837
- /** The entity to test - either an AI Agent or AI Prompt */
838
- this.entity = null;
839
- this._isVisible = false;
840
- /** Event emitted when the visibility state changes, allowing parent components to react */
841
- this.visibilityChange = new EventEmitter();
842
- // === Conversation State ===
843
- /** Complete array of all messages in the current conversation session */
844
- this.conversationMessages = [];
845
- /** Current text input by the user (bound to textarea) */
846
- this.currentUserMessage = '';
847
- /** Whether an agent execution is currently in progress */
848
- this.isExecuting = false;
849
- // === Data Context Management ===
850
- /** Unified variables for agent execution (combines data context and template data) */
851
- this.agentVariables = [];
852
- // === Prompt-specific properties ===
853
- /** Variables for prompt template rendering */
854
- this.templateVariables = [];
855
- /** Selected AI model for prompt execution */
856
- this.selectedModelId = '';
857
- /** Temperature setting for prompt execution */
858
- this.temperature = 0.7;
859
- /** Maximum tokens for prompt execution */
860
- this.maxTokens = null;
861
- /** Available AI models for prompt execution */
862
- this.availableModels = [];
863
- /** Selected response format for prompt execution */
864
- this.selectedResponseFormat = 'Any';
865
- /** Available response format options */
866
- this.responseFormatOptions = [
867
- { text: 'Any', value: 'Any' },
868
- { text: 'Text', value: 'Text' },
869
- { text: 'Markdown', value: 'Markdown' },
870
- { text: 'JSON', value: 'JSON' },
871
- { text: 'Model Specific', value: 'ModelSpecific' }
872
- ];
873
- // === UI State Management ===
874
- /** Whether the configuration sidebar is currently visible */
875
- this.showSidebar = true;
876
- /** Currently active tab in the sidebar */
877
- this.activeTab = 'agentVariables';
878
- /** Array of saved conversation sessions loaded from localStorage */
879
- this.savedConversations = [];
880
- /** ID of the currently active/loaded conversation, if any */
881
- this.currentConversationId = null;
882
- /** Flag to control JSON dialog visibility */
883
- this.showJsonDialog = false;
884
- /** Current JSON content to display in the dialog */
885
- this.currentJsonContent = '';
886
- // === Execution Monitor Properties ===
887
- /** Mode for the execution monitor component */
888
- this.executionMonitorMode = 'historical';
889
- /** Current execution data for the monitor */
890
- this.currentExecutionData = null;
891
- /** Agent conversation state tracking */
892
- this.agentConversationState = null;
893
- this.lastAgentReturnValue = null;
894
- this.subAgentHistory = [];
895
- /** Whether to show the save conversation dialog */
896
- this.showSaveDialog = false;
897
- /** Name for the new conversation being saved */
898
- this.newConversationName = '';
899
- /** Temporary name for the dialog input to avoid binding conflicts */
900
- this.tempConversationName = '';
901
- /** Whether to show the load confirmation dialog */
902
- this.showLoadConfirmDialog = false;
903
- /** Conversation pending to be loaded */
904
- this.pendingLoadConversation = null;
905
- /** Reference to the current message for JSON display */
906
- this.currentJsonMessage = null;
907
- // === Private State & Intervals ===
908
- /** Subject for component destruction cleanup */
909
- this.destroy$ = new Subject();
910
- /** Flag indicating that auto-scroll is needed on next view check */
911
- this.scrollNeeded = false;
912
- /** MemberJunction metadata instance for entity operations */
913
- this._metadata = new Metadata();
914
- /** Track if input has been focused to prevent repeated focusing */
915
- this._hasFocused = false;
916
- }
917
- /** @deprecated Use 'entity' instead. Kept for backward compatibility. */
918
- get aiAgent() {
919
- return this.isAgentEntity(this.entity) ? this.entity : null;
920
- }
921
- set aiAgent(value) {
922
- this.entity = value;
923
- if (value) {
924
- this.mode = 'agent';
925
- }
926
- }
927
- /**
928
- * Controls the visibility of the test harness. When set to true, automatically resets the harness state.
929
- * This property is typically controlled by parent components or dialog wrappers.
930
- */
931
- get isVisible() {
932
- return this._isVisible;
933
- }
934
- set isVisible(value) {
935
- const wasVisible = this._isVisible;
936
- this._isVisible = value;
937
- if (value && !wasVisible) {
938
- this.resetHarness();
939
- }
940
- }
941
- /**
942
- * Component initialization. Loads saved conversations, sets up event subscriptions,
943
- * and initializes the harness to a clean state.
944
- */
945
- ngOnInit() {
946
- // Ensure we have an entity
947
- if (!this.entity && this.aiAgent) {
948
- // Handle backward compatibility
949
- this.entity = this.aiAgent;
950
- this.mode = 'agent';
951
- }
952
- this.loadSavedConversations();
953
- this.subscribeToEvents();
954
- this.resetHarness();
955
- // Load models if in prompt mode
956
- if (this.mode === 'prompt') {
957
- this.loadAvailableModels();
958
- }
959
- }
960
- /**
961
- * Responds to input property changes, particularly when entity is set/changed
962
- */
963
- ngOnChanges(changes) {
964
- if (changes['entity']) {
965
- if (changes['entity'].currentValue) {
966
- this.loadSavedConversations();
967
- }
968
- }
969
- if (changes['aiAgent']) {
970
- if (!this.entity && this.aiAgent) {
971
- this.entity = this.aiAgent;
972
- this.mode = 'agent';
973
- this.loadSavedConversations();
974
- }
975
- }
976
- if (changes['isVisible']) {
977
- if (changes['isVisible'].currentValue) {
978
- // Reset focus flag when dialog becomes visible
979
- this._hasFocused = false;
980
- }
981
- }
982
- }
983
- /**
984
- * Component cleanup. Destroys subscriptions and clears any active intervals
985
- * to prevent memory leaks.
986
- */
987
- ngOnDestroy() {
988
- this.destroy$.next();
989
- this.destroy$.complete();
990
- if (this.elapsedTimeInterval) {
991
- clearInterval(this.elapsedTimeInterval);
992
- }
993
- if (this._mjGlobalEventSub) {
994
- this._mjGlobalEventSub.unsubscribe();
995
- }
996
- if (this._agentStreamSub) {
997
- this._agentStreamSub.unsubscribe();
998
- }
999
- }
1000
- /**
1001
- * Post-view check hook that handles auto-scrolling to the bottom of the message container
1002
- * when new content is added.
1003
- */
1004
- ngAfterViewChecked() {
1005
- if (this.scrollNeeded) {
1006
- this.scrollToBottom();
1007
- this.scrollNeeded = false;
1008
- }
1009
- // Auto-focus message input when dialog first becomes visible
1010
- if (this.isVisible && !this._hasFocused && this.messageInput) {
1011
- this._hasFocused = true;
1012
- setTimeout(() => {
1013
- this.messageInput?.focus();
1014
- }, 100);
1015
- }
1016
- }
1017
- subscribeToEvents() {
1018
- // Set up direct GraphQL subscription for agent execution stream
1019
- const dataProvider = Metadata.Provider;
1020
- const _providerPushStatusSub = dataProvider.PushStatusUpdates().subscribe((status) => {
1021
- const message = JSON.parse(status.message || '{}');
1022
- if (message?.resolver === 'RunAIAgentResolver') {
1023
- // Handle different types of streaming messages
1024
- if (message?.type === 'ExecutionProgress' && message.data?.progress) {
1025
- const userMsg = message.data.progress.message;
1026
- // Update streaming message content
1027
- const streamingMessage = this.conversationMessages.find(m => m.isStreaming);
1028
- if (streamingMessage) {
1029
- // Clear any typing animation interval
1030
- const typingInterval = streamingMessage._typingInterval;
1031
- if (typingInterval) {
1032
- clearInterval(typingInterval);
1033
- delete streamingMessage._typingInterval;
1034
- }
1035
- // Update the streaming content with the status message
1036
- streamingMessage.streamingContent = userMsg;
1037
- this.scrollNeeded = true;
1038
- }
1039
- // Update execution monitor with live progress
1040
- if (!this.currentExecutionData) {
1041
- this.currentExecutionData = { liveSteps: [] };
1042
- }
1043
- this.executionMonitorMode = 'live';
1044
- // Add or update the current step in the execution tree
1045
- const stepInfo = {
1046
- step: {
1047
- ID: `temp-${Date.now()}`,
1048
- StepName: userMsg,
1049
- StepType: message.data.progress.step || 'unknown',
1050
- Status: 'Running',
1051
- StartedAt: new Date()
1052
- },
1053
- executionType: message.data.progress.step || 'unknown',
1054
- agentHierarchy: message.data.progress.agentHierarchy || [],
1055
- depth: message.data.progress.depth || 0,
1056
- startTime: new Date()
1057
- };
1058
- // For live mode, we'll append steps as they come
1059
- if (!this.currentExecutionData.liveSteps) {
1060
- this.currentExecutionData.liveSteps = [];
1061
- }
1062
- this.currentExecutionData.liveSteps.push(stepInfo);
1063
- // Trigger change detection for the monitor
1064
- this.currentExecutionData = { ...this.currentExecutionData };
1065
- }
1066
- else if (message?.type === 'StreamingContent' && message.data?.streaming) {
1067
- const streamingMessage = this.conversationMessages.find(m => m.isStreaming);
1068
- if (streamingMessage) {
1069
- // Append streaming content
1070
- if (!streamingMessage.streamingContent) {
1071
- streamingMessage.streamingContent = '';
1072
- }
1073
- streamingMessage.streamingContent = message.data.streaming.content;
1074
- this.scrollNeeded = true;
1075
- }
1076
- }
1077
- else if (message?.type === 'partial_result' && message.data?.partialResult) {
1078
- // Could update execution monitor with partial results
1079
- }
1080
- else if (message?.type === 'complete') {
1081
- // Switch execution monitor to historical mode with final data
1082
- this.executionMonitorMode = 'historical';
1083
- }
1084
- }
1085
- });
1086
- }
1087
- /**
1088
- * Loads available AI models for prompt execution.
1089
- * Only called when the harness is in prompt mode.
1090
- */
1091
- async loadAvailableModels() {
1092
- await AIEngineBase.Instance.Config(false);
1093
- // Filter models by the prompt's AIModelTypeID if it exists
1094
- let filteredModels = [];
1095
- if (this.entity && 'AIModelTypeID' in this.entity) {
1096
- const prompt = this.entity;
1097
- if (prompt.AIModelTypeID) {
1098
- filteredModels = AIEngineBase.Instance.Models.filter(model => model.AIModelTypeID === prompt.AIModelTypeID && model.IsActive);
1099
- }
1100
- else {
1101
- // No model type restriction, show all active models
1102
- filteredModels = AIEngineBase.Instance.Models.filter(model => model.IsActive);
1103
- }
1104
- // Set default response format from prompt with slight delay for Kendo dropdown
1105
- setTimeout(() => {
1106
- this.selectedResponseFormat = prompt.ResponseFormat || 'Any';
1107
- }, 0);
1108
- }
1109
- else {
1110
- // Not a prompt entity, show all active models
1111
- filteredModels = AIEngineBase.Instance.Models.filter(model => model.IsActive);
1112
- }
1113
- // Add a blank option at the beginning
1114
- this.availableModels = [
1115
- { ID: '', Name: '-- Use Default Model --' },
1116
- ...filteredModels
1117
- ];
1118
- // Don't auto-select a model - let the dropdown show the blank option
1119
- this.selectedModelId = '';
1120
- }
1121
- /**
1122
- * Resets the test harness to its initial state, clearing all conversations,
1123
- * variables, and UI state. Called automatically when the harness becomes visible.
1124
- */
1125
- resetHarness() {
1126
- this.conversationMessages = [];
1127
- this.currentUserMessage = '';
1128
- this.isExecuting = false;
1129
- this.agentVariables = [{ name: '', value: '', type: 'string' }];
1130
- this.templateVariables = [];
1131
- this.currentConversationId = null;
1132
- this.showSidebar = true;
1133
- this.currentExecutionData = null;
1134
- this.executionMonitorMode = 'historical';
1135
- // Reset conversation state
1136
- this.agentConversationState = null;
1137
- this.lastAgentReturnValue = null;
1138
- this.subAgentHistory = [];
1139
- // Set default tab based on mode
1140
- this.activeTab = this.mode === 'agent' ? 'agentVariables' : 'templateVariables';
1141
- }
1142
- /**
1143
- * Starts a new conversation
1144
- */
1145
- newConversation() {
1146
- if (this.conversationMessages.length > 0 && !this.currentConversationId) {
1147
- // Unsaved conversation exists - use our custom dialog
1148
- if (confirm('You have an unsaved conversation. Would you like to save it first?')) {
1149
- this.saveConversation();
1150
- return;
1151
- }
1152
- }
1153
- this.resetHarness();
1154
- MJNotificationService.Instance.CreateSimpleNotification('Started new conversation', 'info', 2000);
1155
- }
1156
- /**
1157
- * Closes the test harness by setting visibility to false and emitting the change event.
1158
- * Used by dialog implementations and close buttons.
1159
- */
1160
- close() {
1161
- this._isVisible = false;
1162
- this.visibilityChange.emit(false);
1163
- }
1164
- /**
1165
- * Toggles the visibility of the configuration sidebar.
1166
- * Allows users to show/hide the data context and conversation management panels.
1167
- */
1168
- toggleSidebar() {
1169
- this.showSidebar = !this.showSidebar;
1170
- }
1171
- /**
1172
- * Switches to the specified tab in the configuration sidebar.
1173
- * @param tab - The tab to activate
1174
- */
1175
- selectTab(tab) {
1176
- this.activeTab = tab;
1177
- // If switching to execution monitor tab, ensure it has the latest data
1178
- if (tab === 'executionMonitor' && this.conversationMessages.length > 0) {
1179
- const lastAssistantMessage = this.conversationMessages
1180
- .filter(m => m.role === 'assistant' && m.executionData)
1181
- .pop();
1182
- if (lastAssistantMessage && lastAssistantMessage.executionData) {
1183
- this.currentExecutionData = lastAssistantMessage.executionData;
1184
- this.executionMonitorMode = 'historical';
1185
- }
1186
- }
1187
- }
1188
- /**
1189
- * Shows the execution history for a specific message
1190
- * @param message - The message to show execution history for
1191
- */
1192
- showMessageExecutionHistory(message) {
1193
- if (message.executionData && this.mode === 'agent') {
1194
- this.currentExecutionData = message.executionData;
1195
- this.executionMonitorMode = 'historical';
1196
- // Switch to execution monitor tab if not already there
1197
- if (this.activeTab !== 'executionMonitor') {
1198
- this.selectTab('executionMonitor');
1199
- }
1200
- }
1201
- }
1202
- /**
1203
- * Extract sub-agent nodes from execution tree
1204
- */
1205
- extractSubAgentNodes(executionTree) {
1206
- const subAgentNodes = [];
1207
- const traverse = (nodes) => {
1208
- for (const node of nodes) {
1209
- if (node.executionType === 'sub-agent') {
1210
- subAgentNodes.push({
1211
- agentName: node.step?.StepName,
1212
- result: node.outputData,
1213
- timestamp: node.endTime || node.startTime
1214
- });
1215
- }
1216
- if (node.children) {
1217
- traverse(node.children);
1218
- }
1219
- }
1220
- };
1221
- traverse(executionTree);
1222
- return subAgentNodes;
1223
- }
1224
- /**
1225
- * Sends the current user message to the AI agent and initiates execution.
1226
- * Handles message validation, conversation updates, UI state management, and agent execution.
1227
- * Automatically clears the input field and triggers auto-scroll after sending.
1228
- *
1229
- * @example
1230
- * ```typescript
1231
- * // Called when user presses Enter or clicks Send button
1232
- * await this.sendMessage();
1233
- * ```
1234
- */
1235
- async sendMessage() {
1236
- if (!this.currentUserMessage.trim() || !this.entity) {
1237
- return;
1238
- }
1239
- // Add user message to conversation
1240
- const userMessage = {
1241
- id: this.generateMessageId(),
1242
- role: 'user',
1243
- content: this.currentUserMessage.trim(),
1244
- timestamp: new Date()
1245
- };
1246
- this.conversationMessages.push(userMessage);
1247
- // Clear input after change detection to avoid ExpressionChangedAfterItHasBeenCheckedError
1248
- const messageToSend = this.currentUserMessage;
1249
- setTimeout(() => {
1250
- this.currentUserMessage = '';
1251
- }, 0);
1252
- // Scroll to bottom
1253
- this.scrollNeeded = true;
1254
- // Auto-switch to execution monitor tab if in agent mode
1255
- if (this.mode === 'agent' && this.activeTab !== 'executionMonitor') {
1256
- this.selectTab('executionMonitor');
1257
- }
1258
- // Execute based on mode
1259
- if (this.mode === 'agent') {
1260
- await this.executeAgent(messageToSend);
1261
- }
1262
- else {
1263
- await this.executePrompt(messageToSend);
1264
- }
1265
- }
1266
- async executeAgent(userMessage) {
1267
- if (!this.entity || !this.isAgentEntity(this.entity))
1268
- return;
1269
- this.isExecuting = true;
1270
- // Clear previous execution data when starting a new run
1271
- this.currentExecutionData = { liveSteps: [] };
1272
- this.executionMonitorMode = 'live';
1273
- // Add placeholder assistant message for streaming
1274
- const assistantMessage = {
1275
- id: this.generateMessageId(),
1276
- role: 'assistant',
1277
- content: '',
1278
- timestamp: new Date(),
1279
- isStreaming: true,
1280
- streamingContent: '',
1281
- agentRunId: '',
1282
- streamingStartTime: Date.now(),
1283
- elapsedTime: 0
1284
- };
1285
- this.conversationMessages.push(assistantMessage);
1286
- this.scrollNeeded = true;
1287
- // Start elapsed time counter
1288
- this.startElapsedTimeCounter(assistantMessage);
1289
- // Initialize execution monitor for live mode
1290
- this.currentExecutionData = { liveSteps: [] };
1291
- this.executionMonitorMode = 'live';
1292
- try {
1293
- // Get GraphQL data provider
1294
- const dataProvider = Metadata.Provider;
1295
- // Build conversation history for context
1296
- const messages = this.conversationMessages
1297
- .filter(m => !m.isStreaming)
1298
- .map(m => ({
1299
- role: m.role,
1300
- content: m.content
1301
- }));
1302
- // Build data context - include conversation state if available
1303
- const dataContext = this.buildDataContext();
1304
- const templateData = this.buildTemplateData();
1305
- // Add conversation state to data context if we have it
1306
- if (this.agentConversationState) {
1307
- dataContext._conversationState = this.agentConversationState;
1308
- }
1309
- if (this.lastAgentReturnValue) {
1310
- dataContext._lastReturnValue = this.lastAgentReturnValue;
1311
- }
1312
- if (this.subAgentHistory.length > 0) {
1313
- dataContext._subAgentHistory = this.subAgentHistory;
1314
- }
1315
- // Generate a session ID for this execution
1316
- const sessionId = dataProvider.sessionId;
1317
- // DEBUG: Log authentication context and request details
1318
- const authToken = dataProvider._authToken || window.localStorage?.getItem('mj-auth-token');
1319
- if (!authToken) {
1320
- console.warn('🔐 AI Test Harness: No authentication token found in dataProvider or localStorage');
1321
- }
1322
- else {
1323
- }
1324
- // Execute the agent
1325
- const query = `
1326
- mutation RunAIAgent($agentId: String!, $messages: String!, $sessionId: String!, $data: String, $templateData: String) {
1327
- RunAIAgent(agentId: $agentId, messages: $messages, sessionId: $sessionId, data: $data, templateData: $templateData) {
1328
- success
1329
- errorMessage
1330
- executionTimeMs
1331
- payload
1332
- }
1333
- }
1334
- `;
1335
- const variables = {
1336
- agentId: this.entity.ID,
1337
- messages: JSON.stringify(messages),
1338
- sessionId: sessionId,
1339
- data: Object.keys(dataContext).length > 0 ? JSON.stringify(dataContext) : null,
1340
- templateData: Object.keys(templateData).length > 0 ? JSON.stringify(templateData) : null
1341
- };
1342
- // Start typing animation while we wait for the first real stream
1343
- this.startTypingAnimation(assistantMessage);
1344
- let result;
1345
- try {
1346
- result = await dataProvider.ExecuteGQL(query, variables);
1347
- }
1348
- catch (gqlError) {
1349
- console.error('❌ AI Test Harness: GraphQL execution failed', {
1350
- error: gqlError,
1351
- message: gqlError?.message,
1352
- networkError: gqlError?.networkError,
1353
- graphQLErrors: gqlError?.graphQLErrors,
1354
- statusCode: gqlError?.networkError?.statusCode
1355
- });
1356
- throw gqlError;
1357
- }
1358
- const executionResult = result?.RunAIAgent;
1359
- // Stop elapsed time counter
1360
- if (this.elapsedTimeInterval) {
1361
- clearInterval(this.elapsedTimeInterval);
1362
- this.elapsedTimeInterval = null;
1363
- }
1364
- // Update assistant message with result
1365
- assistantMessage.isStreaming = false;
1366
- if (executionResult?.success) {
1367
- // Parse the payload to get the full execution result
1368
- const fullResult = JSON.parse(executionResult.payload);
1369
- // Store execution data with the message
1370
- assistantMessage.executionData = fullResult;
1371
- // Merge live steps with final result if needed
1372
- if (this.currentExecutionData && this.currentExecutionData.liveSteps && fullResult) {
1373
- // Preserve the live steps we collected during execution
1374
- fullResult.liveSteps = this.currentExecutionData.liveSteps;
1375
- }
1376
- // Update execution monitor with the new data
1377
- this.currentExecutionData = fullResult;
1378
- this.executionMonitorMode = 'historical';
1379
- // Preserve conversation state from the result
1380
- if (fullResult.returnValue) {
1381
- this.lastAgentReturnValue = fullResult.returnValue;
1382
- // Extract conversation state if present
1383
- if (fullResult.returnValue.conversationState) {
1384
- this.agentConversationState = fullResult.returnValue.conversationState;
1385
- }
1386
- // Track sub-agent executions
1387
- if (fullResult.executionTree) {
1388
- const subAgentNodes = this.extractSubAgentNodes(fullResult.executionTree);
1389
- if (subAgentNodes.length > 0) {
1390
- this.subAgentHistory.push(...subAgentNodes);
1391
- }
1392
- }
1393
- }
1394
- // Extract the user message from the nested returnValue structure
1395
- let displayContent = 'No response generated';
1396
- if (fullResult.returnValue) {
1397
- if (typeof fullResult.returnValue === 'object' &&
1398
- fullResult.returnValue.nextStep?.userMessage) {
1399
- // This is the expected structure for chat responses
1400
- displayContent = fullResult.returnValue.nextStep.userMessage;
1401
- }
1402
- else if (typeof fullResult.returnValue === 'string') {
1403
- // Simple string response
1404
- displayContent = fullResult.returnValue;
1405
- }
1406
- else {
1407
- // Other structured response - show as JSON
1408
- displayContent = JSON.stringify(fullResult.returnValue, null, 2);
1409
- }
1410
- }
1411
- assistantMessage.content = displayContent;
1412
- assistantMessage.executionTime = executionResult.executionTimeMs;
1413
- assistantMessage.agentRunId = fullResult.agentRun?.ID || assistantMessage.agentRunId;
1414
- // Store the full result as raw content for debugging/inspection
1415
- assistantMessage.rawContent = executionResult.payload;
1416
- }
1417
- else {
1418
- console.error('❌ AI Test Harness: Execution failed', {
1419
- success: executionResult?.success,
1420
- errorMessage: executionResult?.errorMessage,
1421
- hasPayload: !!executionResult?.payload
1422
- });
1423
- assistantMessage.content = 'I encountered an error processing your request.';
1424
- assistantMessage.error = executionResult?.errorMessage || 'Unknown error occurred';
1425
- // Try to parse error payload if available
1426
- if (executionResult?.payload) {
1427
- try {
1428
- JSON.parse(executionResult.payload); // Validate it's valid JSON
1429
- assistantMessage.rawContent = executionResult.payload;
1430
- }
1431
- catch {
1432
- // Ignore parse errors
1433
- }
1434
- }
1435
- }
1436
- delete assistantMessage.streamingContent;
1437
- this.scrollNeeded = true;
1438
- // Auto-save conversation
1439
- this.autoSaveConversation();
1440
- }
1441
- catch (error) {
1442
- console.error('❌ AI Test Harness: Caught error during agent execution', {
1443
- error: error,
1444
- message: error?.message,
1445
- stack: error?.stack,
1446
- type: error?.constructor?.name
1447
- });
1448
- // Update assistant message with error
1449
- const lastMessage = this.conversationMessages[this.conversationMessages.length - 1];
1450
- if (lastMessage && lastMessage.role === 'assistant') {
1451
- lastMessage.isStreaming = false;
1452
- lastMessage.content = 'I encountered an error processing your request.';
1453
- lastMessage.error = error.message;
1454
- delete lastMessage.streamingContent;
1455
- }
1456
- MJNotificationService.Instance.CreateSimpleNotification('Failed to execute agent: ' + error.message, 'error', 6000);
1457
- }
1458
- finally {
1459
- this.isExecuting = false;
1460
- if (this.elapsedTimeInterval) {
1461
- clearInterval(this.elapsedTimeInterval);
1462
- this.elapsedTimeInterval = null;
1463
- }
1464
- // Focus back on the input
1465
- this.focusMessageInput();
1466
- }
1467
- }
1468
- async executePrompt(userMessage) {
1469
- if (!this.entity || !this.isPromptEntity(this.entity))
1470
- return;
1471
- this.isExecuting = true;
1472
- // Add placeholder assistant message for streaming
1473
- const assistantMessage = {
1474
- id: this.generateMessageId(),
1475
- role: 'assistant',
1476
- content: '',
1477
- timestamp: new Date(),
1478
- isStreaming: true,
1479
- streamingContent: '',
1480
- agentRunId: '',
1481
- streamingStartTime: Date.now(),
1482
- elapsedTime: 0
1483
- };
1484
- this.conversationMessages.push(assistantMessage);
1485
- this.scrollNeeded = true;
1486
- // Start elapsed time counter
1487
- this.startElapsedTimeCounter(assistantMessage);
1488
- try {
1489
- // Get GraphQL data provider
1490
- const dataProvider = Metadata.Provider;
1491
- // Build template variables from user input
1492
- const templateVariables = this.buildTemplateVariables();
1493
- // Prepare data context (template variables + user message)
1494
- const dataContext = {
1495
- ...templateVariables,
1496
- userMessage: userMessage
1497
- };
1498
- // Execute the prompt using RunAIPrompt
1499
- const query = `
1500
- mutation RunAIPrompt($promptId: String!, $data: String, $modelId: String, $vendorId: String, $configurationId: String, $skipValidation: Boolean, $templateData: String, $responseFormat: String) {
1501
- RunAIPrompt(promptId: $promptId, data: $data, modelId: $modelId, vendorId: $vendorId, configurationId: $configurationId, skipValidation: $skipValidation, templateData: $templateData, responseFormat: $responseFormat) {
1502
- success
1503
- output
1504
- parsedResult
1505
- error
1506
- executionTimeMs
1507
- tokensUsed
1508
- promptRunId
1509
- rawResult
1510
- validationResult
1511
- }
1512
- }
1513
- `;
1514
- const variables = {
1515
- promptId: this.entity.ID,
1516
- data: JSON.stringify(dataContext),
1517
- modelId: this.selectedModelId || undefined,
1518
- vendorId: undefined, // Use model's default vendor
1519
- configurationId: undefined, // Use default configuration
1520
- skipValidation: false,
1521
- templateData: null, // Additional template context if needed
1522
- responseFormat: this.selectedResponseFormat || undefined
1523
- };
1524
- const result = await dataProvider.ExecuteGQL(query, variables);
1525
- const executionResult = result?.RunAIPrompt;
1526
- // Stop elapsed time counter
1527
- if (this.elapsedTimeInterval) {
1528
- clearInterval(this.elapsedTimeInterval);
1529
- this.elapsedTimeInterval = null;
1530
- }
1531
- // Update assistant message with result
1532
- assistantMessage.isStreaming = false;
1533
- if (executionResult?.success) {
1534
- // Use parsedResult if available, otherwise fall back to output
1535
- assistantMessage.content = executionResult.parsedResult || executionResult.output || 'No response generated';
1536
- assistantMessage.executionTime = executionResult.executionTimeMs;
1537
- // Store raw result and metadata
1538
- assistantMessage.rawContent = executionResult.rawResult || executionResult.output || '';
1539
- // Store execution metadata
1540
- if (executionResult.promptRunId || executionResult.tokensUsed) {
1541
- assistantMessage.agentRunId = executionResult.promptRunId;
1542
- // Store additional metadata in a structured format
1543
- const metadata = {
1544
- promptRunId: executionResult.promptRunId,
1545
- tokensUsed: executionResult.tokensUsed,
1546
- modelId: this.selectedModelId,
1547
- validationResult: executionResult.validationResult
1548
- };
1549
- // If rawContent is JSON, try to merge metadata
1550
- if (assistantMessage.rawContent) {
1551
- try {
1552
- const rawJson = JSON.parse(assistantMessage.rawContent);
1553
- assistantMessage.rawContent = JSON.stringify({ ...rawJson, _metadata: metadata }, null, 2);
1554
- }
1555
- catch {
1556
- // If not JSON, store metadata separately
1557
- assistantMessage.rawContent = JSON.stringify(metadata, null, 2);
1558
- }
1559
- }
1560
- else {
1561
- assistantMessage.rawContent = JSON.stringify(metadata, null, 2);
1562
- }
1563
- }
1564
- }
1565
- else {
1566
- assistantMessage.content = 'I encountered an error processing your request.';
1567
- assistantMessage.error = executionResult?.error || 'Unknown error occurred';
1568
- }
1569
- delete assistantMessage.streamingContent;
1570
- this.scrollNeeded = true;
1571
- // Auto-save conversation
1572
- this.autoSaveConversation();
1573
- // Focus back on input
1574
- this.focusMessageInput();
1575
- }
1576
- catch (error) {
1577
- // Update assistant message with error
1578
- const lastMessage = this.conversationMessages[this.conversationMessages.length - 1];
1579
- if (lastMessage && lastMessage.role === 'assistant') {
1580
- lastMessage.isStreaming = false;
1581
- lastMessage.content = 'I encountered an error processing your request.';
1582
- lastMessage.error = error.message;
1583
- delete lastMessage.streamingContent;
1584
- }
1585
- MJNotificationService.Instance.CreateSimpleNotification('Failed to execute prompt: ' + error.message, 'error', 6000);
1586
- }
1587
- finally {
1588
- this.isExecuting = false;
1589
- if (this.elapsedTimeInterval) {
1590
- clearInterval(this.elapsedTimeInterval);
1591
- this.elapsedTimeInterval = null;
1592
- }
1593
- // Focus back on the input
1594
- this.focusMessageInput();
1595
- }
1596
- }
1597
- startTypingAnimation(message) {
1598
- const initialMessages = [
1599
- "I'm processing your request...",
1600
- "Let me think about that...",
1601
- "Working on your request...",
1602
- "Analyzing your question...",
1603
- "Processing..."
1604
- ];
1605
- const selectedMessage = initialMessages[Math.floor(Math.random() * initialMessages.length)];
1606
- let index = 0;
1607
- // Store the interval handle on the message itself so we can cancel it when real streaming starts
1608
- const typingInterval = setInterval(() => {
1609
- if (index < selectedMessage.length && message.isStreaming) {
1610
- message.streamingContent = selectedMessage.substring(0, index + 1);
1611
- index++;
1612
- this.scrollNeeded = true;
1613
- }
1614
- else {
1615
- clearInterval(typingInterval);
1616
- }
1617
- }, 50);
1618
- // Store interval reference in case we need to clear it
1619
- message._typingInterval = typingInterval;
1620
- }
1621
- buildDataContext() {
1622
- const context = {};
1623
- // Use unified agent variables
1624
- for (const variable of this.agentVariables) {
1625
- if (variable.name.trim()) {
1626
- context[variable.name] = this.convertVariableValue(variable.value, variable.type);
1627
- }
1628
- }
1629
- return context;
1630
- }
1631
- buildTemplateData() {
1632
- // For backward compatibility, return the same data as buildDataContext
1633
- // since we've unified the variables
1634
- return this.buildDataContext();
1635
- }
1636
- buildTemplateVariables() {
1637
- const variables = {};
1638
- for (const variable of this.templateVariables) {
1639
- if (variable.name.trim()) {
1640
- variables[variable.name] = this.convertVariableValue(variable.value, variable.type);
1641
- }
1642
- }
1643
- return variables;
1644
- }
1645
- convertVariableValue(value, type) {
1646
- switch (type) {
1647
- case 'number':
1648
- return parseFloat(value) || 0;
1649
- case 'boolean':
1650
- return value.toLowerCase() === 'true';
1651
- case 'object':
1652
- try {
1653
- return JSON.parse(value);
1654
- }
1655
- catch {
1656
- return value;
1657
- }
1658
- default:
1659
- return value;
1660
- }
1661
- }
1662
- /**
1663
- * Adds a new empty agent variable to the collection.
1664
- * Agent variables are passed to the agent during execution for dynamic content and template rendering.
1665
- */
1666
- addAgentVariable() {
1667
- this.agentVariables.push({
1668
- name: '',
1669
- value: '',
1670
- type: 'string'
1671
- });
1672
- }
1673
- /**
1674
- * Removes an agent variable at the specified index.
1675
- * @param index - Zero-based index of the variable to remove
1676
- */
1677
- removeAgentVariable(index) {
1678
- this.agentVariables.splice(index, 1);
1679
- }
1680
- /**
1681
- * Adds a new empty template variable to the collection (prompt mode only).
1682
- * Template variables are used for prompt template rendering.
1683
- */
1684
- addTemplateVariable() {
1685
- this.templateVariables.push({
1686
- name: '',
1687
- value: '',
1688
- type: 'string'
1689
- });
1690
- }
1691
- /**
1692
- * Removes a template variable at the specified index (prompt mode only).
1693
- * @param index - Zero-based index of the variable to remove
1694
- */
1695
- removeTemplateVariable(index) {
1696
- this.templateVariables.splice(index, 1);
1697
- }
1698
- /**
1699
- * Clears the current conversation after user confirmation.
1700
- * Resets both the message history and the current conversation ID.
1701
- */
1702
- clearConversation() {
1703
- if (this.conversationMessages.length > 0) {
1704
- if (confirm('Are you sure you want to clear the conversation?')) {
1705
- this.conversationMessages = [];
1706
- this.currentConversationId = null;
1707
- }
1708
- }
1709
- }
1710
- scrollToBottom() {
1711
- try {
1712
- if (this.messagesContainer) {
1713
- this.messagesContainer.nativeElement.scrollTop = this.messagesContainer.nativeElement.scrollHeight;
1714
- }
1715
- }
1716
- catch (err) {
1717
- // Error scrolling to bottom
1718
- }
1719
- }
1720
- generateMessageId() {
1721
- return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1722
- }
1723
- // Saved conversations functionality
1724
- loadSavedConversations() {
1725
- try {
1726
- const storageKey = this.getStorageKey();
1727
- const saved = localStorage.getItem(storageKey);
1728
- if (saved) {
1729
- const parsedData = JSON.parse(saved);
1730
- this.savedConversations = parsedData || [];
1731
- // Convert date strings back to Date objects
1732
- this.savedConversations.forEach(conv => {
1733
- conv.createdAt = new Date(conv.createdAt);
1734
- conv.updatedAt = new Date(conv.updatedAt);
1735
- conv.messages.forEach(msg => {
1736
- msg.timestamp = new Date(msg.timestamp);
1737
- });
1738
- });
1739
- }
1740
- else {
1741
- this.savedConversations = [];
1742
- }
1743
- }
1744
- catch (error) {
1745
- // Error loading saved conversations
1746
- this.savedConversations = [];
1747
- }
1748
- }
1749
- /**
1750
- * Gets the storage key for saved conversations based on entity type and ID
1751
- */
1752
- getStorageKey() {
1753
- if (!this.entity) {
1754
- return '';
1755
- }
1756
- const entityType = this.mode === 'agent' ? 'agent' : 'prompt';
1757
- const entityId = this.entity.ID || 'unknown';
1758
- return `mj_test_harness_${entityType}_${entityId}_conversations`;
1759
- }
1760
- /**
1761
- * Saves the current conversation to localStorage with user-provided name.
1762
- * Handles both creating new conversations and updating existing ones.
1763
- * Automatically limits storage to 50 conversations to prevent excessive memory usage.
1764
- *
1765
- * @example
1766
- * ```typescript
1767
- * // User clicks save button
1768
- * this.saveConversation(); // Prompts for name and saves
1769
- * ```
1770
- */
1771
- saveConversation() {
1772
- if (this.conversationMessages.length === 0) {
1773
- MJNotificationService.Instance.CreateSimpleNotification('No messages to save', 'warning', 3000);
1774
- return;
1775
- }
1776
- // If updating existing conversation, pre-fill the name
1777
- if (this.currentConversationId) {
1778
- const currentConv = this.savedConversations.find(c => c.id === this.currentConversationId);
1779
- this.tempConversationName = currentConv ? currentConv.name : '';
1780
- }
1781
- else {
1782
- this.tempConversationName = '';
1783
- }
1784
- this.showSaveDialog = true;
1785
- // Focus on input after dialog renders
1786
- setTimeout(() => {
1787
- if (this.saveDialogInput && this.saveDialogInput.nativeElement) {
1788
- const input = this.saveDialogInput.nativeElement;
1789
- input.focus();
1790
- input.select();
1791
- }
1792
- }, 100);
1793
- }
1794
- updateTempConversation() {
1795
- this.tempConversationName = this.saveDialogInput?.nativeElement.value.trim() || '';
1796
- }
1797
- /**
1798
- * Handles the save dialog confirmation
1799
- */
1800
- confirmSaveConversation() {
1801
- // Use the temp name from the input
1802
- const convoName = this.saveDialogInput?.nativeElement.value;
1803
- const trimmedName = convoName?.trim() || '';
1804
- if (!trimmedName) {
1805
- return;
1806
- }
1807
- this.newConversationName = trimmedName;
1808
- const conversation = {
1809
- id: this.generateMessageId(),
1810
- name: this.newConversationName.trim(),
1811
- agentId: this.entity?.ID || '',
1812
- agentName: this.getEntityName() || '',
1813
- messages: [...this.conversationMessages],
1814
- dataContext: this.buildDataContext(),
1815
- templateData: this.mode === 'agent' ? this.buildTemplateData() : {},
1816
- templateVariables: this.mode === 'prompt' ? this.buildTemplateVariables() : {},
1817
- createdAt: new Date(),
1818
- updatedAt: new Date()
1819
- };
1820
- if (this.currentConversationId) {
1821
- // Update existing conversation
1822
- const index = this.savedConversations.findIndex(c => c.id === this.currentConversationId);
1823
- if (index >= 0) {
1824
- conversation.id = this.currentConversationId;
1825
- conversation.createdAt = this.savedConversations[index].createdAt;
1826
- conversation.name = this.newConversationName.trim(); // Use the edited name
1827
- this.savedConversations[index] = conversation;
1828
- }
1829
- else {
1830
- // Current ID not found, treat as new
1831
- this.savedConversations.unshift(conversation);
1832
- this.currentConversationId = conversation.id;
1833
- }
1834
- }
1835
- else {
1836
- // Add new conversation
1837
- this.savedConversations.unshift(conversation);
1838
- this.currentConversationId = conversation.id;
1839
- }
1840
- // Limit to 50 saved conversations
1841
- if (this.savedConversations.length > 50) {
1842
- this.savedConversations = this.savedConversations.slice(0, 50);
1843
- }
1844
- // Save to localStorage
1845
- this.saveConversationsToStorage();
1846
- MJNotificationService.Instance.CreateSimpleNotification('Conversation saved successfully', 'success', 3000);
1847
- this.showSaveDialog = false;
1848
- this.newConversationName = '';
1849
- this.tempConversationName = '';
1850
- }
1851
- /**
1852
- * Cancels the save dialog
1853
- */
1854
- cancelSaveDialog() {
1855
- this.showSaveDialog = false;
1856
- this.newConversationName = '';
1857
- this.tempConversationName = '';
1858
- }
1859
- // Removed debug methods - no longer needed with ngModel binding
1860
- /**
1861
- * Saves conversations to localStorage
1862
- */
1863
- saveConversationsToStorage() {
1864
- try {
1865
- const storageKey = this.getStorageKey();
1866
- localStorage.setItem(storageKey, JSON.stringify(this.savedConversations));
1867
- }
1868
- catch (error) {
1869
- // Error saving conversations
1870
- throw error;
1871
- }
1872
- }
1873
- autoSaveConversation() {
1874
- if (this.currentConversationId && this.conversationMessages.length > 0) {
1875
- const index = this.savedConversations.findIndex(c => c.id === this.currentConversationId);
1876
- if (index >= 0) {
1877
- this.savedConversations[index].messages = [...this.conversationMessages];
1878
- this.savedConversations[index].dataContext = this.buildDataContext();
1879
- if (this.mode === 'agent') {
1880
- this.savedConversations[index].templateData = this.buildTemplateData();
1881
- }
1882
- else {
1883
- this.savedConversations[index].templateVariables = this.buildTemplateVariables();
1884
- }
1885
- this.savedConversations[index].updatedAt = new Date();
1886
- // Save to localStorage
1887
- try {
1888
- this.saveConversationsToStorage();
1889
- }
1890
- catch (error) {
1891
- // Error auto-saving conversation
1892
- }
1893
- }
1894
- }
1895
- }
1896
- loadConversation(conversation) {
1897
- if (this.conversationMessages.length > 0) {
1898
- this.pendingLoadConversation = conversation;
1899
- this.showLoadConfirmDialog = true;
1900
- return;
1901
- }
1902
- this.doLoadConversation(conversation);
1903
- }
1904
- /**
1905
- * Confirms loading a conversation after dialog confirmation
1906
- */
1907
- confirmLoadConversation() {
1908
- if (this.pendingLoadConversation) {
1909
- this.doLoadConversation(this.pendingLoadConversation);
1910
- this.showLoadConfirmDialog = false;
1911
- this.pendingLoadConversation = null;
1912
- }
1913
- }
1914
- /**
1915
- * Cancels loading a conversation
1916
- */
1917
- cancelLoadConversation() {
1918
- this.showLoadConfirmDialog = false;
1919
- this.pendingLoadConversation = null;
1920
- }
1921
- /**
1922
- * Actually loads the conversation
1923
- */
1924
- doLoadConversation(conversation) {
1925
- this.conversationMessages = [...conversation.messages];
1926
- this.currentConversationId = conversation.id;
1927
- // Restore agent variables (unified from dataContext and templateData)
1928
- this.agentVariables = [];
1929
- const allVariables = { ...conversation.dataContext, ...(conversation.templateData || {}) };
1930
- for (const [key, value] of Object.entries(allVariables)) {
1931
- this.agentVariables.push({
1932
- name: key,
1933
- value: typeof value === 'object' ? JSON.stringify(value) : String(value),
1934
- type: typeof value === 'boolean' ? 'boolean' :
1935
- typeof value === 'number' ? 'number' :
1936
- typeof value === 'object' ? 'object' : 'string'
1937
- });
1938
- }
1939
- // Restore template variables for prompt mode
1940
- if (this.mode === 'prompt') {
1941
- this.templateVariables = [];
1942
- for (const [key, value] of Object.entries(conversation.templateVariables || {})) {
1943
- this.templateVariables.push({
1944
- name: key,
1945
- value: typeof value === 'object' ? JSON.stringify(value) : String(value),
1946
- type: typeof value === 'boolean' ? 'boolean' :
1947
- typeof value === 'number' ? 'number' :
1948
- typeof value === 'object' ? 'object' : 'string'
1949
- });
1950
- }
1951
- }
1952
- // Load execution data from the last assistant message if available
1953
- const lastAssistantMessage = this.conversationMessages
1954
- .filter(m => m.role === 'assistant' && m.executionData)
1955
- .pop();
1956
- if (lastAssistantMessage && lastAssistantMessage.executionData) {
1957
- this.currentExecutionData = lastAssistantMessage.executionData;
1958
- this.executionMonitorMode = 'historical';
1959
- // If execution monitor tab is active, ensure it updates
1960
- if (this.activeTab === 'executionMonitor') {
1961
- // Force change detection
1962
- setTimeout(() => {
1963
- this.currentExecutionData = { ...lastAssistantMessage.executionData };
1964
- }, 0);
1965
- }
1966
- }
1967
- else {
1968
- // Clear execution data if no execution found
1969
- this.currentExecutionData = null;
1970
- this.executionMonitorMode = 'historical';
1971
- }
1972
- this.scrollNeeded = true;
1973
- MJNotificationService.Instance.CreateSimpleNotification('Conversation loaded', 'info', 3000);
1974
- }
1975
- async deleteConversation(conversation, event) {
1976
- event.stopPropagation();
1977
- if (confirm(`Delete conversation "${conversation.name}"?`)) {
1978
- const index = this.savedConversations.findIndex(c => c.id === conversation.id);
1979
- if (index >= 0) {
1980
- this.savedConversations.splice(index, 1);
1981
- // Save to localStorage
1982
- this.saveConversationsToStorage();
1983
- if (this.currentConversationId === conversation.id) {
1984
- this.currentConversationId = null;
1985
- }
1986
- MJNotificationService.Instance.CreateSimpleNotification('Conversation deleted', 'info', 3000);
1987
- }
1988
- }
1989
- }
1990
- exportConversation() {
1991
- if (this.conversationMessages.length === 0) {
1992
- MJNotificationService.Instance.CreateSimpleNotification('No messages to export', 'warning', 3000);
1993
- return;
1994
- }
1995
- const exportData = {
1996
- entity: {
1997
- id: this.entity?.ID,
1998
- name: this.getEntityName(),
1999
- type: this.mode
2000
- },
2001
- messages: this.conversationMessages,
2002
- dataContext: this.buildDataContext(),
2003
- exportedAt: new Date().toISOString()
2004
- };
2005
- // Add mode-specific data
2006
- if (this.mode === 'agent') {
2007
- exportData.templateData = this.buildTemplateData();
2008
- }
2009
- else {
2010
- exportData.templateVariables = this.buildTemplateVariables();
2011
- exportData.modelSettings = {
2012
- modelId: this.selectedModelId,
2013
- temperature: this.temperature,
2014
- maxTokens: this.maxTokens
2015
- };
2016
- }
2017
- const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
2018
- const url = window.URL.createObjectURL(blob);
2019
- const link = document.createElement('a');
2020
- link.href = url;
2021
- const entityName = this.getEntityName()?.replace(/[^a-zA-Z0-9]/g, '-') || 'conversation';
2022
- link.download = `${this.mode}-conversation-${entityName}-${new Date().toISOString().slice(0, 10)}.json`;
2023
- link.click();
2024
- window.URL.revokeObjectURL(url);
2025
- }
2026
- importConversation() {
2027
- this.fileInput.nativeElement.click();
2028
- }
2029
- onFileSelected(event) {
2030
- const input = event.target;
2031
- if (input.files && input.files[0]) {
2032
- const file = input.files[0];
2033
- const reader = new FileReader();
2034
- reader.onload = (e) => {
2035
- try {
2036
- const data = JSON.parse(e.target?.result);
2037
- // Validate and import
2038
- if (data.messages && Array.isArray(data.messages)) {
2039
- if (this.conversationMessages.length > 0) {
2040
- if (!confirm('Importing will replace the current conversation. Continue?')) {
2041
- return;
2042
- }
2043
- }
2044
- this.conversationMessages = data.messages.map((msg) => ({
2045
- ...msg,
2046
- timestamp: new Date(msg.timestamp)
2047
- }));
2048
- // Import agent variables (unified from dataContext and templateData)
2049
- this.agentVariables = [];
2050
- const importedVariables = { ...(data.dataContext || {}), ...(data.templateData || {}) };
2051
- for (const [key, value] of Object.entries(importedVariables)) {
2052
- this.agentVariables.push({
2053
- name: key,
2054
- value: typeof value === 'object' ? JSON.stringify(value) : String(value),
2055
- type: typeof value === 'boolean' ? 'boolean' :
2056
- typeof value === 'number' ? 'number' :
2057
- typeof value === 'object' ? 'object' : 'string'
2058
- });
2059
- }
2060
- // Template data is already imported into agentVariables above
2061
- this.currentConversationId = null;
2062
- this.scrollNeeded = true;
2063
- MJNotificationService.Instance.CreateSimpleNotification('Conversation imported successfully', 'success', 3000);
2064
- }
2065
- else {
2066
- throw new Error('Invalid conversation format');
2067
- }
2068
- }
2069
- catch (error) {
2070
- MJNotificationService.Instance.CreateSimpleNotification('Failed to import conversation: ' + error.message, 'error', 5000);
2071
- }
2072
- // Reset file input
2073
- input.value = '';
2074
- };
2075
- reader.readAsText(file);
2076
- }
2077
- }
2078
- /**
2079
- * Handles keyboard input in the message textarea.
2080
- * Sends message on Enter (without Shift) and allows multi-line input with Shift+Enter.
2081
- * @param event - Keyboard event from the textarea
2082
- */
2083
- handleKeyPress(event) {
2084
- if (event.key === 'Enter' && !event.shiftKey) {
2085
- event.preventDefault();
2086
- this.sendMessage();
2087
- }
2088
- }
2089
- /**
2090
- * Generates CSS class names for message display based on message properties.
2091
- * @param message - The conversation message to generate classes for
2092
- * @returns Space-separated CSS class string for styling
2093
- */
2094
- getMessageClass(message) {
2095
- return `message message-${message.role}${message.isStreaming ? ' streaming' : ''}${message.error ? ' error' : ''}`;
2096
- }
2097
- /**
2098
- * Formats a Date object into a user-friendly time string.
2099
- * @param date - Date object to format
2100
- * @returns Formatted time string in HH:MM format
2101
- */
2102
- formatTimestamp(date) {
2103
- return date.toLocaleTimeString('en-US', {
2104
- hour: '2-digit',
2105
- minute: '2-digit'
2106
- });
2107
- }
2108
- /**
2109
- * Formats execution time from milliseconds into a human-readable string.
2110
- * Automatically selects appropriate units (minutes, seconds, or milliseconds).
2111
- * @param milliseconds - Execution time in milliseconds
2112
- * @returns Formatted time string (e.g., "2m 30.5s", "1.23s", "500ms")
2113
- */
2114
- formatExecutionTime(milliseconds) {
2115
- if (milliseconds >= 60000) {
2116
- const minutes = Math.floor(milliseconds / 60000);
2117
- const seconds = ((milliseconds % 60000) / 1000).toFixed(2);
2118
- return `${minutes}m ${seconds}s`;
2119
- }
2120
- else if (milliseconds >= 1000) {
2121
- return `${(milliseconds / 1000).toFixed(2)}s`;
2122
- }
2123
- else {
2124
- return `${milliseconds}ms`;
2125
- }
2126
- }
2127
- formatElapsedTime(milliseconds) {
2128
- const seconds = Math.floor(milliseconds / 1000);
2129
- const ms = milliseconds % 1000;
2130
- if (seconds > 0) {
2131
- return `${seconds}.${Math.floor(ms / 100)}s`;
2132
- }
2133
- else {
2134
- return `${ms}ms`;
2135
- }
2136
- }
2137
- startElapsedTimeCounter(message) {
2138
- if (this.elapsedTimeInterval) {
2139
- clearInterval(this.elapsedTimeInterval);
2140
- }
2141
- this.elapsedTimeInterval = setInterval(() => {
2142
- if (message.streamingStartTime && message.isStreaming) {
2143
- message.elapsedTime = Date.now() - message.streamingStartTime;
2144
- }
2145
- else {
2146
- clearInterval(this.elapsedTimeInterval);
2147
- this.elapsedTimeInterval = null;
2148
- }
2149
- }, 100); // Update every 100ms for smooth counter
2150
- }
2151
- /**
2152
- * Shows the raw JSON dialog for a specific message
2153
- * @param message - The message to show raw JSON for
2154
- */
2155
- showRawJsonDialog(message) {
2156
- if (message.rawContent) {
2157
- try {
2158
- // Try to parse and format the JSON
2159
- const parsed = JSON.parse(message.rawContent);
2160
- // If this is an agent result with execution tree, enhance the display
2161
- if (parsed.executionTree) {
2162
- this.currentJsonContent = JSON.stringify({
2163
- ...parsed,
2164
- _executionTreeSummary: this.summarizeExecutionTree(parsed.executionTree)
2165
- }, null, 2);
2166
- }
2167
- else {
2168
- this.currentJsonContent = JSON.stringify(parsed, null, 2);
2169
- }
2170
- }
2171
- catch {
2172
- // If not valid JSON, show as-is
2173
- this.currentJsonContent = message.rawContent;
2174
- }
2175
- this.showJsonDialog = true;
2176
- }
2177
- }
2178
- /**
2179
- * Creates a summary of the execution tree for easier viewing
2180
- * @param executionTree - The execution tree to summarize
2181
- * @returns A human-readable summary of the execution
2182
- */
2183
- summarizeExecutionTree(executionTree) {
2184
- if (!executionTree || !Array.isArray(executionTree))
2185
- return null;
2186
- const summary = {
2187
- totalSteps: 0,
2188
- stepsByType: {},
2189
- hierarchy: []
2190
- };
2191
- const processNode = (node, level = 0) => {
2192
- summary.totalSteps++;
2193
- // Count by type
2194
- const type = node.executionType || 'unknown';
2195
- summary.stepsByType[type] = (summary.stepsByType[type] || 0) + 1;
2196
- // Create hierarchical summary
2197
- const nodeSummary = {
2198
- level,
2199
- stepName: node.step?.StepName || 'Unknown Step',
2200
- type: node.executionType,
2201
- duration: node.durationMs ? `${node.durationMs}ms` : 'N/A',
2202
- status: node.step?.Status || 'Unknown',
2203
- agentPath: node.agentHierarchy?.join(' → ') || '',
2204
- hasInputData: !!node.inputData,
2205
- hasOutputData: !!node.outputData
2206
- };
2207
- summary.hierarchy.push(nodeSummary);
2208
- // Process children recursively
2209
- if (node.children && node.children.length > 0) {
2210
- node.children.forEach((child) => processNode(child, level + 1));
2211
- }
2212
- };
2213
- executionTree.forEach(node => processNode(node));
2214
- return summary;
2215
- }
2216
- /**
2217
- * Copies the message content to clipboard.
2218
- * @param message - The message to copy
2219
- */
2220
- async copyMessage(message) {
2221
- try {
2222
- // Convert content to string if needed
2223
- const content = typeof message.content === 'string'
2224
- ? message.content
2225
- : JSON.stringify(message.content);
2226
- await navigator.clipboard.writeText(content);
2227
- MJNotificationService.Instance.CreateSimpleNotification('Message copied to clipboard', 'success', 2000);
2228
- }
2229
- catch (error) {
2230
- MJNotificationService.Instance.CreateSimpleNotification('Failed to copy message', 'error', 3000);
2231
- }
2232
- }
2233
- /**
2234
- * Focuses the message input textarea.
2235
- */
2236
- focusMessageInput() {
2237
- if (this.messageInput) {
2238
- setTimeout(() => {
2239
- this.messageInput.focus();
2240
- }, 100);
2241
- }
2242
- }
2243
- /**
2244
- * Determines if the provided content is valid JSON.
2245
- * @param content - String content to test
2246
- * @returns True if content can be parsed as JSON, false otherwise
2247
- */
2248
- isJsonContent(content) {
2249
- if (!content)
2250
- return false;
2251
- try {
2252
- JSON.parse(content);
2253
- return true;
2254
- }
2255
- catch {
2256
- return false;
2257
- }
2258
- }
2259
- /**
2260
- * Formats JSON content with proper indentation for display.
2261
- * @param content - JSON string to format
2262
- * @returns Formatted JSON string or original content if parsing fails
2263
- */
2264
- formatJson(content) {
2265
- try {
2266
- return JSON.stringify(JSON.parse(content), null, 2);
2267
- }
2268
- catch {
2269
- return content;
2270
- }
2271
- }
2272
- /**
2273
- * Automatically detects the content type of a message for appropriate rendering.
2274
- * Uses pattern matching to identify JSON, Markdown, or plain text content.
2275
- * @param content - Content string to analyze
2276
- * @returns Detected content type ('markdown', 'json', or 'text')
2277
- */
2278
- detectContentType(content) {
2279
- if (!content)
2280
- return 'text';
2281
- // Check if it's JSON
2282
- if (this.isJsonContent(content)) {
2283
- return 'json';
2284
- }
2285
- // Check for markdown indicators
2286
- const markdownPatterns = [
2287
- /^#{1,6}\s/m, // Headers
2288
- /\*\*[^*]+\*\*/, // Bold
2289
- /\*[^*]+\*/, // Italic
2290
- /\[([^\]]+)\]\(([^)]+)\)/, // Links
2291
- /```[\s\S]*?```/, // Code blocks
2292
- /`[^`]+`/, // Inline code
2293
- /^[-*+]\s/m, // Lists
2294
- /^\d+\.\s/m // Numbered lists
2295
- ];
2296
- if (markdownPatterns.some(pattern => pattern.test(content))) {
2297
- return 'markdown';
2298
- }
2299
- return 'text';
2300
- }
2301
- renderMarkdown(content) {
2302
- // Basic markdown to HTML conversion with improved formatting
2303
- let html = content;
2304
- // Escape HTML first
2305
- html = html.replace(/&/g, '&amp;')
2306
- .replace(/</g, '&lt;')
2307
- .replace(/>/g, '&gt;');
2308
- // Code blocks with language support
2309
- html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
2310
- const language = lang || '';
2311
- const className = language ? ` class="language-${language}"` : '';
2312
- return `<pre class="code-block"><code${className}>${code.trim()}</code></pre>`;
2313
- });
2314
- // Regular code blocks without language
2315
- html = html.replace(/```([\s\S]*?)```/g, '<pre class="code-block"><code>$1</code></pre>');
2316
- // Inline code
2317
- html = html.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
2318
- // Headers
2319
- html = html.replace(/^### (.+)$/gm, '<h3 class="markdown-h3">$1</h3>');
2320
- html = html.replace(/^## (.+)$/gm, '<h2 class="markdown-h2">$1</h2>');
2321
- html = html.replace(/^# (.+)$/gm, '<h1 class="markdown-h1">$1</h1>');
2322
- // Bold
2323
- html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
2324
- // Italic
2325
- html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
2326
- // Links
2327
- html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" class="markdown-link">$1</a>');
2328
- // Unordered lists
2329
- html = html.replace(/^[*-+] (.+)$/gm, '<li>$1</li>');
2330
- html = html.replace(/((?:<li>.*<\/li>\s*)+)/g, '<ul class="markdown-list">$1</ul>');
2331
- // Numbered lists
2332
- html = html.replace(/^\d+\. (.+)$/gm, '<li>$1</li>');
2333
- html = html.replace(/((?:<li>.*<\/li>\s*)+)/g, '<ol class="markdown-list">$1</ol>');
2334
- // Paragraphs and line breaks - improved handling
2335
- html = html.replace(/\n\s*\n/g, '</p><p class="markdown-paragraph">');
2336
- html = html.replace(/\n/g, '<br>');
2337
- html = `<p class="markdown-paragraph">${html}</p>`;
2338
- // Clean up empty paragraphs
2339
- html = html.replace(/<p class="markdown-paragraph"><\/p>/g, '');
2340
- return this.sanitizer.bypassSecurityTrustHtml(`<div class="markdown-content">${html}</div>`);
2341
- }
2342
- getFormattedContent(message) {
2343
- const content = message.content;
2344
- const contentStr = typeof content === 'string' ? content : String(content);
2345
- const contentType = this.detectContentType(contentStr);
2346
- if (contentType === 'json') {
2347
- // Try to extract human-readable content from JSON
2348
- const extractedContent = this.extractHumanReadableContent(contentStr);
2349
- if (extractedContent) {
2350
- // Just render the extracted content
2351
- return this.renderMarkdown(extractedContent);
2352
- }
2353
- else {
2354
- // Fallback to inline code editor for JSON display
2355
- return this.renderJsonWithCodeEditor(contentStr);
2356
- }
2357
- }
2358
- else if (contentType === 'markdown') {
2359
- return this.renderMarkdown(contentStr);
2360
- }
2361
- else {
2362
- // Convert plain text to markdown for consistent formatting
2363
- return this.renderMarkdown(contentStr);
2364
- }
2365
- }
2366
- /**
2367
- * Renders JSON content using an inline code editor component
2368
- */
2369
- renderJsonWithCodeEditor(jsonStr) {
2370
- try {
2371
- // Format the JSON for display
2372
- const formattedJson = this.formatJson(jsonStr);
2373
- // Generate a unique ID for this editor instance
2374
- const editorId = `json-editor-${this.generateMessageId()}`;
2375
- // Create the HTML with a placeholder div that we'll replace with the code editor
2376
- const html = `
2377
- <div class="inline-json-editor" data-editor-id="${editorId}" data-json-content="${this.escapeHtmlAttribute(formattedJson)}">
2378
- <div class="json-editor-container" style="height: 300px; width: 100%; border: 1px solid #e0e0e0; border-radius: 4px; overflow: hidden;">
2379
- <pre style="margin: 0; padding: 12px; font-family: 'Fira Code', 'Consolas', monospace; font-size: 13px; overflow: auto; height: 100%;">${this.escapeHtml(formattedJson)}</pre>
2380
- </div>
2381
- </div>
2382
- `;
2383
- // Note: In a real implementation, we would need to dynamically create the code editor component
2384
- // For now, we'll use a styled pre tag as a fallback
2385
- return this.sanitizer.bypassSecurityTrustHtml(html);
2386
- }
2387
- catch {
2388
- // If JSON parsing fails, show as plain text
2389
- const html = `<pre style="margin: 0; padding: 12px; font-family: 'Fira Code', 'Consolas', monospace; font-size: 13px; overflow: auto; background: #f8f9fa; border-radius: 4px;">${this.escapeHtml(jsonStr)}</pre>`;
2390
- return this.sanitizer.bypassSecurityTrustHtml(html);
2391
- }
2392
- }
2393
- /**
2394
- * Escapes HTML content for use in attributes
2395
- */
2396
- escapeHtmlAttribute(text) {
2397
- return text
2398
- .replace(/&/g, '&amp;')
2399
- .replace(/"/g, '&quot;')
2400
- .replace(/'/g, '&#39;')
2401
- .replace(/</g, '&lt;')
2402
- .replace(/>/g, '&gt;');
2403
- }
2404
- /**
2405
- * Renders JSON content with human-readable content prominently displayed
2406
- * and raw JSON in a collapsible section below with proper text wrapping.
2407
- */
2408
- /**
2409
- * Gets a summary of the execution for tooltip display
2410
- * @param message - The message to get execution summary for
2411
- * @returns A brief summary of the execution steps
2412
- */
2413
- getExecutionSummary(message) {
2414
- if (!message.rawContent)
2415
- return '';
2416
- try {
2417
- const parsed = JSON.parse(message.rawContent);
2418
- if (parsed.executionTree) {
2419
- const summary = this.summarizeExecutionTree(parsed.executionTree);
2420
- const stepCounts = Object.entries(summary.stepsByType)
2421
- .map(([type, count]) => `${count} ${type}`)
2422
- .join(', ');
2423
- return `${summary.totalSteps} steps executed (${stepCounts})`;
2424
- }
2425
- }
2426
- catch {
2427
- // Ignore parse errors
2428
- }
2429
- return '';
2430
- }
2431
- /**
2432
- * Closes the JSON dialog
2433
- */
2434
- closeJsonDialog() {
2435
- this.showJsonDialog = false;
2436
- this.currentJsonContent = '';
2437
- this.currentJsonMessage = null;
2438
- }
2439
- /**
2440
- * Copies the JSON content to clipboard
2441
- */
2442
- copyJsonContent() {
2443
- if (this.currentJsonContent) {
2444
- navigator.clipboard.writeText(this.currentJsonContent).then(() => {
2445
- // Success - JSON copied
2446
- }).catch((err) => {
2447
- // Error copying
2448
- });
2449
- }
2450
- }
2451
- /**
2452
- * Extracts human-readable content from JSON responses.
2453
- * Prioritizes userMessage field first, then checks other common fields.
2454
- * @param jsonStr - JSON string to extract content from
2455
- * @returns Extracted human-readable content or null if none found
2456
- */
2457
- extractHumanReadableContent(jsonStr) {
2458
- try {
2459
- const parsed = JSON.parse(jsonStr);
2460
- // Priority 1: Always check userMessage first, regardless of taskComplete status
2461
- if (parsed.userMessage && typeof parsed.userMessage === 'string' && parsed.userMessage.trim()) {
2462
- return parsed.userMessage;
2463
- }
2464
- // Priority 2: Check for nested userMessage in nextStep or other objects
2465
- if (parsed.nextStep && parsed.nextStep.userMessage &&
2466
- typeof parsed.nextStep.userMessage === 'string' && parsed.nextStep.userMessage.trim()) {
2467
- return parsed.nextStep.userMessage;
2468
- }
2469
- // Priority 3: Other common human-readable fields
2470
- const contentFields = [
2471
- 'message', 'content', 'response', 'text', 'output',
2472
- 'result', 'answer', 'reply', 'description', 'summary'
2473
- ];
2474
- for (const field of contentFields) {
2475
- if (parsed[field] && typeof parsed[field] === 'string' && parsed[field].trim()) {
2476
- return parsed[field];
2477
- }
2478
- }
2479
- // Priority 4: Check nested objects for content
2480
- for (const key of Object.keys(parsed)) {
2481
- if (typeof parsed[key] === 'object' && parsed[key] !== null) {
2482
- for (const field of ['userMessage', 'message', 'content']) {
2483
- if (parsed[key][field] && typeof parsed[key][field] === 'string' && parsed[key][field].trim()) {
2484
- return parsed[key][field];
2485
- }
2486
- }
2487
- }
2488
- }
2489
- // Priority 5: If it's a simple string value, return it
2490
- if (typeof parsed === 'string' && parsed.trim()) {
2491
- return parsed;
2492
- }
2493
- // Priority 6: If it's an object with a single string property, consider returning it
2494
- const keys = Object.keys(parsed);
2495
- if (keys.length === 1 && typeof parsed[keys[0]] === 'string' && parsed[keys[0]].trim()) {
2496
- return parsed[keys[0]];
2497
- }
2498
- return null;
2499
- }
2500
- catch {
2501
- return null;
2502
- }
2503
- }
2504
- /**
2505
- * Checks if a message contains JSON content that has extractable human-readable content.
2506
- * Used to determine if the raw toggle should be shown.
2507
- * @param message - The conversation message to check
2508
- * @returns True if the message has extractable content different from raw JSON
2509
- */
2510
- hasExtractableContent(message) {
2511
- if (!message.content || message.role === 'user') {
2512
- return false;
2513
- }
2514
- const contentStr = typeof message.content === 'string' ? message.content : String(message.content);
2515
- if (!this.isJsonContent(contentStr)) {
2516
- return false;
2517
- }
2518
- const extractedContent = this.extractHumanReadableContent(contentStr);
2519
- return extractedContent !== null && extractedContent !== contentStr;
2520
- }
2521
- /**
2522
- * Determines whether to show the raw toggle button for a message.
2523
- * Combines the logic for raw content availability and extractable content.
2524
- * @param message - The conversation message to check
2525
- * @returns True if the raw toggle should be displayed
2526
- */
2527
- showRawToggle(message) {
2528
- return (message.rawContent && !message.isStreaming) || this.hasExtractableContent(message);
2529
- }
2530
- escapeHtml(text) {
2531
- const div = document.createElement('div');
2532
- div.textContent = text;
2533
- return div.innerHTML;
2534
- }
2535
- /**
2536
- * Formats JSON for proper display with text wrapping instead of wide code blocks.
2537
- * Creates a structured, readable format that respects container width.
2538
- */
2539
- formatJsonForDisplay(jsonStr) {
2540
- try {
2541
- const parsed = JSON.parse(jsonStr);
2542
- return this.createJsonDisplayHtml(parsed, 0);
2543
- }
2544
- catch {
2545
- // If JSON parsing fails, escape and display as-is with wrapping
2546
- return `<div class="json-fallback">${this.escapeHtml(jsonStr)}</div>`;
2547
- }
2548
- }
2549
- /**
2550
- * Creates formatted HTML for JSON display with proper indentation and wrapping.
2551
- */
2552
- createJsonDisplayHtml(obj, depth = 0) {
2553
- const indent = ' '.repeat(depth);
2554
- const nextIndent = ' '.repeat(depth + 1);
2555
- if (obj === null)
2556
- return `<span class="json-null">null</span>`;
2557
- if (typeof obj === 'boolean')
2558
- return `<span class="json-boolean">${obj}</span>`;
2559
- if (typeof obj === 'number')
2560
- return `<span class="json-number">${obj}</span>`;
2561
- if (typeof obj === 'string') {
2562
- const escaped = this.escapeHtml(obj);
2563
- return `<span class="json-string">"<span class="json-string-content">${escaped}</span>"</span>`;
2564
- }
2565
- if (Array.isArray(obj)) {
2566
- if (obj.length === 0)
2567
- return '<span class="json-bracket">[]</span>';
2568
- const items = obj.map(item => `<div class="json-array-item">${nextIndent}${this.createJsonDisplayHtml(item, depth + 1)}</div>`).join(',\n');
2569
- return `<span class="json-bracket">[</span>\n${items}\n<div class="json-indent">${indent}</div><span class="json-bracket">]</span>`;
2570
- }
2571
- if (typeof obj === 'object') {
2572
- const keys = Object.keys(obj);
2573
- if (keys.length === 0)
2574
- return '<span class="json-bracket">{}</span>';
2575
- const properties = keys.map(key => {
2576
- const escapedKey = this.escapeHtml(key);
2577
- const value = this.createJsonDisplayHtml(obj[key], depth + 1);
2578
- return `<div class="json-property">${nextIndent}<span class="json-key">"${escapedKey}"</span><span class="json-colon">:</span> ${value}</div>`;
2579
- }).join(',\n');
2580
- return `<span class="json-bracket">{</span>\n${properties}\n<div class="json-indent">${indent}</div><span class="json-bracket">}</span>`;
2581
- }
2582
- return String(obj);
2583
- }
2584
- /**
2585
- * Type guard to check if entity is an AI Agent
2586
- */
2587
- isAgentEntity(entity) {
2588
- // Check using the EntityInfo property from BaseEntity
2589
- return entity && entity.EntityInfo && entity.EntityInfo.Name === 'AI Agents';
2590
- }
2591
- /**
2592
- * Type guard to check if entity is an AI Prompt
2593
- */
2594
- isPromptEntity(entity) {
2595
- // Check using the EntityInfo property from BaseEntity
2596
- const result = entity && entity.EntityInfo && entity.EntityInfo.Name === 'AI Prompts';
2597
- return result;
2598
- }
2599
- /**
2600
- * Gets the display name of the current entity
2601
- */
2602
- getEntityName() {
2603
- if (!this.entity)
2604
- return '';
2605
- return this.entity.Name || 'Untitled';
2606
- }
2607
- static { this.ɵfac = function AITestHarnessComponent_Factory(t) { return new (t || AITestHarnessComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer)); }; }
2608
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AITestHarnessComponent, selectors: [["mj-ai-test-harness"]], viewQuery: function AITestHarnessComponent_Query(rf, ctx) { if (rf & 1) {
2609
- i0.ɵɵviewQuery(_c0, 5);
2610
- i0.ɵɵviewQuery(_c1, 5);
2611
- i0.ɵɵviewQuery(_c2, 5);
2612
- i0.ɵɵviewQuery(_c3, 5);
2613
- } if (rf & 2) {
2614
- let _t;
2615
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messagesContainer = _t.first);
2616
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.fileInput = _t.first);
2617
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageInput = _t.first);
2618
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.saveDialogInput = _t.first);
2619
- } }, inputs: { mode: "mode", entity: "entity", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange" }, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 4, consts: [["fileInput", ""], ["messagesContainer", ""], ["messageInput", ""], ["saveDialogInput", ""], ["class", "harness-container", 4, "ngIf"], [1, "save-dialog", 3, "title", "width"], [1, "confirm-dialog", 3, "title", "width"], [1, "json-dialog-window", 3, "title", "width", "height", "minWidth", "minHeight", "resizable", "draggable", "state", "keepContent"], [1, "harness-container"], [1, "harness-header"], [1, "agent-info"], [1, "harness-body"], ["orientation", "horizontal", 2, "height", "100%", "width", "100%"], [1, "chat-area"], [1, "agent-details"], [1, "fa-solid"], [1, "header-actions"], ["title", "Clear conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-broom"], ["title", "Save conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-save"], ["title", "Export conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-download"], ["title", "Import conversation", 1, "custom-button", 3, "click"], [1, "fa-solid", "fa-upload"], ["type", "file", "accept", ".json", 2, "display", "none", 3, "change"], ["title", "Toggle sidebar", 1, "custom-button", "icon-only", 3, "click"], [3, "collapsible", "resizable", "min"], [1, "messages-container"], [1, "empty-state"], [3, "ngClass"], [1, "input-area"], [1, "input-container"], ["placeholder", "Type your message here... (Press Enter to send, Shift+Enter for new line)", 1, "message-input", 3, "ngModelChange", "keypress", "ngModel", "rows", "disabled"], ["title", "Send message", 1, "send-button", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-paper-plane"], [3, "collapsible", "resizable", "size", "min"], [1, "sidebar"], [1, "sidebar-tabs"], [1, "tab-button", 3, "click", "disabled"], [1, "fa-solid", "fa-history"], [1, "badge"], [1, "sidebar-content"], [1, "tab-content"], [1, "tab-content", 2, "padding", "0", "height", "100%"], [1, "fa-solid", "fa-comments"], [1, "message-header"], [1, "message-role"], [1, "message-time"], [1, "execution-time", "streaming"], [1, "execution-time", 3, "title"], ["title", "View raw JSON response", 1, "raw-toggle"], [1, "message-content"], ["title", "Copy message", 1, "copy-button-in-bubble", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "streaming-wrapper"], [3, "innerHTML"], [1, "error-details"], [1, "fa-solid", "fa-user"], [1, "fa-solid", "fa-robot"], ["title", "View raw JSON response", 1, "raw-toggle", 3, "click"], [1, "fa-solid", "fa-code"], [1, "streaming-content"], [1, "cursor"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "tab-button", 3, "click"], [1, "fa-solid", "fa-diagram-project"], [1, "fa-solid", "fa-sliders"], [1, "tab-header"], [1, "variables-list"], [1, "empty-variables"], [1, "variable-item"], [1, "add-button", 3, "click", "disabled"], [1, "fa-solid", "fa-plus"], ["placeholder", "Variable name", 1, "variable-name", 3, "ngModelChange", "ngModel", "disabled"], ["textField", "text", "valueField", "value", 1, "variable-type", 3, "ngModelChange", "ngModel", "data", "valuePrimitive", "disabled"], [1, "variable-value", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], ["title", "Remove variable", 1, "remove-button", 3, "click", "disabled"], [1, "fa-solid", "fa-times"], [3, "mode", "executionData", "autoExpand"], [1, "add-button", 3, "click"], ["title", "Remove variable", 1, "remove-button", 3, "click"], [1, "model-settings"], [1, "setting-group"], ["textField", "Name", "valueField", "ID", "placeholder", "Select a model...", 1, "model-selector", 3, "ngModelChange", "ngModel", "data", "valuePrimitive"], [1, "temperature-slider", 3, "ngModelChange", "ngModel", "min", "max", "smallStep", "showButtons"], [1, "setting-help"], ["textField", "text", "valueField", "value", "placeholder", "Select format...", 1, "format-selector", 3, "ngModelChange", "ngModel", "data"], ["placeholder", "Max tokens...", 1, "max-tokens-input", 3, "ngModelChange", "ngModel", "min", "max", "step"], ["title", "Start a new conversation", 1, "custom-button", "small", "primary"], [1, "saved-list"], [1, "empty-saved"], [1, "saved-item", 3, "current"], ["title", "Start a new conversation", 1, "custom-button", "small", "primary", 3, "click"], [1, "fa-solid", "fa-folder-open"], [1, "saved-item", 3, "click"], [1, "saved-info"], [1, "saved-date"], ["title", "Delete conversation", 1, "delete-button", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "View execution details", 1, "execution-history-toggle"], ["title", "View execution details", 1, "execution-history-toggle", 3, "click"], [1, "save-dialog", 3, "close", "title", "width"], [1, "dialog-content"], ["type", "text", "placeholder", "Conversation name", 1, "k-textbox", "k-input", "k-input-md", "k-rounded-md", "k-input-solid", "full-width", 3, "keyup"], ["kendoButton", "", 3, "click"], ["kendoButton", "", 3, "click", "primary", "disabled"], [1, "confirm-dialog", 3, "close", "title", "width"], ["kendoButton", "", 3, "click", "primary"], [1, "json-dialog-window", 3, "close", "title", "width", "height", "minWidth", "minHeight", "resizable", "draggable", "state", "keepContent"], [1, "json-dialog-content"], [1, "json-dialog-header"], ["title", "Copy JSON", 1, "custom-button", "icon-only", 3, "click"], [1, "json-dialog-body"], [2, "height", "100%", "width", "100%", 3, "ngModelChange", "ngModel", "readonly", "language", "lineWrapping"]], template: function AITestHarnessComponent_Template(rf, ctx) { if (rf & 1) {
2620
- i0.ɵɵtemplate(0, AITestHarnessComponent_div_0_Template, 6, 2, "div", 4)(1, AITestHarnessComponent_Conditional_1_Template, 11, 4, "kendo-dialog", 5)(2, AITestHarnessComponent_Conditional_2_Template, 11, 3, "kendo-dialog", 6)(3, AITestHarnessComponent_Conditional_3_Template, 7, 13, "kendo-window", 7);
2621
- } if (rf & 2) {
2622
- i0.ɵɵproperty("ngIf", ctx.isVisible);
2623
- i0.ɵɵadvance();
2624
- i0.ɵɵconditional(ctx.showSaveDialog ? 1 : -1);
2625
- i0.ɵɵadvance();
2626
- i0.ɵɵconditional(ctx.showLoadConfirmDialog ? 2 : -1);
2627
- i0.ɵɵadvance();
2628
- i0.ɵɵconditional(ctx.showJsonDialog ? 3 : -1);
2629
- } }, dependencies: [i2.NgClass, i2.NgIf, i3.AgentExecutionMonitorComponent, i4.NgControlStatus, i4.NgModel, i5.SplitterComponent, i5.SplitterPaneComponent, i6.DialogComponent, i6.DialogActionsComponent, i6.WindowComponent, i7.TextAreaComponent, i7.TextBoxComponent, i7.SliderComponent, i7.NumericTextBoxComponent, i8.DropDownListComponent, i9.ButtonComponent, i10.CodeEditorComponent, i2.DatePipe], styles: ["\n\n.harness-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n}\n\n\n\n.custom-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.custom-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.custom-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.custom-button.icon-only[_ngcontent-%COMP%] {\n padding: 6px 8px;\n}\n\n.custom-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.send-button[_ngcontent-%COMP%] {\n background: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\n border-radius: 4px;\n padding: 8px 16px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n font-family: inherit;\n}\n\n.send-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\n}\n\n.send-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.send-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.add-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background: #0d6efd;\n color: white;\n}\n\n\n\n.remove-button[_ngcontent-%COMP%], \n.delete-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: #dc3545;\n padding: 4px 8px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover, \n.delete-button[_ngcontent-%COMP%]:hover {\n background: rgba(220, 53, 69, 0.1);\n color: #bd2130;\n}\n\n\n\n.copy-button-in-bubble[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n padding: 6px;\n font-size: 14px;\n color: #adb5bd;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0;\n z-index: 10; \n\n}\n\n.message-content[_ngcontent-%COMP%]:hover .copy-button-in-bubble[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #6c757d;\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.model-settings[_ngcontent-%COMP%] {\n padding: 16px;\n}\n\n.setting-group[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.setting-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: #495057;\n font-size: 14px;\n}\n\n.model-selector[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.temperature-slider[_ngcontent-%COMP%] {\n width: 100%;\n margin-top: 8px;\n}\n\n.max-tokens-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.setting-help[_ngcontent-%COMP%] {\n margin-top: 6px;\n font-size: 12px;\n color: #6c757d;\n font-style: italic;\n}\n\n\n\n.harness-header[_ngcontent-%COMP%] {\n background: white;\n border-bottom: 1px solid #dee2e6;\n padding: 16px 20px;\n}\n\n.agent-info[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.agent-details[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.agent-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n color: #17a2b8;\n}\n\n.agent-details[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.agent-details[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n\n.harness-body[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n\n\n.chat-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: white;\n border-right: 1px solid #dee2e6;\n height: 100%;\n min-height: 0; \n\n}\n\n\n\n.messages-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: #6c757d;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.message-user[_ngcontent-%COMP%] {\n margin-left: auto;\n max-width: 70%;\n}\n\n.message-assistant[_ngcontent-%COMP%] {\n margin-right: auto;\n max-width: 70%;\n}\n\n.message-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 13px;\n}\n\n.message-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.message-user[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: #6f42c1;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: #17a2b8;\n}\n\n.message-time[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time[_ngcontent-%COMP%] {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming[_ngcontent-%COMP%] {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\n cursor: pointer;\n transition: all 0.2s;\n margin-left: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n}\n\n.raw-toggle[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.05);\n color: #495057;\n}\n\n.raw-toggle[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n\n.message-user[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\n}\n\n.streaming-content[_ngcontent-%COMP%] {\n display: inline;\n}\n\n.streaming-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.cursor[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_blink 1s infinite;\n font-weight: 100;\n color: #495057;\n}\n\n@keyframes _ngcontent-%COMP%_blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n.error-details[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px 12px;\n background: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #dc3545;\n}\n\n\n\n.save-dialog[_ngcontent-%COMP%], \n.confirm-dialog[_ngcontent-%COMP%] {\n .dialog-content {\n padding: 20px;\n \n p {\n margin: 0 0 16px 0;\n color: #333;\n font-size: 14px;\n line-height: 1.5;\n \n &:last-child {\n margin-bottom: 0;\n }\n }\n \n .full-width {\n width: 100%;\n }\n \n input.k-textbox {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\n }\n }\n }\n}\n\n\n\n.markdown-content[_ngcontent-%COMP%] {\n line-height: 1.6;\n word-wrap: break-word;\n overflow-wrap: break-word;\n max-width: 100%;\n}\n\n\n\n.inline-json-editor[_ngcontent-%COMP%] {\n margin: 8px 0;\n \n .json-editor-container {\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n max-height: 400px;\n \n pre {\n margin: 0;\n padding: 12px;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n height: 100%;\n background: transparent;\n color: #333;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n }\n}\n\n.markdown-paragraph[_ngcontent-%COMP%] {\n margin: 8px 0;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.markdown-h1[_ngcontent-%COMP%] {\n font-size: 1.5em;\n font-weight: 600;\n margin: 16px 0 8px 0;\n color: #212529;\n border-bottom: 2px solid #e9ecef;\n padding-bottom: 4px;\n}\n\n.markdown-h2[_ngcontent-%COMP%] {\n font-size: 1.3em;\n font-weight: 600;\n margin: 14px 0 6px 0;\n color: #212529;\n border-bottom: 1px solid #e9ecef;\n padding-bottom: 2px;\n}\n\n.markdown-h3[_ngcontent-%COMP%] {\n font-size: 1.1em;\n font-weight: 600;\n margin: 12px 0 4px 0;\n color: #212529;\n}\n\n.code-block[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n padding: 16px;\n margin: 12px 0;\n overflow-x: auto;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n color: #212529;\n white-space: pre;\n word-wrap: normal;\n max-width: 100%;\n}\n\n.code-block[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre;\n word-wrap: normal;\n}\n\n.language-json[_ngcontent-%COMP%] {\n color: #d73e48;\n}\n\n.inline-code[_ngcontent-%COMP%] {\n background: #f1f3f4;\n border: 1px solid #dadce0;\n border-radius: 4px;\n padding: 2px 6px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 0.9em;\n color: #d73e48;\n white-space: nowrap;\n}\n\n.markdown-list[_ngcontent-%COMP%] {\n margin: 8px 0;\n padding-left: 24px;\n}\n\n.markdown-list[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin: 4px 0;\n line-height: 1.5;\n}\n\n.markdown-link[_ngcontent-%COMP%] {\n color: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link[_ngcontent-%COMP%]:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n\n\n.message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border-radius: 12px;\n padding: 12px 40px 12px 16px; \n\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n position: relative;\n overflow-wrap: break-word;\n hyphens: auto;\n max-width: 100%;\n overflow-x: hidden;\n}\n\n\n\n.json-content-wrapper[_ngcontent-%COMP%] {\n margin: 8px 0;\n}\n\n.json-main-content[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n.json-toggle-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.json-toggle-button[_ngcontent-%COMP%]:hover {\n background: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.json-toggle-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n margin: 8px 0 0 0;\n font-size: 12px;\n max-height: 300px;\n overflow-y: auto;\n}\n\n\n\n@media (max-width: 768px) {\n .json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n font-size: 11px;\n max-height: 200px;\n }\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n\n\n.input-area[_ngcontent-%COMP%] {\n padding: 16px;\n background: white;\n border-top: 1px solid #dee2e6;\n flex-shrink: 0; \n\n margin-top: auto; \n\n}\n\n.input-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n}\n\n.message-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.message-input[_ngcontent-%COMP%] textarea[_ngcontent-%COMP%] {\n resize: none;\n font-size: 14px;\n}\n\n.send-button[_ngcontent-%COMP%] {\n margin-bottom: 1px;\n}\n\n\n\n.sidebar[_ngcontent-%COMP%] {\n width: 100%; \n\n background: white;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n.harness-body[_ngcontent-%COMP%] kendo-splitter[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n.harness-body[_ngcontent-%COMP%] kendo-splitter-pane[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n.sidebar-tabs[_ngcontent-%COMP%] {\n display: flex;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.tab-button[_ngcontent-%COMP%] {\n flex: 1;\n padding: 12px 8px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: #6c757d;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.tab-button[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\n}\n\n.tab-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tab-button[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: #6c757d;\n color: white;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n margin-left: 4px;\n}\n\n.tab-button.active[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: #0d6efd;\n}\n\n.tab-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n\n\n.sidebar-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n width: 100%; \n\n}\n\n.tab-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%; \n\n box-sizing: border-box; \n\n}\n\n.tab-header[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.tab-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: #212529;\n}\n\n.tab-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] {\n align-self: flex-start;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n\n\n.variables-list[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n width: 100%;\n}\n\n.variable-item[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n align-items: center;\n width: 100%;\n}\n\n.variable-name[_ngcontent-%COMP%] {\n width: 30%; \n\n min-width: 100px;\n}\n\n.variable-type[_ngcontent-%COMP%] {\n width: 25%; \n\n min-width: 80px;\n}\n\n.variable-value[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0; \n\n}\n\n.remove-button[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.add-variable-button[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.empty-variables[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: #6c757d;\n}\n\n\n\n.saved-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: #6c757d;\n}\n\n.empty-saved[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.saved-item[_ngcontent-%COMP%] {\n border: 1px solid #dee2e6;\n border-radius: 8px;\n padding: 12px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.saved-item[_ngcontent-%COMP%]:hover {\n background: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current[_ngcontent-%COMP%] {\n background: #e7f3ff;\n border-color: #0d6efd;\n}\n\n.saved-info[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: #212529;\n}\n\n.saved-info[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6c757d;\n}\n\n\n\n@media (max-width: 1200px) {\n .sidebar[_ngcontent-%COMP%] {\n width: 320px;\n }\n}\n\n@media (max-width: 992px) {\n .message-user[_ngcontent-%COMP%], \n .message-assistant[_ngcontent-%COMP%] {\n max-width: 85%;\n }\n \n .sidebar[_ngcontent-%COMP%] {\n width: 280px;\n }\n}\n\n\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 4px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: #a1a1a1;\n}\n\n\n\n .ai-agent-test-harness .k-dialog-wrapper {\n border-radius: 8px;\n overflow: hidden;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar {\n background: #343a40;\n color: white;\n}\n\n .ai-agent-test-harness .k-dialog-title {\n font-weight: 600;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar-actions .k-button {\n color: white;\n}\n\n .ai-agent-test-harness .k-dialog-content {\n padding: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.json-dialog-window[_ngcontent-%COMP%] {\n \n\n ::ng-deep .k-window {\n position: fixed !important;\n top: 50% !important;\n left: 50% !important;\n transform: translate(-50%, -50%) !important;\n margin: 0 !important;\n }\n \n ::ng-deep .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n \n ::ng-deep .k-window-titlebar {\n .k-window-title {\n font-size: 16px;\n font-weight: 500;\n }\n \n .k-window-actions {\n button {\n background: transparent;\n border: none;\n color: #666;\n padding: 8px 12px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.2s;\n \n &:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #333;\n }\n \n i {\n font-size: 14px;\n }\n }\n }\n }\n}\n\n.json-dialog-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n overflow: hidden;\n}\n\n.json-dialog-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n display: flex;\n justify-content: flex-end;\n align-items: center;\n flex-shrink: 0;\n}\n\n.json-dialog-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 0;\n position: relative;\n min-height: 0;\n \n mj-code-editor {\n display: block;\n height: 100%;\n \n ::ng-deep .cm-editor {\n height: 100%;\n \n .cm-scroller {\n overflow: auto !important;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n }\n }\n }\n}"] }); }
2630
- }
2631
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AITestHarnessComponent, [{
2632
- type: Component,
2633
- args: [{ selector: 'mj-ai-test-harness', template: "<div class=\"harness-container\" *ngIf=\"isVisible\">\n <!-- Header -->\n <div class=\"harness-header\">\n @if (entity) {\n <div class=\"agent-info\">\n <div class=\"agent-details\">\n <i class=\"fa-solid\" [class.fa-robot]=\"mode === 'agent'\" [class.fa-comment-dots]=\"mode === 'prompt'\"></i>\n <div>\n <h3>{{ getEntityName() }}</h3>\n @if (entity.Description) {\n <p>{{ entity.Description }}</p>\n }\n </div>\n </div>\n <div class=\"header-actions\">\n <button \n class=\"custom-button\"\n (click)=\"clearConversation()\"\n [disabled]=\"isExecuting || conversationMessages.length === 0\"\n title=\"Clear conversation\">\n <i class=\"fa-solid fa-broom\"></i>\n Clear\n </button>\n <button \n class=\"custom-button\"\n (click)=\"saveConversation()\"\n [disabled]=\"conversationMessages.length === 0\"\n title=\"Save conversation\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n <button \n class=\"custom-button\"\n (click)=\"exportConversation()\"\n [disabled]=\"conversationMessages.length === 0\"\n title=\"Export conversation\">\n <i class=\"fa-solid fa-download\"></i>\n Export\n </button>\n <button \n class=\"custom-button\"\n (click)=\"importConversation()\"\n title=\"Import conversation\">\n <i class=\"fa-solid fa-upload\"></i>\n Import\n </button>\n <input \n #fileInput\n type=\"file\"\n accept=\".json\"\n style=\"display: none\"\n (change)=\"onFileSelected($event)\">\n <button \n class=\"custom-button icon-only\"\n (click)=\"toggleSidebar()\"\n title=\"Toggle sidebar\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"!showSidebar\" [class.fa-chevron-left]=\"showSidebar\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Main Content Area with Splitter -->\n <div class=\"harness-body\">\n @if (showSidebar) {\n <kendo-splitter \n orientation=\"horizontal\"\n style=\"height: 100%; width: 100%;\">\n \n <!-- Chat Area (Left Pane) -->\n <kendo-splitter-pane \n [collapsible]=\"false\"\n [resizable]=\"true\"\n [min]=\"'400px'\">\n <div class=\"chat-area\">\n <!-- Messages Container -->\n <div class=\"messages-container\" #messagesContainer>\n @if (conversationMessages.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\n }\n\n @for (message of conversationMessages; track message.id) {\n <div [ngClass]=\"getMessageClass(message)\">\n <div class=\"message-header\">\n <span class=\"message-role\">\n @if (message.role === 'user') {\n <i class=\"fa-solid fa-user\"></i> You\n } @else {\n <i class=\"fa-solid fa-robot\"></i> {{ getEntityName() || 'Assistant' }}\n }\n </span>\n <span class=\"message-time\">{{ formatTimestamp(message.timestamp) }}</span>\n @if (message.isStreaming && message.elapsedTime !== undefined) {\n <span class=\"execution-time streaming\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> {{ formatElapsedTime(message.elapsedTime) }}\n </span>\n } @else if (message.executionTime) {\n <span class=\"execution-time\" [title]=\"getExecutionSummary(message)\">{{ formatExecutionTime(message.executionTime) }}</span>\n }\n @if (showRawToggle(message)) {\n <button class=\"raw-toggle\" (click)=\"showRawJsonDialog(message)\" title=\"View raw JSON response\">\n <i class=\"fa-solid fa-code\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\">{{ message.streamingContent }}<span class=\"cursor\">|</span></span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <div class=\"input-container\">\n <kendo-textarea\n #messageInput\n [(ngModel)]=\"currentUserMessage\"\n [rows]=\"3\"\n placeholder=\"Type your message here... (Press Enter to send, Shift+Enter for new line)\"\n (keypress)=\"handleKeyPress($event)\"\n [disabled]=\"isExecuting\"\n class=\"message-input\">\n </kendo-textarea>\n <button\n class=\"send-button\"\n (click)=\"sendMessage()\"\n [disabled]=\"isExecuting || !currentUserMessage.trim()\"\n title=\"Send message\">\n @if (isExecuting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n }\n </button>\n </div>\n </div>\n </div>\n </kendo-splitter-pane>\n \n <!-- Sidebar (Right Pane) -->\n <kendo-splitter-pane \n [collapsible]=\"false\"\n [resizable]=\"true\"\n [size]=\"'30%'\"\n [min]=\"'300px'\">\n <div class=\"sidebar\">\n <!-- Tab Navigation -->\n <div class=\"sidebar-tabs\">\n @if (mode === 'agent') {\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'agentVariables'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'agentVariables'\"\n (click)=\"selectTab('agentVariables')\">\n <i class=\"fa-solid fa-code\"></i>\n Agent Variables\n </button>\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'executionMonitor'\"\n (click)=\"selectTab('executionMonitor')\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n Execution Monitor\n </button>\n } @else {\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'templateVariables'\"\n (click)=\"selectTab('templateVariables')\">\n <i class=\"fa-solid fa-code\"></i>\n Template Variables\n </button>\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'modelSettings'\"\n (click)=\"selectTab('modelSettings')\">\n <i class=\"fa-solid fa-sliders\"></i>\n Model Settings\n </button>\n }\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'savedConversations'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'savedConversations'\"\n (click)=\"selectTab('savedConversations')\">\n <i class=\"fa-solid fa-history\"></i>\n Saved\n @if (savedConversations.length > 0) {\n <span class=\"badge\">{{ savedConversations.length }}</span>\n }\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"sidebar-content\">\n <!-- Agent Variables Tab (Unified) -->\n @if (activeTab === 'agentVariables') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Agent Variables</h4>\n <p>Variables available during agent execution and template rendering</p>\n </div>\n \n <div class=\"variables-list\">\n @if (agentVariables.length === 0) {\n <div class=\"empty-variables\">\n <p>No variables defined. Click \"Add Variable\" to get started.</p>\n </div>\n }\n \n @for (variable of agentVariables; track $index) {\n <div class=\"variable-item\">\n <kendo-textbox \n [(ngModel)]=\"variable.name\" \n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\"\n class=\"variable-name\">\n </kendo-textbox>\n \n <kendo-dropdownlist \n [(ngModel)]=\"variable.type\"\n [data]=\"[\n {text: 'String', value: 'string'}, \n {text: 'Number', value: 'number'}, \n {text: 'Boolean', value: 'boolean'}, \n {text: 'Object', value: 'object'}\n ]\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [disabled]=\"isExecuting\"\n class=\"variable-type\">\n </kendo-dropdownlist>\n \n <kendo-textbox \n [(ngModel)]=\"variable.value\" \n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\"\n class=\"variable-value\">\n </kendo-textbox>\n \n <button \n class=\"remove-button\"\n (click)=\"removeAgentVariable($index)\"\n [disabled]=\"isExecuting\"\n title=\"Remove variable\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n </div>\n \n <button \n class=\"add-button\"\n (click)=\"addAgentVariable()\"\n [disabled]=\"isExecuting\">\n <i class=\"fa-solid fa-plus\"></i> Add Variable\n </button>\n </div>\n }\n\n <!-- Execution Monitor Tab -->\n @if (activeTab === 'executionMonitor') {\n <div class=\"tab-content\" style=\"padding: 0; height: 100%;\">\n <mj-agent-execution-monitor\n [mode]=\"executionMonitorMode\"\n [executionData]=\"currentExecutionData\"\n [autoExpand]=\"true\">\n </mj-agent-execution-monitor>\n </div>\n }\n\n <!-- Template Variables Tab (Prompt Mode) -->\n @if (activeTab === 'templateVariables') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Template Variables</h4>\n <p>Variables for prompt template rendering</p>\n </div>\n \n <div class=\"variables-list\">\n @for (variable of templateVariables; track $index) {\n <div class=\"variable-item\">\n <kendo-textbox \n [(ngModel)]=\"variable.name\" \n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\"\n class=\"variable-name\">\n </kendo-textbox>\n \n <kendo-dropdownlist \n [(ngModel)]=\"variable.type\"\n [data]=\"[\n {text: 'String', value: 'string'}, \n {text: 'Number', value: 'number'}, \n {text: 'Boolean', value: 'boolean'}, \n {text: 'Object', value: 'object'}\n ]\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [disabled]=\"isExecuting\"\n class=\"variable-type\">\n </kendo-dropdownlist>\n \n <kendo-textbox \n [(ngModel)]=\"variable.value\" \n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\"\n class=\"variable-value\">\n </kendo-textbox>\n \n <button \n class=\"remove-button\"\n (click)=\"removeTemplateVariable($index)\"\n title=\"Remove variable\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n </div>\n \n <button \n class=\"add-button\"\n (click)=\"addTemplateVariable()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Variable\n </button>\n </div>\n }\n\n <!-- Model Settings Tab (Prompt Mode) -->\n @if (activeTab === 'modelSettings') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Model Settings</h4>\n <p>Configure AI model parameters</p>\n </div>\n \n <div class=\"model-settings\">\n <div class=\"setting-group\">\n <label>AI Model</label>\n <kendo-dropdownlist \n [(ngModel)]=\"selectedModelId\"\n [data]=\"availableModels\"\n textField=\"Name\"\n valueField=\"ID\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select a model...\"\n class=\"model-selector\">\n </kendo-dropdownlist>\n </div>\n \n <div class=\"setting-group\">\n <label>Temperature ({{ temperature }})</label>\n <kendo-slider \n [(ngModel)]=\"temperature\"\n [min]=\"0\"\n [max]=\"2\"\n [smallStep]=\"0.1\"\n [showButtons]=\"false\"\n class=\"temperature-slider\">\n </kendo-slider>\n <div class=\"setting-help\">\n Lower values make output more focused and deterministic\n </div>\n </div>\n \n <div class=\"setting-group\">\n <label>Response Format</label>\n <kendo-dropdownlist \n [(ngModel)]=\"selectedResponseFormat\"\n [data]=\"responseFormatOptions\"\n textField=\"text\"\n valueField=\"value\"\n placeholder=\"Select format...\"\n class=\"format-selector\">\n </kendo-dropdownlist>\n <div class=\"setting-help\">\n Expected format for AI response (defaults to prompt setting)\n </div>\n </div>\n \n <div class=\"setting-group\">\n <label>Max Tokens</label>\n <kendo-numerictextbox \n [(ngModel)]=\"maxTokens\"\n [min]=\"100\"\n [max]=\"8000\"\n [step]=\"100\"\n placeholder=\"Max tokens...\"\n class=\"max-tokens-input\">\n </kendo-numerictextbox>\n <div class=\"setting-help\">\n Maximum length of generated response\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Saved Conversations Tab -->\n @if (activeTab === 'savedConversations') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Saved Conversations</h4>\n <p>Previously saved test sessions</p>\n @if (currentConversationId) {\n <button class=\"custom-button small primary\" (click)=\"newConversation()\" title=\"Start a new conversation\">\n <i class=\"fa-solid fa-plus\"></i>\n New\n </button>\n }\n </div>\n \n <div class=\"saved-list\">\n @if (savedConversations.length === 0) {\n <div class=\"empty-saved\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <p>No saved conversations</p>\n </div>\n }\n \n @for (conv of savedConversations; track conv.id) {\n <div class=\"saved-item\" \n [class.current]=\"conv.id === currentConversationId\"\n (click)=\"loadConversation(conv)\">\n <div class=\"saved-info\">\n <h5>{{ conv.name }}</h5>\n <p>{{ conv.messages.length }} messages</p>\n <span class=\"saved-date\">{{ conv.updatedAt | date:'short' }}</span>\n </div>\n <button \n class=\"delete-button\"\n (click)=\"deleteConversation(conv, $event)\"\n title=\"Delete conversation\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </kendo-splitter-pane>\n </kendo-splitter>\n } @else {\n <!-- No sidebar - full width chat -->\n <div class=\"chat-area\">\n <!-- Messages Container -->\n <div class=\"messages-container\" #messagesContainer>\n @if (conversationMessages.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\n }\n\n @for (message of conversationMessages; track message.id) {\n <div [ngClass]=\"getMessageClass(message)\">\n <div class=\"message-header\">\n <span class=\"message-role\">\n @if (message.role === 'user') {\n <i class=\"fa-solid fa-user\"></i> You\n } @else {\n <i class=\"fa-solid fa-robot\"></i> {{ getEntityName() || 'Assistant' }}\n }\n </span>\n <span class=\"message-time\">{{ formatTimestamp(message.timestamp) }}</span>\n @if (message.isStreaming && message.elapsedTime !== undefined) {\n <span class=\"execution-time streaming\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> {{ formatElapsedTime(message.elapsedTime) }}\n </span>\n } @else if (message.executionTime) {\n <span class=\"execution-time\" [title]=\"getExecutionSummary(message)\">{{ formatExecutionTime(message.executionTime) }}</span>\n }\n @if (showRawToggle(message)) {\n <button class=\"raw-toggle\" (click)=\"showRawJsonDialog(message)\" title=\"View raw JSON response\">\n <i class=\"fa-solid fa-code\"></i>\n </button>\n }\n @if (message.executionData && mode === 'agent' && message.role === 'assistant') {\n <button class=\"execution-history-toggle\" (click)=\"showMessageExecutionHistory(message)\" title=\"View execution details\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\">{{ message.streamingContent }}<span class=\"cursor\">|</span></span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Input Area -->\n <div class=\"input-area\">\n <div class=\"input-container\">\n <kendo-textarea\n #messageInput\n [(ngModel)]=\"currentUserMessage\"\n [rows]=\"3\"\n placeholder=\"Type your message here... (Press Enter to send, Shift+Enter for new line)\"\n (keypress)=\"handleKeyPress($event)\"\n [disabled]=\"isExecuting\"\n class=\"message-input\">\n </kendo-textarea>\n <button\n class=\"send-button\"\n (click)=\"sendMessage()\"\n [disabled]=\"isExecuting || !currentUserMessage.trim()\"\n title=\"Send message\">\n @if (isExecuting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n }\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Save Conversation Dialog -->\n @if (showSaveDialog) {\n <kendo-dialog \n [title]=\"'Save Conversation'\" \n [width]=\"400\"\n (close)=\"cancelSaveDialog()\"\n class=\"save-dialog\">\n <div class=\"dialog-content\">\n <p>Enter a name for this conversation:</p>\n <input \n #saveDialogInput\n type=\"text\"\n (keyup)=\"updateTempConversation()\"\n placeholder=\"Conversation name\"\n class=\"k-textbox k-input k-input-md k-rounded-md k-input-solid full-width\" />\n </div>\n <kendo-dialog-actions>\n <button kendoButton (click)=\"cancelSaveDialog()\">Cancel</button>\n <button kendoButton \n [primary]=\"true\" \n (click)=\"confirmSaveConversation()\"\n [disabled]=\"tempConversationName === ''\">\n Save\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n \n <!-- Load Confirmation Dialog -->\n @if (showLoadConfirmDialog) {\n <kendo-dialog \n [title]=\"'Replace Current Conversation?'\" \n [width]=\"400\"\n (close)=\"cancelLoadConversation()\"\n class=\"confirm-dialog\">\n <div class=\"dialog-content\">\n <p>Loading this conversation will replace the current one. Any unsaved changes will be lost.</p>\n <p>Do you want to continue?</p>\n </div>\n <kendo-dialog-actions>\n <button kendoButton (click)=\"cancelLoadConversation()\">Cancel</button>\n <button kendoButton \n [primary]=\"true\" \n (click)=\"confirmLoadConversation()\">\n Load Conversation\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n\n <!-- JSON Display Dialog -->\n @if (showJsonDialog) {\n <kendo-window \n [title]=\"'Raw JSON Response'\" \n [width]=\"900\" \n [height]=\"700\"\n [minWidth]=\"600\"\n [minHeight]=\"400\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [state]=\"'default'\"\n [keepContent]=\"true\"\n (close)=\"closeJsonDialog()\"\n class=\"json-dialog-window\">\n <div class=\"json-dialog-content\">\n <div class=\"json-dialog-header\">\n <button class=\"custom-button icon-only\" (click)=\"copyJsonContent()\" title=\"Copy JSON\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n <div class=\"json-dialog-body\">\n <mj-code-editor \n [(ngModel)]=\"currentJsonContent\"\n [readonly]=\"true\"\n [language]=\"'json'\"\n [lineWrapping]=\"true\"\n style=\"height: 100%; width: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n </kendo-window>\n }", styles: ["/* Container Styles */\n.harness-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n}\n\n/* Custom Button Styles */\n.custom-button {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.custom-button:hover:not(:disabled) {\n background: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.custom-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.custom-button.icon-only {\n padding: 6px 8px;\n}\n\n.custom-button i {\n font-size: 14px;\n}\n\n/* Send Button - Primary Style */\n.send-button {\n background: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\n border-radius: 4px;\n padding: 8px 16px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n font-family: inherit;\n}\n\n.send-button:hover:not(:disabled) {\n background: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\n}\n\n.send-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.send-button i {\n font-size: 16px;\n}\n\n/* Add Button */\n.add-button {\n background: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.add-button:hover {\n background: #0d6efd;\n color: white;\n}\n\n/* Remove/Delete Buttons */\n.remove-button,\n.delete-button {\n background: transparent;\n border: none;\n color: #dc3545;\n padding: 4px 8px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.remove-button:hover,\n.delete-button:hover {\n background: rgba(220, 53, 69, 0.1);\n color: #bd2130;\n}\n\n/* Copy Button in Message Bubble */\n.copy-button-in-bubble {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n padding: 6px;\n font-size: 14px;\n color: #adb5bd;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0;\n z-index: 10; /* Ensure it's above content */\n}\n\n.message-content:hover .copy-button-in-bubble {\n opacity: 1;\n}\n\n.copy-button-in-bubble:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #6c757d;\n}\n\n.copy-button-in-bubble i {\n font-size: 14px;\n}\n\n/* Model Settings Styles (Prompt Mode) */\n.model-settings {\n padding: 16px;\n}\n\n.setting-group {\n margin-bottom: 24px;\n}\n\n.setting-group label {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: #495057;\n font-size: 14px;\n}\n\n.model-selector {\n width: 100%;\n}\n\n.temperature-slider {\n width: 100%;\n margin-top: 8px;\n}\n\n.max-tokens-input {\n width: 100%;\n}\n\n.setting-help {\n margin-top: 6px;\n font-size: 12px;\n color: #6c757d;\n font-style: italic;\n}\n\n/* Header Styles */\n.harness-header {\n background: white;\n border-bottom: 1px solid #dee2e6;\n padding: 16px 20px;\n}\n\n.agent-info {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.agent-details {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.agent-details i {\n font-size: 28px;\n color: #17a2b8;\n}\n\n.agent-details h3 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.agent-details p {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n/* Body Layout */\n.harness-body {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Chat Area */\n.chat-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: white;\n border-right: 1px solid #dee2e6;\n height: 100%;\n min-height: 0; /* Important for flexbox children */\n}\n\n/* Messages Container */\n.messages-container {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: #6c757d;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Message Styles */\n.message {\n margin-bottom: 20px;\n animation: fadeIn 0.3s ease-in;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.message-user {\n margin-left: auto;\n max-width: 70%;\n}\n\n.message-assistant {\n margin-right: auto;\n max-width: 70%;\n}\n\n.message-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 13px;\n}\n\n.message-role {\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role i {\n font-size: 14px;\n}\n\n.message-user .message-role {\n color: #6f42c1;\n}\n\n.message-assistant .message-role {\n color: #17a2b8;\n}\n\n.message-time {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\n cursor: pointer;\n transition: all 0.2s;\n margin-left: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n}\n\n.raw-toggle:hover {\n background: rgba(0, 0, 0, 0.05);\n color: #495057;\n}\n\n.raw-toggle i {\n font-size: 12px;\n}\n\n/* Message content styles are now defined above in enhanced content formatting section */\n\n.message-user .message-content {\n background: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant .message-content {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming .message-content {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\n}\n\n.streaming-content {\n display: inline;\n}\n\n.streaming-wrapper {\n position: relative;\n}\n\n.cursor {\n animation: blink 1s infinite;\n font-weight: 100;\n color: #495057;\n}\n\n@keyframes blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n.error-details {\n margin-top: 8px;\n padding: 8px 12px;\n background: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details i {\n color: #dc3545;\n}\n\n/* Dialog styles */\n.save-dialog,\n.confirm-dialog {\n .dialog-content {\n padding: 20px;\n \n p {\n margin: 0 0 16px 0;\n color: #333;\n font-size: 14px;\n line-height: 1.5;\n \n &:last-child {\n margin-bottom: 0;\n }\n }\n \n .full-width {\n width: 100%;\n }\n \n input.k-textbox {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\n }\n }\n }\n}\n\n/* Enhanced content formatting styles */\n.markdown-content {\n line-height: 1.6;\n word-wrap: break-word;\n overflow-wrap: break-word;\n max-width: 100%;\n}\n\n/* Inline JSON editor styles */\n.inline-json-editor {\n margin: 8px 0;\n \n .json-editor-container {\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n max-height: 400px;\n \n pre {\n margin: 0;\n padding: 12px;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n height: 100%;\n background: transparent;\n color: #333;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n }\n}\n\n.markdown-paragraph {\n margin: 8px 0;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.markdown-h1 {\n font-size: 1.5em;\n font-weight: 600;\n margin: 16px 0 8px 0;\n color: #212529;\n border-bottom: 2px solid #e9ecef;\n padding-bottom: 4px;\n}\n\n.markdown-h2 {\n font-size: 1.3em;\n font-weight: 600;\n margin: 14px 0 6px 0;\n color: #212529;\n border-bottom: 1px solid #e9ecef;\n padding-bottom: 2px;\n}\n\n.markdown-h3 {\n font-size: 1.1em;\n font-weight: 600;\n margin: 12px 0 4px 0;\n color: #212529;\n}\n\n.code-block {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n padding: 16px;\n margin: 12px 0;\n overflow-x: auto;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n color: #212529;\n white-space: pre;\n word-wrap: normal;\n max-width: 100%;\n}\n\n.code-block code {\n background: none;\n border: none;\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre;\n word-wrap: normal;\n}\n\n.language-json {\n color: #d73e48;\n}\n\n.inline-code {\n background: #f1f3f4;\n border: 1px solid #dadce0;\n border-radius: 4px;\n padding: 2px 6px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 0.9em;\n color: #d73e48;\n white-space: nowrap;\n}\n\n.markdown-list {\n margin: 8px 0;\n padding-left: 24px;\n}\n\n.markdown-list li {\n margin: 4px 0;\n line-height: 1.5;\n}\n\n.markdown-link {\n color: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n/* Ensure proper text wrapping in message content */\n.message-content {\n background: #f8f9fa;\n border-radius: 12px;\n padding: 12px 40px 12px 16px; /* Extra right padding for copy button */\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n position: relative;\n overflow-wrap: break-word;\n hyphens: auto;\n max-width: 100%;\n overflow-x: hidden;\n}\n\n/* Enhanced JSON content display */\n.json-content-wrapper {\n margin: 8px 0;\n}\n\n.json-main-content {\n margin-bottom: 12px;\n}\n\n.json-raw-section {\n margin-top: 12px;\n}\n\n.json-toggle-button {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.json-toggle-button:hover {\n background: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.json-toggle-button i {\n font-size: 12px;\n}\n\n/* Compact code block for JSON in collapsible sections */\n.json-raw-section .code-block {\n margin: 8px 0 0 0;\n font-size: 12px;\n max-height: 300px;\n overflow-y: auto;\n}\n\n/* Better mobile responsiveness for JSON content */\n@media (max-width: 768px) {\n .json-raw-section .code-block {\n font-size: 11px;\n max-height: 200px;\n }\n}\n\n/* JSON raw section styling - simplified since we use code editor in dialog */\n.json-raw-section {\n margin-top: 12px;\n}\n\n/* Input Area */\n.input-area {\n padding: 16px;\n background: white;\n border-top: 1px solid #dee2e6;\n flex-shrink: 0; /* Prevent input area from shrinking */\n margin-top: auto; /* Push to bottom */\n}\n\n.input-container {\n display: flex;\n gap: 12px;\n align-items: center;\n}\n\n.message-input {\n flex: 1;\n}\n\n.message-input textarea {\n resize: none;\n font-size: 14px;\n}\n\n.send-button {\n margin-bottom: 1px;\n}\n\n/* Sidebar */\n.sidebar {\n width: 100%; /* Changed from fixed 360px to 100% */\n background: white;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n/* Kendo Splitter Specific Styles */\n.harness-body kendo-splitter {\n height: 100%;\n}\n\n.harness-body kendo-splitter-pane {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Sidebar Tabs */\n.sidebar-tabs {\n display: flex;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.tab-button {\n flex: 1;\n padding: 12px 8px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: #6c757d;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.tab-button:hover {\n background: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\n}\n\n.tab-button i {\n font-size: 14px;\n}\n\n.tab-button .badge {\n background: #6c757d;\n color: white;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n margin-left: 4px;\n}\n\n.tab-button.active .badge {\n background: #0d6efd;\n}\n\n.tab-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* Sidebar Content */\n.sidebar-content {\n flex: 1;\n overflow-y: auto;\n width: 100%; /* Ensure content takes full width */\n}\n\n.tab-content {\n padding: 20px;\n width: 100%; /* Ensure content takes full width */\n box-sizing: border-box; /* Include padding in width calculation */\n}\n\n.tab-header {\n margin-bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.tab-header h4 {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: #212529;\n}\n\n.tab-header p {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\n}\n\n.tab-header .custom-button.small {\n align-self: flex-start;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n.tab-header .custom-button.small i {\n margin-right: 4px;\n}\n\n/* Variables */\n.variables-list {\n margin-bottom: 16px;\n width: 100%;\n}\n\n.variable-item {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n align-items: center;\n width: 100%;\n}\n\n.variable-name {\n width: 30%; /* Changed from fixed width to percentage */\n min-width: 100px;\n}\n\n.variable-type {\n width: 25%; /* Changed from fixed width to percentage */\n min-width: 80px;\n}\n\n.variable-value {\n flex: 1;\n min-width: 0; /* Allow flex item to shrink below content size */\n}\n\n.remove-button {\n width: 32px;\n height: 32px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.add-variable-button {\n width: 100%;\n}\n\n.empty-variables {\n text-align: center;\n padding: 40px 20px;\n color: #6c757d;\n}\n\n/* Saved Conversations */\n.saved-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved {\n text-align: center;\n padding: 40px 20px;\n color: #6c757d;\n}\n\n.empty-saved i {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.saved-item {\n border: 1px solid #dee2e6;\n border-radius: 8px;\n padding: 12px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.saved-item:hover {\n background: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current {\n background: #e7f3ff;\n border-color: #0d6efd;\n}\n\n.saved-info h5 {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: #212529;\n}\n\n.saved-info p {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date {\n font-size: 11px;\n color: #6c757d;\n}\n\n/* Responsive adjustments */\n@media (max-width: 1200px) {\n .sidebar {\n width: 320px;\n }\n}\n\n@media (max-width: 992px) {\n .message-user,\n .message-assistant {\n max-width: 85%;\n }\n \n .sidebar {\n width: 280px;\n }\n}\n\n/* Custom scrollbar */\n.messages-container::-webkit-scrollbar,\n.sidebar-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.messages-container::-webkit-scrollbar-track,\n.sidebar-content::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.messages-container::-webkit-scrollbar-thumb,\n.sidebar-content::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 4px;\n}\n\n.messages-container::-webkit-scrollbar-thumb:hover,\n.sidebar-content::-webkit-scrollbar-thumb:hover {\n background: #a1a1a1;\n}\n\n/* Dialog customization */\n::ng-deep .ai-agent-test-harness .k-dialog-wrapper {\n border-radius: 8px;\n overflow: hidden;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-titlebar {\n background: #343a40;\n color: white;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-title {\n font-weight: 600;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-titlebar-actions .k-button {\n color: white;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-content {\n padding: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* JSON Dialog Styles */\n.json-dialog-window {\n /* Center the dialog on screen */\n ::ng-deep .k-window {\n position: fixed !important;\n top: 50% !important;\n left: 50% !important;\n transform: translate(-50%, -50%) !important;\n margin: 0 !important;\n }\n \n ::ng-deep .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n \n ::ng-deep .k-window-titlebar {\n .k-window-title {\n font-size: 16px;\n font-weight: 500;\n }\n \n .k-window-actions {\n button {\n background: transparent;\n border: none;\n color: #666;\n padding: 8px 12px;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.2s;\n \n &:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #333;\n }\n \n i {\n font-size: 14px;\n }\n }\n }\n }\n}\n\n.json-dialog-content {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n overflow: hidden;\n}\n\n.json-dialog-header {\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n display: flex;\n justify-content: flex-end;\n align-items: center;\n flex-shrink: 0;\n}\n\n.json-dialog-body {\n flex: 1;\n overflow: auto;\n padding: 0;\n position: relative;\n min-height: 0;\n \n mj-code-editor {\n display: block;\n height: 100%;\n \n ::ng-deep .cm-editor {\n height: 100%;\n \n .cm-scroller {\n overflow: auto !important;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n }\n }\n }\n}"] }]
2634
- }], () => [{ type: i1.DomSanitizer }], { mode: [{
2635
- type: Input
2636
- }], entity: [{
2637
- type: Input
2638
- }], aiAgent: [{
2639
- type: Input
2640
- }], isVisible: [{
2641
- type: Input
2642
- }], visibilityChange: [{
2643
- type: Output
2644
- }], messagesContainer: [{
2645
- type: ViewChild,
2646
- args: ['messagesContainer']
2647
- }], fileInput: [{
2648
- type: ViewChild,
2649
- args: ['fileInput']
2650
- }], messageInput: [{
2651
- type: ViewChild,
2652
- args: ['messageInput']
2653
- }], saveDialogInput: [{
2654
- type: ViewChild,
2655
- args: ['saveDialogInput']
2656
- }] }); })();
2657
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "src/lib/custom/AIAgents/ai-test-harness.component.ts", lineNumber: 135 }); })();
2658
- //# sourceMappingURL=ai-test-harness.component.js.map