@c8y/ngx-components 1023.92.0 → 1023.97.3

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 (111) hide show
  1. package/ai/agents/scada/index.d.ts +10 -0
  2. package/ai/agents/scada/index.d.ts.map +1 -0
  3. package/ai/ai-chat/index.d.ts +1 -1
  4. package/ai/ai-chat/index.d.ts.map +1 -1
  5. package/alarms/index.d.ts.map +1 -1
  6. package/computed-asset-properties/index.d.ts +89 -1
  7. package/computed-asset-properties/index.d.ts.map +1 -1
  8. package/context-dashboard/device/view/index.d.ts +24 -1
  9. package/context-dashboard/device/view/index.d.ts.map +1 -1
  10. package/context-dashboard/index.d.ts +27 -11
  11. package/context-dashboard/index.d.ts.map +1 -1
  12. package/echart/index.d.ts.map +1 -1
  13. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +2 -2
  14. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-ai-agents-scada.mjs +893 -0
  16. package/fesm2022/c8y-ngx-components-ai-agents-scada.mjs.map +1 -0
  17. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +1 -0
  18. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-alarms.mjs +12 -5
  20. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-asset-properties.mjs +2 -2
  22. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  23. package/fesm2022/{c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-Cy9R6Ixb.mjs → c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-CHZX7ALq.mjs} +10 -9
  24. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-CHZX7ALq.mjs.map +1 -0
  25. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-LrmlAh6V.mjs → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-DgWGXzEx.mjs} +2 -2
  26. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-LrmlAh6V.mjs.map → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-DgWGXzEx.mjs.map} +1 -1
  27. package/fesm2022/{c8y-ngx-components-computed-asset-properties-last-measurement-config.component-f1u1TcCl.mjs → c8y-ngx-components-computed-asset-properties-last-measurement-config.component-yfc45-l_.mjs} +2 -2
  28. package/fesm2022/{c8y-ngx-components-computed-asset-properties-last-measurement-config.component-f1u1TcCl.mjs.map → c8y-ngx-components-computed-asset-properties-last-measurement-config.component-yfc45-l_.mjs.map} +1 -1
  29. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -1
  30. package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs +21 -3
  31. package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs.map +1 -1
  32. package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs +2 -2
  33. package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs.map +1 -1
  34. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +69 -51
  35. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  36. package/fesm2022/c8y-ngx-components-echart.mjs +52 -36
  37. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  38. package/fesm2022/c8y-ngx-components-global-context.mjs +112 -22
  39. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  40. package/fesm2022/c8y-ngx-components-map.mjs +15 -0
  41. package/fesm2022/c8y-ngx-components-map.mjs.map +1 -1
  42. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +292 -115
  43. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  44. package/fesm2022/c8y-ngx-components-repository-firmware.mjs +2 -2
  45. package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
  46. package/fesm2022/c8y-ngx-components-repository-software.mjs +1 -1
  47. package/fesm2022/c8y-ngx-components-repository-software.mjs.map +1 -1
  48. package/fesm2022/c8y-ngx-components-upgrade.mjs +12 -1
  49. package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
  50. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +2 -1
  51. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
  52. package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs +169 -0
  53. package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs.map +1 -0
  54. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs +2 -1
  55. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs.map +1 -1
  56. package/fesm2022/c8y-ngx-components-widgets-exports.mjs +8 -1
  57. package/fesm2022/c8y-ngx-components-widgets-exports.mjs.map +1 -1
  58. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs +2 -2
  59. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs.map +1 -1
  60. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +3 -3
  61. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  62. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs +2 -2
  63. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs.map +1 -1
  64. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +2 -2
  65. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
  66. package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs +2 -2
  67. package/fesm2022/c8y-ngx-components-widgets-implementations-events.mjs.map +1 -1
  68. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +90 -32
  69. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
  70. package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs +2 -2
  71. package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs.map +1 -1
  72. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1698 -0
  73. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -0
  74. package/fesm2022/c8y-ngx-components.mjs +220 -45
  75. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  76. package/global-context/index.d.ts +58 -3
  77. package/global-context/index.d.ts.map +1 -1
  78. package/index.d.ts +79 -22
  79. package/index.d.ts.map +1 -1
  80. package/locales/de.po +165 -3
  81. package/locales/es.po +165 -3
  82. package/locales/fr.po +165 -3
  83. package/locales/ja_JP.po +165 -3
  84. package/locales/ko.po +165 -3
  85. package/locales/locales.pot +156 -3
  86. package/locales/nl.po +165 -3
  87. package/locales/pl.po +165 -3
  88. package/locales/pt_BR.po +165 -3
  89. package/locales/zh_CN.po +165 -3
  90. package/locales/zh_TW.po +165 -3
  91. package/map/index.d.ts.map +1 -1
  92. package/package.json +1 -1
  93. package/repository/configuration/index.d.ts +64 -39
  94. package/repository/configuration/index.d.ts.map +1 -1
  95. package/upgrade/index.d.ts +1 -0
  96. package/upgrade/index.d.ts.map +1 -1
  97. package/widgets/cockpit-exports/index.d.ts +6 -0
  98. package/widgets/cockpit-exports/index.d.ts.map +1 -1
  99. package/widgets/definitions/index.d.ts +1 -0
  100. package/widgets/definitions/index.d.ts.map +1 -1
  101. package/widgets/definitions/scada/index.d.ts +6 -0
  102. package/widgets/definitions/scada/index.d.ts.map +1 -0
  103. package/widgets/device-management-exports/index.d.ts +6 -0
  104. package/widgets/device-management-exports/index.d.ts.map +1 -1
  105. package/widgets/exports/index.d.ts +8 -1
  106. package/widgets/exports/index.d.ts.map +1 -1
  107. package/widgets/implementations/html-widget/index.d.ts +30 -12
  108. package/widgets/implementations/html-widget/index.d.ts.map +1 -1
  109. package/widgets/implementations/scada/index.d.ts +415 -0
  110. package/widgets/implementations/scada/index.d.ts.map +1 -0
  111. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-Cy9R6Ixb.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c8y-ngx-components-ai-agents-scada.mjs","sources":["../../ai/agents/scada/scada-svg.agent.c8y.ts","../../ai/agents/scada/scada-svg-agent.definition.ts","../../ai/agents/scada/c8y-ngx-components-ai-agents-scada.ts"],"sourcesContent":["import type { AgentDefinition } from '@c8y/ngx-components/ai';\n\nexport const SCADA_OUTPUT_TAG_NAME = 'c8y-scada-output';\nexport const SVG_EXTRACT_TAG_NAME = 'c8y-svg-extract';\nexport const MAPPING_EXTRACT_TAG_NAME = 'c8y-mapping-extract';\n\nconst SVG_SCADA_INSTRUCTIONS = `You are responsible for creating an SVG visualization for a SCADA (Supervisory Control and Data Acquisition) widget in the Cumulocity IoT Platform. Your task is to design industrial system or device visualizations based on user descriptions.\n\n## Core Requirements\n\n1. **Output Format**: Wrap BOTH outputs together in a single <${SCADA_OUTPUT_TAG_NAME}> block:\n - Clean, well-structured SVG code wrapped in <${SVG_EXTRACT_TAG_NAME}> tags (inside the wrapper)\n - Placeholder mapping configuration wrapped in <${MAPPING_EXTRACT_TAG_NAME}> tags (inside the wrapper)\n - Both inner tags MUST appear inside the <${SCADA_OUTPUT_TAG_NAME}> wrapper — never at the top level\n2. **No Emojis**: Do not include any emoji characters or Unicode symbols - use text descriptions or SVG shapes instead\n3. **Viewbox**: Always include a properly sized viewBox attribute for responsive scaling\n4. **Organized Structure**: Group related elements using <g> tags with meaningful class names or IDs\n\n## Basic SVG Structure\n\n<${SCADA_OUTPUT_TAG_NAME}>\n <${SVG_EXTRACT_TAG_NAME}>\n <?xml version=\"1.0\" encoding=\"utf-8\"?>\n <svg viewBox=\"0 0 800 600\" xmlns=\"http://www.w3.org/2000/svg\">\n <style>\n /* Use Cumulocity CSS variables for theming */\n .text-primary {\n fill: var(--c8y-root-component-color-default);\n font-family: var(--c8y-font-family-base);\n }\n .brand-color {\n fill: var(--c8y-brand-primary);\n }\n /* Additional styles */\n </style>\n \n <!-- Background -->\n <rect width=\"800\" height=\"600\" fill=\"var(--c8y-root-component-background-default)\" />\n \n <!-- Your SCADA visualization elements here -->\n </svg>\n </${SVG_EXTRACT_TAG_NAME}>\n <${MAPPING_EXTRACT_TAG_NAME}>\n { \"placeholderName\": { \"assetProperty\": { ... } } }\n </${MAPPING_EXTRACT_TAG_NAME}>\n</${SCADA_OUTPUT_TAG_NAME}>\n\n## Current Device Context\n\nThe context device object structure is as follows:\n{{ c8yContext }}\n\nThe device supports the following measurements:\n{{ c8yContextMeasurements }}\n\n## Placeholder Mapping Output\n\nInside the <${SCADA_OUTPUT_TAG_NAME}> wrapper, after the SVG code, you MUST output a placeholder mapping configuration that defines how each placeholder in your SVG maps to device data. This mapping is wrapped in <${MAPPING_EXTRACT_TAG_NAME}> tags and contains a JSON object.\n\n### Mapping Format\n\nThe mapping object structure is:\n\\`\\`\\`json\n{\n \"placeholderName\": {\n \"assetProperty\": {\n // Property configuration object, including asset info like:\n \"asset\": {\n \"id\": 12345,\n \"name\": \"Asset name\"\n }\n }\n }\n}\n\\`\\`\\`\n\n### Two Types of Mappings\n\n#### 1. Regular Property Mapping\n\nFor direct mappings to device properties (like name, ID, status, or custom properties):\n\n\\`\\`\\`json\n{\n \"deviceName\": {\n \"assetProperty\": {\n \"isEditable\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"name\": {\n \"label\": \"Device Name\",\n \"type\": \"string\",\n \"key\": \"name\",\n \"properties\": {}\n }\n }\n },\n \"name\": \"name\",\n \"active\": true,\n \"label\": \"Device Name\",\n \"type\": \"string\",\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n }\n}\n\\`\\`\\`\n\n#### 2. Computed Property Mapping (e.g. Last Measurement)\n\nFor measurements or computed properties (like last measurement, alarms count, etc.):\n\n\\`\\`\\`json\n{\n \"temperature\": {\n \"assetProperty\": {\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"lastMeasurement\": {\n \"label\": \"Last measurement\",\n \"type\": \"string\"\n }\n }\n },\n \"name\": \"lastMeasurement\",\n \"label\": \"Last measurement\",\n \"type\": \"string\",\n \"config\": {\n \"dp\": [\n {\n \"fragment\": \"c8y_Battery\",\n \"series\": \"level\",\n \"label\": \"c8y_Battery → level\",\n \"unit\": \"%\",\n \"__target\": {\n \"id\": \"94130201\",\n \"name\": \"Temperature #1\"\n },\n \"color\": \"#347928\",\n \"__active\": true,\n \"__template\": null,\n \"renderType\": \"min\",\n \"lineType\": \"line\",\n \"yAxisType\": null\n }\n ],\n \"resultType\": 4\n },\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n }\n}\n\\`\\`\\`\n\n### Guidelines for Creating Mappings\n**CRITICAL: When mapping to computed properties (such as last measurements, asset/device counts, alarm/event counts, etc.), you MUST use the correct property names and configuration as supported by Cumulocity. Never guess or invent property names; always check and use the actual names and structure as shown below.**\n\n#### Supported Computed Properties\n\nBesides \"Last measurement\", Cumulocity supports several other computed properties for SCADA widget mappings. Examples:\n\n\\`\\`\\`json\n{\n \"childAssetsCount\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"childAssetsCount\": {\n \"label\": \"Number of child assets\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"childAssetsCount\",\n \"label\": \"Number of child assets\",\n \"type\": \"number\",\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"childDevicesCount\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"childDevicesCount\": {\n \"label\": \"Number of child devices\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"childDevicesCount\",\n \"label\": \"Number of child devices\",\n \"type\": \"number\",\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"alarmCount3Months\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"alarmCount3Months\": {\n \"label\": \"Alarm count 3 months\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"alarmCount3Months\",\n \"label\": \"Alarm count 3 months\",\n \"type\": \"number\",\n \"config\": {\n \"type\": \"c8y_myAlarm\",\n \"severities\": {\n \"CRITICAL\": true,\n \"MAJOR\": true,\n \"MINOR\": true,\n \"WARNING\": true\n }\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"alarmCountLastWeek\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"alarmCountLastWeek\": {\n \"label\": \"Alarm count last week\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"alarmCountLastWeek\",\n \"label\": \"Alarm count last week\",\n \"type\": \"number\",\n \"config\": {\n \"type\": \"myAlarm\"\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"alarmCountToday\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"alarmCountToday\": {\n \"label\": \"Alarm count today\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"alarmCountToday\",\n \"label\": \"Alarm count today\",\n \"type\": \"number\",\n \"config\": {\n \"type\": \"MyTodayAlarm\",\n \"severities\": {\n \"CRITICAL\": true,\n \"MAJOR\": true,\n \"MINOR\": true,\n \"WARNING\": true\n }\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"eventCount3Months\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"eventCount3Months\": {\n \"label\": \"Event count 3 months\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"eventCount3Months\",\n \"label\": \"Event count 3 months\",\n \"type\": \"number\",\n \"config\": {\n \"type\": \"myEventType\"\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n },\n \"eventCountToday\": {\n \"assetProperty\": {\n \"computed\": true,\n \"isEditable\": false,\n \"isStandardProperty\": true,\n \"active\": true,\n \"temporary\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"eventCountToday\": {\n \"label\": \"Event count today\",\n \"type\": \"number\"\n }\n }\n },\n \"name\": \"eventCountToday\",\n \"label\": \"Event count today\",\n \"type\": \"number\",\n \"config\": {\n \"type\": \"myEventType2\"\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature #1\"\n }\n }\n }\n}\n\\`\\`\\`\n\n**Usage:**\n- Use the placeholder name (e.g., \\`childAssetsCount\\`, \\`alarmCountToday\\`) in your SVG template as \\`c8yScadaValues?.childAssetsCount\\`, \\`c8yScadaValues?.alarmCountToday\\`, etc.\n- These properties are read-only and computed by Cumulocity, and can be mapped in the widget configuration.\n\n**For alarm/event counts:**\n- You may specify severity filters and type in the \\`config\\` object as shown above (providing type is required).\n\n**For asset/device counts:**\n- No additional config is needed; just use the property name.\n\n**For measurements:**\n- Continue to use the existing measurement mapping format.\n\n**CRITICAL: When mapping to last measurements, you MUST use the correct, existing measurement fragment and series as verified by the cumulocity-api-request tool. Never guess or invent fragment/series names; always check and use the actual names from the API tool.**\n\n1. **Match Placeholder Names**: The keys in the mapping object must exactly match the placeholder names used in your SVG (e.g., if you use \\${this.c8yScadaValues?.temperature?.value}, create a mapping for \"temperature\")\n\n2. **Set Context Device Info**: Set the \"asset\" object inside \"assetProperty\" with the \"id\" and \"name\" from the context device object provided\n\n3. **Choose Appropriate Type**:\n - For measurements: Use computed property format with \"computed\": true, \"isStandardProperty\": true, and include \"config\" with data point configuration\n - For device properties: Use regular property format with \"isEditable\": true\n\n4. **Data Point Configuration**: For measurements, configure the \"dp\" array with:\n - **fragment**: The measurement fragment name (e.g., \"c8y_Temperature\", \"c8y_Battery\")\n - **series**: The series name within the fragment\n - **unit**: The unit of measurement\n - **label**: A descriptive label\n - **__target**: Reference to the target device with name and id\n - **resultType**: MUST always be \\`4\\` — this is the only value that returns the complete measurement object, giving access to \\`.value\\` and \\`.unit\\` sub-properties\n\n5. **Generate Unique Instance IDs**: For computed properties, include a unique \"instanceId\" (use UUID format)\n\n### Example Complete Output\n\nFor an SVG that uses placeholders \\${this.c8yScadaValues?.temperature?.value}, \\${this.c8yScadaValues?.pressure?.value}, and \\${this.c8yScadaValues?.deviceName}:\n\n<${SCADA_OUTPUT_TAG_NAME}>\n <${SVG_EXTRACT_TAG_NAME}>\n <!-- SVG code here -->\n </${SVG_EXTRACT_TAG_NAME}>\n <${MAPPING_EXTRACT_TAG_NAME}>\n {\n \"temperature\": {\n \"assetProperty\": {\n \"temporary\": true,\n \"instanceId\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"computed\": true,\n \"isEditable\": false,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"lastMeasurement\": {\n \"label\": \"Last measurement\",\n \"type\": \"string\"\n }\n }\n },\n \"name\": \"lastMeasurement\",\n \"active\": true,\n \"isStandardProperty\": true,\n \"label\": \"Last measurement\",\n \"contextAssetId\": \"94130201\",\n \"type\": \"string\",\n \"config\": {\n \"dp\": [\n {\n \"fragment\": \"c8y_Temperature\",\n \"unit\": \"°C\",\n \"color\": \"#347928\",\n \"series\": \"T\",\n \"lineType\": \"line\",\n \"__active\": true,\n \"__template\": null,\n \"label\": \"c8y_Temperature → T\",\n \"renderType\": \"min\",\n \"yAxisType\": null,\n \"__target\": {\n \"name\": \"Temperature Sensor\",\n \"id\": \"94130201\"\n }\n }\n ],\n \"resultType\": 4\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature Sensor\"\n }\n }\n },\n \"pressure\": {\n \"assetProperty\": {\n \"temporary\": true,\n \"instanceId\": \"b2c3d4e5-f6a7-8901-bcde-f12345678901\",\n \"computed\": true,\n \"isEditable\": false,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"lastMeasurement\": {\n \"label\": \"Last measurement\",\n \"type\": \"string\"\n }\n }\n },\n \"name\": \"lastMeasurement\",\n \"active\": true,\n \"isStandardProperty\": true,\n \"label\": \"Last measurement\",\n \"contextAssetId\": \"94130201\",\n \"type\": \"string\",\n \"config\": {\n \"dp\": [\n {\n \"fragment\": \"c8y_Pressure\",\n \"unit\": \"kPa\",\n \"color\": \"#2196F3\",\n \"series\": \"pressure\",\n \"lineType\": \"line\",\n \"__active\": true,\n \"__template\": null,\n \"label\": \"c8y_Pressure → pressure\",\n \"renderType\": \"min\",\n \"yAxisType\": null,\n \"__target\": {\n \"name\": \"Pressure Sensor\",\n \"id\": \"94130201\"\n }\n }\n ],\n \"resultType\": 4\n },\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Pressure Sensor\"\n }\n }\n },\n \"deviceName\": {\n \"assetProperty\": {\n \"isEditable\": true,\n \"c8y_JsonSchema\": {\n \"properties\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"string\",\n \"key\": \"name\",\n \"properties\": {}\n }\n }\n },\n \"name\": \"name\",\n \"active\": true,\n \"label\": \"Name\",\n \"type\": \"string\",\n \"asset\": {\n \"id\": 94130201,\n \"name\": \"Temperature Sensor\"\n }\n }\n }\n }\n </${MAPPING_EXTRACT_TAG_NAME}>\n</${SCADA_OUTPUT_TAG_NAME}>\n\n## Data Binding Syntax\n\nYou can make your SVG dynamic by binding to data values using template literal syntax:\n\n### Accessing Device Data\n\n**IMPORTANT**: To use and display ANY value from the context device object or its measurements, you MUST use the \\`c8yScadaValues\\` syntax. This is the ONLY correct way to access device data because:\n1. It creates a placeholder in the data mapping list during widget configuration\n2. The placeholder will be automatically bound to the appropriate data source from the context device\n3. This enables proper data flow from the device to your visualization\n\n**Do NOT** attempt to access device properties directly (e.g., \\${this.device?.property}) or use any other syntax. Always use \\`c8yScadaValues\\` with a short, descriptive placeholder name.\n\n### Two Types of Data Access\n\n#### 1. For Device Measurements (with subproperties)\n\nWhen a placeholder will be mapped to a **device measurement**, use the subproperties:\n- **\\${this.c8yScadaValues?.placeholderName?.value}** - The numeric value of the measurement (may be a number or a numeric string)\n- **\\${this.c8yScadaValues?.placeholderName?.unit}** - The unit of measurement (e.g., \"°C\", \"kPa\", \"%\")\n\n**IMPORTANT — numeric formatting:** \\`.value\\` may be a number or a numeric string. **Never call \\`.toFixed()\\` by default** — it will throw for string values. Only add decimal formatting when the user explicitly requests it, and always convert first: \\`Number(this.c8yScadaValues?.pressure?.value).toFixed(2)\\`.\n\n\\`\\`\\`xml\n<!-- Display temperature value with units -->\n<text x=\"100\" y=\"50\">\\${this.c8yScadaValues?.temperature?.value || '-'} \\${this.c8yScadaValues?.temperature?.unit || ''}</text>\n\n<!-- Display pressure value with units -->\n<text x=\"100\" y=\"100\">Pressure: \\${this.c8yScadaValues?.pressure?.value || '-'} \\${this.c8yScadaValues?.pressure?.unit || 'kPa'}</text>\n\n<!-- Display measurement with timestamp -->\n<text x=\"100\" y=\"150\">Level: \\${this.c8yScadaValues?.level?.value || '-'}% (Updated: \\${this.c8yScadaValues?.level?.time || 'N/A'})</text>\n\\`\\`\\`\n\n#### 2. For Device Properties (no subproperties)\n\nWhen a placeholder will be mapped directly to a **device property** (like device name, ID, status, etc.), access it directly WITHOUT subproperties:\n\n\\`\\`\\`xml\n<!-- Display device name -->\n<text x=\"100\" y=\"50\">Device: \\${this.c8yScadaValues?.deviceName || 'Unknown'}</text>\n\n<!-- Display device ID -->\n<text x=\"100\" y=\"75\">ID: \\${this.c8yScadaValues?.deviceId || '-'}</text>\n\n<!-- Display custom property -->\n<text x=\"100\" y=\"100\">Location: \\${this.c8yScadaValues?.location || 'Not set'}</text>\n\\`\\`\\`\n\n**Remember**: Each placeholder name (e.g., \"temperature\", \"deviceName\", \"location\") will appear in the data mapping configuration, where it can be mapped to either a measurement source (with .value, .unit, .time) or a device property (direct value).\n\n\\`\\`\\`xml\n<!-- Display temperature value with units -->\n<text x=\"100\" y=\"50\">\\${this.c8yScadaValues?.temperature?.value || '-'} \\${this.c8yScadaValues?.temperature?.unit || ''}</text>\n\n<!-- Display pressure value with units -->\n<text x=\"100\" y=\"100\">Pressure: \\${this.c8yScadaValues?.pressure?.value || '-'} \\${this.c8yScadaValues?.pressure?.unit || 'kPa'}</text>\n\n<!-- Display measurement with timestamp -->\n<text x=\"100\" y=\"150\">Level: \\${this.c8yScadaValues?.level?.value || '-'}% (Updated: \\${this.c8yScadaValues?.level?.time || 'N/A'})</text>\n\\`\\`\\`\n\n### Conditional Styling\nApply CSS classes dynamically based on data values:\n\n\\`\\`\\`xml\n<style>\n .temp-normal { fill: var(--c8y-palette-status-success); }\n .temp-warning { fill: var(--c8y-palette-status-warning); }\n .temp-critical { fill: var(--c8y-palette-status-danger); }\n</style>\n\n<text x=\"100\" y=\"50\" \n class=\"\\${this.c8yScadaValues?.temperature?.value > 80 ? 'temp-critical' : \n this.c8yScadaValues?.temperature?.value > 60 ? 'temp-warning' : 'temp-normal'}\">\n \\${this.c8yScadaValues?.temperature?.value}\\${this.c8yScadaValues?.temperature?.unit || '°C'}\n</text>\n\\`\\`\\`\n\n### Dynamic Attributes\nChange SVG attributes based on data:\n\n\\`\\`\\`xml\n<!-- Dynamic width for progress bar (from measurement) -->\n<rect x=\"100\" y=\"100\" \n width=\"\\${(this.c8yScadaValues?.progress?.value || 0) * 3}\" \n height=\"30\" \n fill=\"var(--c8y-brand-primary)\" />\n<text x=\"100\" y=\"145\">\\${this.c8yScadaValues?.progress?.value || 0}\\${this.c8yScadaValues?.progress?.unit || '%'}</text>\n\n<!-- Dynamic rotation for valve (from measurement) -->\n<g transform=\"rotate(\\${this.c8yScadaValues?.valveAngle?.value || 0} 200 200)\">\n <rect x=\"190\" y=\"150\" width=\"20\" height=\"100\" fill=\"#888\" />\n</g>\n\n<!-- Dynamic fill color based on status (from device property - no .value needed) -->\n<circle cx=\"200\" cy=\"200\" r=\"50\" \n fill=\"\\${this.c8yScadaValues?.status === 'active' ? 'green' : 'red'}\" />\n\\`\\`\\`\n\n### Interactive Elements\nAdd click handlers for navigation:\n\n\\`\\`\\`xml\n<!-- Navigate to device details -->\n<g class=\"button\" @click=\\${() => this.c8yScadaFunctions?.goToDeviceDetails(this.c8yScadaValues?.deviceId)}>\n <rect x=\"50\" y=\"50\" width=\"150\" height=\"40\" fill=\"var(--c8y-brand-primary)\" rx=\"4\" />\n <text x=\"125\" y=\"75\" text-anchor=\"middle\" fill=\"white\">View Device</text>\n</g>\n\n<!-- Navigate to group details -->\n<g class=\"button\" @click=\\${() => this.c8yScadaFunctions?.goToGroupDetails(this.c8yScadaValues?.groupId)}>\n <rect x=\"50\" y=\"100\" width=\"150\" height=\"40\" fill=\"var(--c8y-brand-primary)\" rx=\"4\" />\n <text x=\"125\" y=\"125\" text-anchor=\"middle\" fill=\"white\">View Group</text>\n</g>\n\\`\\`\\`\n\n### Alarm Status Indicators\nDisplay alarm status with appropriate colors:\n\n\\`\\`\\`xml\n<style>\n .alarm-none { fill: var(--c8y-palette-status-success); }\n .alarm-warning { fill: var(--c8y-palette-status-info); }\n .alarm-minor { fill: var(--c8y-palette-status-warning-high); }\n .alarm-major { fill: var(--c8y-palette-status-warning); }\n .alarm-critical { fill: var(--c8y-palette-status-danger); }\n</style>\n\n<!-- Alarm status circle -->\n<circle cx=\"100\" cy=\"100\" r=\"15\" \n class=\"alarm-\\${this.c8yScadaFunctions?.getActiveAlarmsStatusClass(this.c8yScadaValues?.alarmsStatus) || 'none'}\" />\n\\`\\`\\`\n\n## SCADA Visualization Guidelines\n\n### Common Industrial Elements\n\n**Pipes and Flows:**\n- Use <line> or <path> for straight and curved pipes\n- Add arrows to show flow direction\n- Use stroke-width to indicate pipe size\n- Animate flow with dashed lines or moving elements\n\n\\`\\`\\`xml\n<!-- Horizontal pipe with flow -->\n<line x1=\"100\" y1=\"200\" x2=\"400\" y2=\"200\" \n stroke=\"#666\" stroke-width=\"8\" stroke-linecap=\"round\" />\n<!-- Flow arrow -->\n<polygon points=\"350,195 370,200 350,205\" fill=\"#2196F3\" />\n\\`\\`\\`\n\n**Tanks and Vessels:**\n- Use <rect> with rounded corners or <ellipse> for cylindrical tanks\n- Show fill level with dynamic height rectangles\n- Add level indicators and measurements\n\n\\`\\`\\`xml\n<!-- Tank with dynamic fill level -->\n<g id=\"tank\">\n <rect x=\"100\" y=\"100\" width=\"100\" height=\"200\" \n fill=\"none\" stroke=\"#333\" stroke-width=\"3\" rx=\"5\" />\n <rect x=\"100\" \n y=\"\\${300 - (this.c8yScadaValues?.tankLevel?.value || 0) * 2}\" \n width=\"100\" \n height=\"\\${(this.c8yScadaValues?.tankLevel?.value || 0) * 2}\" \n fill=\"#2196F3\" opacity=\"0.7\" />\n <text x=\"150\" y=\"320\" text-anchor=\"middle\">\n \\${this.c8yScadaValues?.tankLevel?.value || 0}\\${this.c8yScadaValues?.tankLevel?.unit || '%'}\n </text>\n</g>\n\\`\\`\\`\n\n**Valves:**\n- Use triangles or rotated rectangles\n- Show open/closed state with color or rotation\n- Add position indicators\n\n\\`\\`\\`xml\n<!-- Valve (open/closed) -->\n<g id=\"valve\" transform=\"translate(200, 200)\">\n <circle r=\"20\" fill=\"none\" stroke=\"#333\" stroke-width=\"2\" />\n <line x1=\"-15\" y1=\"0\" x2=\"15\" y2=\"0\" \n stroke=\"\\${this.c8yScadaValues?.valveOpen?.value ? '#4CAF50' : '#F44336'}\" \n stroke-width=\"3\" \n transform=\"rotate(\\${this.c8yScadaValues?.valveOpen?.value ? 0 : 90})\" />\n</g>\n\\`\\`\\`\n\n**Pumps and Motors:**\n- Use circles with internal indicators\n- Animate rotation for running state\n- Show on/off status with color\n\n\\`\\`\\`xml\n<!-- Pump -->\n<g id=\"pump\">\n <circle cx=\"200\" cy=\"200\" r=\"30\" \n fill=\"\\${this.c8yScadaValues?.pumpRunning?.value ? '#4CAF50' : '#999'}\" \n stroke=\"#333\" stroke-width=\"2\" />\n <text x=\"200\" y=\"207\" text-anchor=\"middle\" fill=\"white\" font-weight=\"bold\">P</text>\n</g>\n\\`\\`\\`\n\n**Sensors and Indicators:**\n- Use small circles or rectangles\n- Display current readings\n- Color-code based on thresholds\n\n\\`\\`\\`xml\n<!-- Temperature sensor -->\n<g id=\"temp-sensor\">\n <rect x=\"100\" y=\"100\" width=\"80\" height=\"40\" \n fill=\"var(--c8y-root-component-background-default)\" \n stroke=\"#333\" rx=\"4\" />\n <text x=\"140\" y=\"125\" text-anchor=\"middle\" \n class=\"\\${this.c8yScadaValues?.temperature?.value > 80 ? 'temp-critical' : 'temp-normal'}\">\n \\${this.c8yScadaValues?.temperature?.value || '-'}\\${this.c8yScadaValues?.temperature?.unit || '°C'}\n </text>\n</g>\n\\`\\`\\`\n\n### Color Conventions\n\n**Operational States:**\n- Green (#4CAF50 or var(--c8y-palette-status-success)): Running/OK/Open\n- Red (#F44336 or var(--c8y-palette-status-danger)): Stopped/Error/Closed\n- Orange (#FF9800 or var(--c8y-palette-status-warning)): Warning/Standby\n- Gray (#999): Inactive/Disabled\n- Blue (#2196F3 or var(--c8y-brand-primary)): Water/Liquid/Flow\n\n**Use Cumulocity design tokens:**\n- var(--c8y-brand-primary): Brand color\n- var(--c8y-palette-status-success): Success green\n- var(--c8y-palette-status-warning): Warning orange\n- var(--c8y-palette-status-danger): Error/critical red\n- var(--c8y-root-component-background-default): Background\n- var(--c8y-root-component-color-default): Text color\n\n### Layout Best Practices\n\n1. **Left-to-right flow**: Process flows typically go from left to right\n2. **Hierarchical grouping**: Group related components visually\n3. **Consistent spacing**: Maintain uniform spacing between elements\n4. **Clear labels**: Label all major components and measurement points\n5. **Legend/Key**: Include a legend if using special symbols or colors\n6. **Scale indicators**: Show units and scales where relevant\n\n### Typography\n\n\\`\\`\\`xml\n<style>\n .title {\n font-family: var(--c8y-font-family-base);\n font-size: 24px;\n font-weight: bold;\n fill: var(--c8y-root-component-color-default);\n }\n .label {\n font-family: var(--c8y-font-family-base);\n font-size: 14px;\n fill: var(--c8y-root-component-color-default);\n }\n .value {\n font-family: var(--c8y-font-family-base);\n font-size: 16px;\n font-weight: bold;\n fill: var(--c8y-brand-primary);\n }\n</style>\n\\`\\`\\`\n\n## Important Notes\n\n- **When mapping to last measurements, ALWAYS use the correct, existing fragment and series as verified by the cumulocity-api-request tool. Never guess or invent measurement names.**\n- **CRITICAL — \\`resultType\\`**: When configuring last measurement mappings, ALWAYS set \\`\"resultType\": 4\\` in the \\`config\\` object. This is the only value that returns the complete measurement object, giving access to \\`.value\\` and \\`.unit\\` sub-properties.\n- **CRITICAL — numeric formatting**: \\`.value\\` may be a number or a numeric string. **Never call \\`.toFixed()\\` by default.** Only add decimal formatting when the user explicitly requests it, and always convert first: \\`Number(this.c8yScadaValues?.pressure?.value).toFixed(2)\\`.\n- **CRITICAL — changes**: When the user requests any change to the SVG or mappings, always re-output the complete \\`<${SCADA_OUTPUT_TAG_NAME}>\\` block with the fix included — never output only the changed portion or a diff.\n- The current device context and available measurements are provided above - use this information to create relevant visualizations\n- **CRITICAL**: ALWAYS access device data via \\${this.c8yScadaValues?.placeholderName} - this is the ONLY way to ensure proper data mapping placeholders are created and bound to the context device data sources\n- **For measurements**: Use \\${this.c8yScadaValues?.placeholderName?.value} to access the value, and optionally .unit and .time for additional measurement data\n- **For device properties**: Use \\${this.c8yScadaValues?.placeholderName} directly WITHOUT subproperties (no .value, .unit, or .time)\n- Each unique placeholder name in c8yScadaValues creates a placeholder in the data mapping list that can be configured to bind to specific device measurements or properties\n- Use semantic grouping with <g> tags and meaningful IDs\n- Make visualizations responsive by using viewBox properly\n- Provide fallback values (use || operator) for all dynamic data to handle missing/undefined values\n- Keep the design clean and professional - avoid clutter\n- Test conditional logic to ensure proper rendering in all states\n- Consider accessibility - use proper contrast and text sizing`;\n\nexport default {\n name: 'c8y-scada-svg',\n agent: {\n system: `You are an expert at creating SVG visualizations for SCADA (Supervisory Control and Data Acquisition) widgets to be used in dashboards in the Cumulocity IoT Platform. Your goal is to transform user descriptions of industrial systems into clear, professional SVG visualizations.\n\n## Workflow\n\n1. **Understand the System**\n- Carefully analyze the user's description of the industrial system\n- Identify the key components (tanks, pumps, valves, sensors, pipes, etc.)\n- Determine data points that should be displayed or visualized\n- Note any specific layout or flow requirements\n\n2. **Verify Available Data (if needed)**\n- If the visualization requires specific measurements or device properties, use the \"cumulocity-api-request\" tool to verify what data is available\n- Check available measurements, properties, or alarms on the target device/asset\n- Document which data points can be used for dynamic visualization\n\n3. **Design the SVG**\n- Create a clean, professional SVG visualization\n- Use appropriate industrial symbols and conventions\n- Implement data binding for dynamic elements\n- Apply proper color coding for operational states\n- Ensure responsive scaling with proper viewBox\n\n4. **Output the Code**\n- Wrap BOTH outputs together in a single <${SCADA_OUTPUT_TAG_NAME}> block: SVG code in <${SVG_EXTRACT_TAG_NAME}> tags followed by mapping in <${MAPPING_EXTRACT_TAG_NAME}> tags, both inside the wrapper\n- CRITICAL: Include ONLY the SVG code inside the SVG tags and ONLY the JSON mapping inside the mapping tags - no explanatory text, no markdown formatting, no comments outside the inner tags\n- Ensure every placeholder used in the SVG (via \\${this.c8yScadaValues?.placeholderName}) has a corresponding entry in the mapping object\n- **If the user requests any change to the SVG or mappings, always re-output the complete \\`<${SCADA_OUTPUT_TAG_NAME}>\\` block with the fix included — never output only the changed portion or a diff**\n- Follow the guidelines in: ${SVG_SCADA_INSTRUCTIONS}\n\n5. **Validate Quality**\n- Verify the visualization represents the described system accurately\n- Ensure all dynamic data bindings use proper fallback values\n- Check that colors and styling follow Cumulocity design standards\n- If the user's description is unclear or lacks critical details, ask for clarification\n\n## Key Principles\n- Professional industrial design - clean, clear, uncluttered\n- Semantic SVG structure with organized groups\n- Proper data binding syntax for dynamic content\n- Responsive and theme-aware using Cumulocity CSS variables\n- No emojis or Unicode symbols - use SVG shapes and text only\n`,\n maxOutputTokens: 20000\n },\n type: 'text',\n mcp: [\n {\n serverName: 'cumulocity-default',\n tools: ['cumulocity-api-request']\n }\n ]\n} as AgentDefinition;\n","import type { ClientAgentDefinition } from '@c8y/ngx-components/ai';\nimport SCADA_SVG_AGENT from './scada-svg.agent.c8y';\nimport { gettext } from '@c8y/ngx-components/gettext';\n\ndeclare const __MODE__: 'development' | 'production' | undefined;\n\n// Treat as \"production\" when run from Jest\nconst mode = (typeof __MODE__ !== 'undefined' ? __MODE__ : 'production') as\n | 'development'\n | 'production';\n\nexport const SCADA_SVG_AGENT_DEFINITION: ClientAgentDefinition = {\n snapshot: mode === 'development',\n label: gettext('SCADA SVG agent'),\n definition: SCADA_SVG_AGENT\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAEO,MAAM,qBAAqB,GAAG;AAC9B,MAAM,oBAAoB,GAAG;AAC7B,MAAM,wBAAwB,GAAG;AAExC,MAAM,sBAAsB,GAAG,CAAA;;;;gEAIiC,qBAAqB,CAAA;mDAClC,oBAAoB,CAAA;qDAClB,wBAAwB,CAAA;+CAC9B,qBAAqB,CAAA;;;;;;;GAOjE,qBAAqB,CAAA;KACnB,oBAAoB,CAAA;;;;;;;;;;;;;;;;;;;;MAoBnB,oBAAoB,CAAA;KACrB,wBAAwB,CAAA;;MAEvB,wBAAwB,CAAA;IAC1B,qBAAqB,CAAA;;;;;;;;;;;;AAYX,YAAA,EAAA,qBAAqB,qLAAqL,wBAAwB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+V7O,qBAAqB,CAAA;KACnB,oBAAoB,CAAA;;MAEnB,oBAAoB,CAAA;KACrB,wBAAwB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAwHvB,wBAAwB,CAAA;IAC1B,qBAAqB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uHAuR8F,qBAAqB,CAAA;;;;;;;;;;;+DAW7E;AAE/D,sBAAe;AACb,IAAA,IAAI,EAAE,eAAe;AACrB,IAAA,KAAK,EAAE;AACL,QAAA,MAAM,EAAE,CAAA;;;;;;;;;;;;;;;;;;;;;;;4CAuBgC,qBAAqB,CAAA,sBAAA,EAAyB,oBAAoB,CAAA,+BAAA,EAAkC,wBAAwB,CAAA;;;+FAGzE,qBAAqB,CAAA;8BACtF,sBAAsB;;;;;;;;;;;;;;AAcnD,CAAA;AACG,QAAA,eAAe,EAAE;AAClB,KAAA;AACD,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,GAAG,EAAE;AACH,QAAA;AACE,YAAA,UAAU,EAAE,oBAAoB;YAChC,KAAK,EAAE,CAAC,wBAAwB;AACjC;AACF;CACiB;;ACz2BpB;AACA,MAAM,IAAI,IAAI,OAAO,QAAQ,KAAK,WAAW,GAAG,QAAQ,GAAG,YAAY,CAEvD;AAET,MAAM,0BAA0B,GAA0B;IAC/D,QAAQ,EAAE,IAAI,KAAK,aAAa;AAChC,IAAA,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC;AACjC,IAAA,UAAU,EAAE;;;ACdd;;AAEG;;;;"}
@@ -520,6 +520,7 @@ class AiChatComponent {
520
520
  * The current text in the chat input field. Supports two-way binding.
521
521
  */
522
522
  this.prompt = '';
523
+ this.cumulativeUsage = null;
523
524
  /**
524
525
  * Emitted when the user sends a message.
525
526
  * Provides an AIMessage object with role, content, and timestamp.
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-ai-ai-chat.mjs","sources":["../../ai/ai-chat/ai-chat-tool-call.component.ts","../../ai/ai-chat/ai-chat-tool-call.component.html","../../ai/ai-chat/json-to-markdown.pipe.ts","../../ai/ai-chat/ai-chat-assistant-part.component.ts","../../ai/ai-chat/ai-chat-assistant-part.component.html","../../ai/ai-chat/ai-chat-assistant-message.component.ts","../../ai/ai-chat/ai-chat-assistant-message.component.html","../../ai/ai-chat/ai-chat-message-action.component.ts","../../ai/ai-chat/ai-chat-message-action.component.html","../../ai/ai-chat/ai-chat-message.component.ts","../../ai/ai-chat/ai-chat-message.component.html","../../ai/ai-chat/ai-chat-suggestion.component.ts","../../ai/ai-chat/ai-chat-suggestion.component.html","../../ai/ai-chat/ai-chat.component.ts","../../ai/ai-chat/ai-chat.component.html","../../ai/ai-chat/c8y-ngx-components-ai-ai-chat.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, input, signal, Type } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { ToolCallConfig, ToolCallPart } from '@c8y/ngx-components/ai';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { JsonPipe, NgComponentOutlet } from '@angular/common';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\n\n@Component({\n selector: 'c8y-ai-chat-tool-call',\n templateUrl: './ai-chat-tool-call.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgComponentOutlet,\n JsonPipe,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule\n ]\n})\nexport class AiChatToolCallComponent {\n /**\n * The tool call part to render. This includes all information about the tool call, including the name of the tool,\n * the input provided and (once available) the output from the tool.\n */\n readonly tool = input.required<ToolCallPart>();\n\n /**\n * Whether the tool call is still in progress.\n */\n readonly isExecuting = input.required<boolean>();\n\n /**\n * A custom component to render the details of the tool call. If not provided, the default details section will be shown.\n */\n readonly toolDetailsComponent = input<Type<unknown> | undefined>(undefined);\n\n /**\n * Shows the default details section for a tool call.\n */\n readonly showDefaultToolDetails = input<boolean>(false);\n\n /**\n * The label to show while the tool is executing. If not provided, a default label will be generated based on the tool name.\n */\n readonly executingLabel = input<string | undefined>(undefined);\n /**\n * The label to show once the tool has completed. If not provided, a default label will be generated based on the tool name and whether the tool call was successful or resulted in an error.\n */\n readonly completedLabel = input<string | undefined>(undefined);\n\n /**\n * A function that can generate a label for this tool call based on the tool call data.\n */\n readonly labelProvider = input<ToolCallConfig['labelProvider']>();\n\n protected readonly expanded = signal(false);\n protected readonly everExpanded = signal(false);\n\n private readonly translateService = inject(TranslateService);\n\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n if (this.labelProvider()) {\n try {\n const dynamicLabel = this.labelProvider()(tool, this.translateService);\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, report it then fall back to default logic\n console.error(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && this.executingLabel()) {\n return this.executingLabel();\n }\n if (!isExecuting && this.completedLabel()) {\n return this.completedLabel();\n }\n\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n { toolName: tool.toolName }\n );\n }\n\n protected toggleExpanded(): void {\n const willExpand = !this.expanded();\n this.expanded.set(willExpand);\n if (willExpand) {\n this.everExpanded.set(true);\n }\n }\n}\n","@let _tool = tool();\n@let showDetails = showDefaultToolDetails() || toolDetailsComponent() || _tool.error;\n@let isToolExpanded = expanded();\n\n<fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n [attr.aria-label]=\"'Tool call: ' + _tool.toolName\"\n>\n <button\n class=\"btn-clean ai-tool-call__btn\"\n [attr.aria-expanded]=\"showDetails ? isToolExpanded : null\"\n [attr.aria-controls]=\"showDetails ? 'tool-call-' + _tool.toolCallId : null\"\n type=\"button\"\n [attr.data-cy]=\"'tool-call-' + _tool.toolName\"\n [disabled]=\"!showDetails || null\"\n (click)=\"toggleExpanded()\"\n >\n @if (isExecuting()) {\n <i\n class=\"icon-spin icon-14 text-primary m-r-4\"\n c8yIcon=\"spinner\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <!-- Treat it as an error if a tool still thinks its executing when the message containing it is not -->\n @if (_tool.error || isExecuting()) {\n <i\n class=\"icon-14 text-danger m-r-4\"\n [c8yIcon]=\"'exclamation-circle'\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <i\n class=\"icon-14 text-success m-r-4\"\n [c8yIcon]=\"'check'\"\n aria-hidden=\"true\"\n ></i>\n }\n }\n <span class=\"small\">{{ getToolLabel(_tool) | translate }}</span>\n\n @if (showDetails) {\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"isToolExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n <!-- If this is an artifact tool, render it - but do so lazily only on first open,\n since these components could be heavyweight (e.g. Monaco)\n -->\n @if (showDetails && (isToolExpanded || everExpanded())) {\n <div\n class=\"collapse tool-details m-t-8 p-8 b-r-4\"\n [attr.aria-label]=\"'Tool details for message latest tool: ' + _tool.toolName\"\n role=\"region\"\n [collapse]=\"!isToolExpanded\"\n [id]=\"'tool-call-' + _tool.toolCallId\"\n [isAnimated]=\"true\"\n data-cy=\"ai-tool-component\"\n >\n @if (toolDetailsComponent()) {\n <ng-container\n [ngComponentOutlet]=\"toolDetailsComponent()\"\n [ngComponentOutletInputs]=\"{ tool: _tool }\"\n ></ng-container>\n } @else {\n @let noneLabel = '(no data)' | translate;\n\n <p class=\"text-label-small\">{{ 'Tool input' | translate }}</p>\n <pre class=\"fit-w small\">{{ _tool.input || noneLabel | json }}</pre>\n\n @if (_tool.type === 'tool-result') {\n <p class=\"text-label-small\">{{ 'Tool output' | translate }}</p>\n @if (\n typeof _tool.output === 'string' || _tool.output === undefined || _tool.output === null\n ) {\n <pre class=\"fit-w small\">{{ _tool.output || noneLabel }}</pre>\n } @else {\n <pre class=\"fit-w small\">{{ _tool.output | json }}</pre>\n }\n }\n }\n </div>\n }\n</fieldset>\n","import { Pipe, PipeTransform } from '@angular/core';\n\n/**\n * Converts a JSON string to a markdown code block.\n */\n@Pipe({\n name: 'jsonToMarkdown',\n standalone: true\n})\nexport class JsonToMarkdownPipe implements PipeTransform {\n transform(value: string | null | undefined): string {\n if (!value) {\n return '```json\\nnull\\n```';\n }\n\n const escapedValue = value.replace(/\\\\/g, '\\\\\\\\').replace(/`/g, '\\\\`');\n return `\\`\\`\\`json\\n${escapedValue}\\n\\`\\`\\``;\n }\n}\n","import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';\nimport { AIMessagePart } from '@c8y/ngx-components/ai';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe\n} from '@c8y/ngx-components';\nimport { AsyncPipe, NgComponentOutlet } from '@angular/common';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AssistantMessageContext } from './ai-chat-assistant-message.component';\nimport { AiChatToolCallComponent } from './ai-chat-tool-call.component';\nimport { JsonToMarkdownPipe } from './json-to-markdown.pipe';\n\n/** This renders a part of an assistant message. Currently only ToolCallPart is supported, but later we can expand this to deal with all part types. */\n@Component({\n selector: 'c8y-ai-chat-assistant-part',\n templateUrl: './ai-chat-assistant-part.component.html',\n standalone: true,\n imports: [\n NgComponentOutlet,\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n MarkdownToHtmlPipe,\n AsyncPipe,\n AiChatToolCallComponent,\n JsonToMarkdownPipe\n ],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AiChatAssistantPartComponent {\n readonly part = input.required<AIMessagePart>();\n\n /** Whether this part is rendered as part of the main answer, or is an intermediate step with more muted rendering. */\n readonly displayAsPartOfMainAnswer = input(true);\n\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /** Tracks whether this is currently expanded (used for reasoning section). */\n protected readonly expanded = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update(v => !v);\n }\n}\n","@let ctx = assistantMessageContext();\n@let _config = ctx.config;\n@let toolCallConfig = _config.toolCallConfig || {};\n@let _part = part();\n\n@if (_part.type === 'text') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></p>\n} @else if (_part.type === 'reasoning') {\n @let reasoningExpanded = expanded();\n\n <fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n data-cy=\"ai-reasoning\"\n >\n <button\n class=\"btn-clean ai-tool-call__btn\"\n aria-label=\"{{ 'Toggle display of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"reasoningExpanded\"\n [attr.aria-controls]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"toggleExpanded()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'ai-sparkles'\"\n ></i>\n @let hideReasoning = 'Hide reasoning' | translate;\n @let showReasoning = 'Show reasoning' | translate;\n <span class=\"small\">{{ reasoningExpanded ? hideReasoning : showReasoning }}</span>\n <i\n class=\"m-l-4 icon-12 text-muted\"\n [c8yIcon]=\"reasoningExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse reasoning-content\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"!reasoningExpanded\"\n [id]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n data-cy=\"ai-reasoning-content\"\n >\n <div\n class=\"m-t-8 p-b-4 text-muted\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></div>\n </div>\n </fieldset>\n} @else if (_part.type === 'object') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.jsonContent | jsonToMarkdown | markdownToHtml | async\"\n data-cy=\"ai-object-content\"\n ></p>\n} @else if (_part.type === 'step-start') {\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"ai-step-start hidden-copy-label\"\n aria-hidden=\"true\"\n data-cy=\"ai-step-start-separator\"\n translate\n >--- (step separator) ---</span\n >\n} @else if (_part.type.startsWith('tool')) {\n @let tool = $any(_part);\n @let toolDisplay = toolCallConfig[tool.toolName];\n\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n translate\n [translateParams]=\"{ toolName: tool.toolName }\"\n ngNonBindable\n >--- Tool call: {{ toolName }} ---</span\n >\n\n @if (toolDisplay?.component) {\n <div data-cy=\"ai-tool-with-custom-component\">\n <ng-container\n [ngComponentOutlet]=\"toolDisplay.component\"\n [ngComponentOutletInputs]=\"{\n tool: tool,\n ctx: ctx\n }\"\n ></ng-container>\n </div>\n } @else if (!toolDisplay?.isHidden) {\n <!-- Don't allow expanding while tool call is in progress - it's unlikely to have anything worth rendering,\n and complicates implementation for the client to have to check for the isExecuting case.\n -->\n <c8y-ai-chat-tool-call\n [tool]=\"tool\"\n [isExecuting]=\"tool.type !== 'tool-result' && ctx.isMessageLoading\"\n [toolDetailsComponent]=\"_config.toolDetailsComponent?.(tool)\"\n [showDefaultToolDetails]=\"_config.showDefaultToolDetails === 'all'\"\n [executingLabel]=\"toolDisplay?.executingLabel\"\n [completedLabel]=\"toolDisplay?.completedLabel\"\n [labelProvider]=\"toolDisplay?.labelProvider\"\n ></c8y-ai-chat-tool-call>\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n signal\n} from '@angular/core';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport {\n AIAssistantMessage,\n AIMessagePart,\n AssistantMessageDisplayConfig,\n ToolCallPart\n} from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AiChatAssistantPartComponent } from './ai-chat-assistant-part.component';\n\n/**\n * Context object which includes the inputs needed for assistant message rendering.\n * If creating a custom component for assistant message rendering, you will receive this as an input.\n */\nexport interface AssistantMessageContext {\n message: AIAssistantMessage;\n config: AssistantMessageDisplayConfig;\n\n /** The message response is currently streaming in (not yet complete). */\n isMessageLoading: boolean;\n\n /** A number identifying this message in the chat history numbered from the latest - 0 is the latest, -1 is the previous, etc. */\n messageDisplayIndex: number;\n}\n\n/**\n * This is the default component used to render the contents of a message from the AI assistant, including\n * the main answer text, text from earlier steps, reasoning text and tool calls.\n */\n@Component({\n selector: 'c8y-ai-chat-assistant-message',\n templateUrl: './ai-chat-assistant-message.component.html',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule,\n AiChatAssistantPartComponent\n ]\n})\nexport class AiChatAssistantMessageComponent {\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /**\n * By default this component will render a \"Working...\" indicator while streaming results. This input can turn that off if required.\n */\n readonly showWorkingIndicator = input(true);\n\n /**\n * Whether the thinking section is expanded. Initialized to false unless the message is still loading.\n * Call setThinkingExpanded() via viewChild to control this programmatically. Does nothing if appearance does not distinguish thinking steps.\n */\n protected readonly thinkingExpanded = signal(false);\n\n /**\n * Tracks which reasoning sections are expanded, keyed by step index.\n */\n protected readonly expandedReasoningStepIndices = signal(new Set<number>());\n\n private readonly translateService = inject(TranslateService);\n\n protected readonly thinkingAndMainAnswerParts = computed(() =>\n this.splitContentIntoThinkingAndMainAnswer(this.assistantMessageContext())\n );\n\n constructor() {\n // Expand when we initially set the message loading flag, without overwriting the value\n // any other time\n effect(() => {\n if (this.assistantMessageContext().isMessageLoading) {\n this.thinkingExpanded.set(true);\n }\n });\n }\n\n /**\n * This is public and exists for agent-chat to collapse older messages.\n * @param expanded Whether the thinking section should be expanded or not.\n */\n setThinkingExpanded(expanded: boolean): void {\n this.thinkingExpanded.set(expanded);\n }\n\n /**\n * Get a translated/translateable label for the specified tool.\n * @param tool The tool call part to get the label for.\n * @return The label to show for this tool call.\n */\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n const config = this.assistantMessageContext().config;\n const toolCallConfig = config?.toolCallConfig?.[tool.toolName];\n if (toolCallConfig?.labelProvider) {\n try {\n const dynamicLabel = toolCallConfig.labelProvider(tool, this.translateService);\n // Run it through translate in case it contains gettext values\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, so report this - then fallback to default logic\n console.warn(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && toolCallConfig?.executingLabel) {\n return toolCallConfig.executingLabel;\n }\n if (!isExecuting && toolCallConfig?.completedLabel) {\n return toolCallConfig.completedLabel;\n }\n\n // If we have no specific label configured, use the default\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n // Have to use the tool id since that's all we have\n { toolName: tool.toolName }\n );\n }\n\n protected toggleReasoningExpanded(stepIndex: number): void {\n this.expandedReasoningStepIndices.update(s => {\n const next = new Set(s);\n s.has(stepIndex) ? next.delete(stepIndex) : next.add(stepIndex);\n return next;\n });\n }\n\n /**\n * Note: ctx is passed as a parameter rather than reading the signal in the template to ensure\n * it's totally aligned with what the template is rendering.\n * @param ctx The context for the assistant message.\n * @return The label to display for the reasoning section.\n */\n protected getThinkingLabel(ctx: AssistantMessageContext): string {\n return ctx.isMessageLoading\n ? gettext('Reasoning')\n : this.thinkingExpanded()\n ? gettext('Hide reasoning')\n : gettext('Show reasoning');\n }\n\n protected getToolName(part: AIMessagePart): string | undefined {\n return part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n ? part.toolName\n : undefined;\n }\n\n protected experimental_nonFinalStepTextDisplay(\n ctx: AssistantMessageContext\n ): AssistantMessageDisplayConfig['experimental_nonFinalStepTextDisplay'] {\n // For now be conservative with the old behaviour, but hope to change this once we've got working really smoothly.\n return ctx.config?.experimental_nonFinalStepTextDisplay || 'main-answer';\n }\n\n /**\n * Splits the assistant message content into two arrays: thinking content and main answer content.\n * This also removes hidden tools.\n *\n * If using the experimental rendering modes, main answer content is text in the final step (if conditions are met) plus any tool calls configured to be shown with the main answer.\n * Thinking content is everything else (reasoning, earlier text, tool calls not shown with main answer).\n *\n * @param ctx The context for the assistant message.\n * @return An object with thinkingParts and mainAnswerParts arrays.\n */\n protected splitContentIntoThinkingAndMainAnswer(ctx: AssistantMessageContext): {\n thinkingParts: AIMessagePart[];\n mainAnswerParts: AIMessagePart[];\n } {\n // Remove hidden tools\n let content = ctx.message?.content || [];\n if (Object.values(ctx.config?.toolCallConfig || {}).some(c => c?.isHidden)) {\n content = (ctx.message?.content || []).filter(\n part => !ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isHidden\n );\n }\n\n // Putting this check here keeps things safe by ensuring there is no chance of any rendering differences\n // during streaming unless in one of the experimental modes. This means the rest of this method only applies\n // to the experimental rendering.\n if (this.experimental_nonFinalStepTextDisplay(ctx) === 'main-answer') {\n return { thinkingParts: [], mainAnswerParts: content };\n }\n\n const { finalStepStart, finalStepHasText } = this.findFinalStepWithText(content);\n\n const hasToolCalls = content.some(\n part =>\n part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n );\n // Since we don't bother with a step-start at index 0 for the first step, add one\n const stepCount =\n content.filter((part, index) => index > 0 && part.type === 'step-start').length + 1;\n\n // The final step text goes in the main answer area if there are no pending tool calls\n // (since otherwise the tools would show below it), and\n // message has finished loading, or we're expecting more steps than this.\n // Note that we check all steps for toolCalls not just the current one, for the sake of \"fake\" tool calls created by preprocessAgentMessage\n // where additional step boundaries may be added to simplify parsing.\n const shouldShowLastTextAsMainAnswer =\n finalStepHasText &&\n finalStepStart !== -1 &&\n !hasToolCalls &&\n (!ctx.isMessageLoading || stepCount >= (ctx.config?.experimental_expectedStepCount || 2));\n\n if (!shouldShowLastTextAsMainAnswer) {\n return { thinkingParts: content, mainAnswerParts: [] };\n }\n\n const thinkingParts: AIMessagePart[] = [];\n const mainAnswerParts: AIMessagePart[] = [];\n\n // Split the content: final step and promoted tool calls go to main answer, everything else to thinking\n content.forEach((part, index) => {\n const isPromotedToolCall =\n ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isShownWithMainAnswer;\n\n // This ensures promoted tool calls never go to the collapseable thinking area\n if (index >= finalStepStart || isPromotedToolCall) {\n mainAnswerParts.push(part);\n } else {\n thinkingParts.push(part);\n }\n });\n\n return { thinkingParts, mainAnswerParts };\n }\n\n /**\n * Scans backwards through the content parts to find the step-start index for the last step\n * that contains at least one text part. Skips trailing empty steps (step-start with no text after).\n *\n * @returns `finalStepStart` — index of the step-start part, or 0 if content belongs to the implicit first step.\n * `finalStepHasText` — whether a step with text was found at all.\n */\n private findFinalStepWithText(content: AIMessagePart[]): {\n finalStepStart: number;\n finalStepHasText: boolean;\n } {\n let finalStepStart = 0;\n let finalStepHasText = false;\n for (let i = content.length - 1; i >= 0; i--) {\n if (content[i].type === 'text') {\n finalStepHasText = true;\n }\n if (content[i].type === 'step-start') {\n if (finalStepHasText) {\n finalStepStart = i;\n break;\n } else if (i === content.length - 1) {\n // Trailing empty step-start — keep looking\n continue;\n } else {\n // step-start found but no text in that step\n finalStepStart = -1;\n break;\n }\n }\n }\n return { finalStepStart, finalStepHasText };\n }\n}\n","@let ctx = assistantMessageContext();\n@let parts = ctx.message.content;\n@let _config = ctx.config;\n\n<!-- \nWe show the assistant message in (up to) 3 slots:\n- collapsible thinking block (for intermediate step text, standard tool calls, etc)\n- special \"artifact\" tools that update user artifacts and need prominent display (e.g. for code edits made by the AI)\n- the main answer (typically from the final step)\n\nThis is a standard approach for AI chats - step text and tools from an LLM are treated as a work log, i.e. useful to \ndisplay progress while streaming the response, but only the text from the last step after all tool calls gives the main answer of the AI to the user. \n\nDepending on configuration, we have an experimental option (if we need it) to style the thinking block the same as the main answer. \n\nOnce the message finishes loading we know the final step IS the main content, but if it's still steaming \nwe don't know for sure which step has the final/main answer until the LLM has actually finished so have to take a heuistic guess \n(and minimize jumping in the UI). \n\nFor applications where we expect tool calls in most responses, assume the 2nd step is probably the final text; \nfor applications where tool calls are less ubiquitous, assume the first step is main answer until proved otherwise. \nThis minimizes jumping (except when there are >2 steps, which is rare).\n\n-->\n\n@let contentSplit = thinkingAndMainAnswerParts();\n@let nonFinalStepTextDisplay = experimental_nonFinalStepTextDisplay(ctx);\n\n<!-- Thinking steps section - holds reasoning, text from non-final steps, and standard/non-artifact tool calls -->\n\n@if (contentSplit.thinkingParts.length > 0) {\n <div\n class=\"m-b-8 text-muted\"\n [class.thinking-block]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block'\"\n [class.small]=\"nonFinalStepTextDisplay === 'muted-main-answer'\"\n [class.thinking-steps-appearance]=\"nonFinalStepTextDisplay\"\n data-cy=\"thinking-steps\"\n >\n @if (nonFinalStepTextDisplay === 'collapsible-thinking-block') {\n <button\n class=\"btn btn-clean btn-xs text-muted p-l-0\"\n aria-label=\"{{ 'Toggle collapse of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"thinkingExpanded()\"\n [attr.aria-controls]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"thinkingExpanded.set(!thinkingExpanded())\"\n >\n <span class=\"small\">{{ getThinkingLabel(ctx) }}</span>\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"thinkingExpanded() ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n }\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block' && !thinkingExpanded()\"\n [id]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n >\n <div\n [class]=\"\n nonFinalStepTextDisplay === 'collapsible-thinking-block'\n ? 'thinking-content bg-level-1 m-t-8 p-8 b-r-4 border-left-accent small m-b-0 text-muted'\n : ''\n \"\n >\n @for (part of contentSplit.thinkingParts; track $index) {\n @if (part.type !== 'step-start' || $index > 0) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"nonFinalStepTextDisplay !== 'muted-main-answer'\"\n ></c8y-ai-chat-assistant-part>\n }\n }\n </div>\n </div>\n </div>\n}\n\n<!-- Main answer area contains the text from the final step, and \n any promoted tool calls which are too important to be hidden in the collapeable thinking area -->\n<div\n class=\"message-content\"\n data-cy=\"ai-main-answer-content\"\n>\n @for (part of contentSplit.mainAnswerParts; track $index) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"true\"\n ></c8y-ai-chat-assistant-part>\n }\n</div>\n\n@if (ctx.isMessageLoading && showWorkingIndicator()) {\n <!-- Once the message starts to stream, show a small/low-key thinking indicator -->\n <div\n class=\"text-muted text-12 fade-in-out d-flex j-c-end\"\n aria-live=\"polite\"\n role=\"status\"\n data-cy=\"working-indicator\"\n >\n {{ 'Working…' | translate }}\n </div>\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An action button that can be added to chat messages.\n * Typically used for actions like copying, regenerating, or providing feedback on messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message-action',\n templateUrl: './ai-chat-message-action.component.html',\n standalone: true,\n imports: [TooltipModule, C8yTranslatePipe, IconDirective]\n})\nexport class AiChatMessageActionComponent {\n /**\n * Set to true to use content projection for custom action button content.\n */\n @Input()\n custom = false;\n\n /**\n * Disables the action button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * Tooltip text displayed when hovering over the action button.\n */\n @Input()\n tooltip = '';\n\n /**\n * Icon to display in the action button.\n */\n @Input()\n icon: SupportedIconsSuggestions = 'cog';\n\n /**\n * Emitted when the action button is clicked.\n */\n @Output()\n actionClicked = new EventEmitter<void>();\n}\n","@if (!custom) {\n <button\n class=\"btn btn-dot text-muted\"\n [attr.aria-label]=\"tooltip | translate\"\n [tooltip]=\"tooltip | translate\"\n [adaptivePosition]=\"true\"\n [delay]=\"500\"\n (click)=\"actionClicked.emit()\"\n [disabled]=\"disabled\"\n >\n <i\n class=\"text-12\"\n [c8yIcon]=\"icon\"\n ></i>\n </button>\n} @else {\n <ng-content></ng-content>\n}\n","import { Component, computed, input, inject, ChangeDetectionStrategy } from '@angular/core';\n\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { C8yTranslatePipe, DatePipe } from '@c8y/ngx-components';\nimport { NgClass } from '@angular/common';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { TranslateService } from '@ngx-translate/core';\n\n/**\n * A container for content and actions that should be rendered for each chat message.\n *\n * Project content into this component to display the message, for example add an `<ai-chat-assistant-message>`\n * for assistant messages, and a simple `markdownToHtml | async` rendering of the content for user messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message',\n templateUrl: './ai-chat-message.component.html',\n styleUrl: './ai-chat-message.component.scss',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgClass, TooltipModule, C8yTranslatePipe, DatePipe]\n})\nexport class AiChatMessageComponent {\n readonly role = input<AIMessage['role']>();\n readonly message = input<AIMessage>();\n\n private readonly translateService = inject(TranslateService);\n\n private readonly roleResolved = computed(() => {\n return this.message()?.role || this.role();\n });\n\n /**\n * Generates an accessible label for the message container.\n * Includes the role (user or assistant) and timestamp if available.\n * @returns The aria-label string for screen readers\n */\n readonly ariaLabel = computed(() => {\n const tpl =\n this.roleResolved() === 'user'\n ? gettext('You said: \"{{ message }}\"')\n : gettext('Assistant said: \"{{ message }}\"');\n const msg = this.message();\n return this.translateService.instant(tpl, { message: msg?.content || gettext('No response.') });\n });\n\n /**\n * Generates an accessible label for the message content.\n * Prefixes the content with contextual information about who sent it.\n * @returns The aria-label string with prefixed role information\n */\n readonly messageContentAriaLabel = computed(() => {\n const msg = this.message();\n const time =\n msg.role != 'system' && msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString() : '';\n let tpl: string;\n if (time) {\n tpl =\n this.roleResolved() === 'user'\n ? gettext('User message at {{ time }}')\n : gettext('Assistant message at {{ time }}');\n } else {\n tpl = this.roleResolved() === 'user' ? gettext('User message') : gettext('Assistant message');\n }\n return this.translateService.instant(tpl, { time });\n });\n}\n","<div\n class=\"d-col p-t-16\"\n [attr.aria-label]=\"ariaLabel()\"\n role=\"article\"\n>\n <div\n class=\"chat-message text-break-word\"\n [ngClass]=\"{\n 'user-message': message()?.role === 'user' || role() === 'user',\n 'agent-message': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n >\n {{ `====== ${messageContentAriaLabel()} ======` }}</span\n >\n\n <!-- Apply the class and aria-label to both the main content and whatever is projected, so we get the same styling by default -->\n <div\n class=\"message-content\"\n [attr.aria-label]=\"messageContentAriaLabel()\"\n >\n <div style=\"display: contents\">\n <ng-content select=\":not(c8y-ai-chat-message-action)\"></ng-content>\n </div>\n </div>\n @if (message()?.timestamp) {\n <div class=\"message-timestamp\">\n <span [tooltip]=\"message()?.timestamp | c8yDate\">\n {{ message()?.timestamp | c8yDate: 'adaptiveDate' }}\n </span>\n </div>\n }\n </div>\n <div\n class=\"message-action\"\n [attr.aria-label]=\"'Message actions' | translate\"\n role=\"toolbar\"\n [ngClass]=\"{\n 'user-action showOnHover': message()?.role === 'user' || role() === 'user',\n 'agent-action p-l-16': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <ng-content select=\"c8y-ai-chat-message-action\"></ng-content>\n </div>\n</div>\n","import { Component, input, output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\n\n/**\n * A suggestion chip that can be displayed in the chat interface.\n * When clicked, it automatically populates and sends a predefined prompt.\n */\n@Component({\n selector: 'c8y-ai-chat-suggestion',\n templateUrl: './ai-chat-suggestion.component.html',\n host: { class: 'd-contents' },\n standalone: true,\n imports: [IconDirective, C8yTranslatePipe]\n})\nexport class AiChatSuggestionComponent {\n /**\n * The visible label text displayed on the suggestion chip.\n */\n readonly label = input.required<string>();\n\n /**\n * The prompt text that will be sent when the suggestion is clicked.\n */\n readonly prompt = input.required<string>();\n\n /**\n * Icon to display alongside the suggestion label.\n */\n readonly icon = input<SupportedIconsSuggestions>('c8y-bulb');\n\n /**\n * When true, uses AI-styled buttons instead of default styling.\n */\n readonly useAiButtons = input(false);\n\n /**\n * Disables the suggestion chip when true.\n */\n readonly disabled = input(false);\n\n /**\n * Emitted when the suggestion is clicked, providing the prompt as an AIMessage.\n */\n readonly suggestionClicked = output<AIMessage>();\n\n /**\n * Handles suggestion click and emits the prompt as a user message.\n */\n suggest() {\n this.suggestionClicked.emit({\n content: this.prompt(),\n role: 'user',\n timestamp: new Date().toISOString()\n });\n }\n}\n","@if (!useAiButtons()) {\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <i [c8yIcon]=\"icon()\"></i>\n {{ label() | translate }}\n </button>\n} @else {\n <button\n class=\"btn btn-sm btn-ai\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <span>{{ label() | translate }}</span>\n </button>\n}\n","import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n contentChildren,\n effect,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n TemplateRef,\n viewChild\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe,\n NumberPipe,\n TextareaAutoresizeDirective\n} from '@c8y/ngx-components';\nimport { AIMessage, ChatConfig } from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AiChatMessageComponent } from './ai-chat-message.component';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An interactive chat interface component for AI-powered conversations.\n * Displays messages in a conversation format with support for loading states,\n * custom configuration, and markdown formatting.\n */\n@Component({\n selector: 'c8y-ai-chat',\n templateUrl: './ai-chat.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n FormsModule,\n TextareaAutoresizeDirective,\n IconDirective,\n NgClass,\n NgTemplateOutlet,\n MarkdownToHtmlPipe,\n AsyncPipe,\n TooltipModule,\n NumberPipe\n ],\n standalone: true,\n host: { class: 'd-contents' }\n})\nexport class AiChatComponent {\n /**\n * Indicates whether the chat is currently processing a request.\n * When true, displays a cancel button instead of send button and disables the input.\n */\n @Input()\n isLoading = false;\n\n /**\n * Disables the chat input and send button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * The current text in the chat input field. Supports two-way binding.\n */\n @Input()\n prompt = '';\n\n /**\n * Template for rendering custom suggestions below the input field. Can be used to provide predefined prompts or actions\n * from a dynamic source such as the AI. To use this, wrap your suggestion components in an `<ng-template #suggestionsRef>`\n * (where `suggestionsRef` matches the suggestionsTemplate reference);\n */\n @Input()\n suggestionsTemplate?: TemplateRef<any>;\n\n /** Template for customizing the welcome view using `<ng-template>`. */\n @Input() welcomeTemplate?: TemplateRef<any>;\n\n @Input() cumulativeUsage?: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n };\n\n /**\n * Emitted when the user sends a message.\n * Provides an AIMessage object with role, content, and timestamp.\n */\n @Output()\n onMessage = new EventEmitter<AIMessage>();\n\n /**\n * Emitted when the user cancels an ongoing operation during loading state.\n */\n @Output()\n onCancel = new EventEmitter<void>();\n\n /**\n * Child message components displayed in the chat.\n */\n readonly messages = contentChildren(AiChatMessageComponent);\n\n /**\n * Reference to the scroll container for the chat messages.\n */\n private readonly scrollContainer = viewChild<ElementRef<HTMLDivElement>>('chatScrollContainer');\n\n readonly componentId = `chat-${crypto.randomUUID()}`;\n\n private _config: ChatConfig = {\n headline: gettext('Welcome!'),\n welcomeText: '',\n welcomePosition: 'top',\n title: gettext('What can I help you with?'),\n placeholder: gettext('Type your message here...'),\n scrollbarOnlyOnHover: false,\n sendButtonText: gettext('Send'),\n cancelButtonText: gettext('Cancel'),\n disclaimerText: gettext(\n 'AI-generated responses can contain errors. Verify the details before use.'\n ),\n userInterfaceIcons: {\n send: 'arrow-circle-up',\n cancel: 'stop-circle'\n }\n };\n\n constructor() {\n // Auto-scroll to bottom when messages change\n effect(() => {\n this.messages(); // track changes\n const container = this.scrollContainer()?.nativeElement;\n if (!container) return;\n // In column-reverse, scrollTop=0 IS the visual bottom.\n // Only snap back if user is already near the bottom (wasn't scrolled up).\n if (container.scrollTop < 50) {\n container.scrollTop = 0;\n }\n });\n }\n\n /**\n * Configuration object for customizing labels, placeholders, and icons.\n * Accepts partial configuration to override defaults.\n * @param value Partial configuration to merge with defaults.\n * @returns The complete configuration object.\n */\n @Input()\n set config(value: Partial<ChatConfig>) {\n this._config = { ...this._config, ...value };\n }\n get config(): ChatConfig {\n return this._config;\n }\n\n /**\n * Handles message submission when the user sends a message.\n * Emits the onMessage event and clears the input.\n * @param $event The event object from the form submission\n */\n sendMessage($event: Event): void {\n $event.preventDefault();\n if (!this.prompt) return;\n this.onMessage.emit({\n role: 'user',\n content: this.prompt,\n timestamp: new Date().toISOString()\n });\n this.prompt = '';\n }\n\n /**\n * Handles cancellation of ongoing operations during loading state.\n * Emits the onCancel event.\n */\n cancel(): void {\n this.onCancel.emit();\n }\n}\n","<div\n class=\"d-col fit-h fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-balance\">{{ config.title | translate }}</p>\n }\n <div class=\"text-balance chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-8 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{ config.placeholder | translate }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n ></textarea>\n <div class=\"chat-input-group-btn\">\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted m-b-8 text-10 p-l-16\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <span\n class=\"tag tag--info m-l-auto\"\n [tooltip]=\"\n 'Input tokens: {{ input }} \\n Output tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0) |\n c8yNumber : 'floor':'1.0-0' } }}\n </span>\n }\n </div>\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2"],"mappings":";;;;;;;;;;;;;MAqBa,uBAAuB,CAAA;AAbpC,IAAA,WAAA,GAAA;AAcE;;;AAGG;AACM,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,+CAAgB;AAE9C;;AAEG;AACM,QAAA,IAAA,CAAA,WAAW,GAAG,KAAK,CAAC,QAAQ,sDAAW;AAEhD;;AAEG;AACM,QAAA,IAAA,CAAA,oBAAoB,GAAG,KAAK,CAA4B,SAAS,gEAAC;AAE3E;;AAEG;AACM,QAAA,IAAA,CAAA,sBAAsB,GAAG,KAAK,CAAU,KAAK,kEAAC;AAEvD;;AAEG;AACM,QAAA,IAAA,CAAA,cAAc,GAAG,KAAK,CAAqB,SAAS,0DAAC;AAC9D;;AAEG;AACM,QAAA,IAAA,CAAA,cAAc,GAAG,KAAK,CAAqB,SAAS,0DAAC;AAE9D;;AAEG;QACM,IAAA,CAAA,aAAa,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,eAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAmC;AAE9C,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;AACxB,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,KAAK,wDAAC;AAE9B,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAkC7D,IAAA;AAhCC,IAAA,YAAY,CAAC,IAAkB,EAAA;AAC7B,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,KAAK,aAAa;AAC/C,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE;AACxB,YAAA,IAAI;AACF,gBAAA,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC;AACtE,gBAAA,IAAI,YAAY;AAAE,oBAAA,OAAO,YAAY;YACvC;YAAE,OAAO,GAAG,EAAE;;gBAEZ,OAAO,CAAC,KAAK,CAAC,CAAA,gCAAA,EAAmC,IAAI,CAAC,QAAQ,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC;YACzE;QACF;AAEA,QAAA,IAAI,WAAW,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE;AACxC,YAAA,OAAO,IAAI,CAAC,cAAc,EAAE;QAC9B;QACA,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE;AACzC,YAAA,OAAO,IAAI,CAAC,cAAc,EAAE;QAC9B;AAEA,QAAA,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAClC,WAAW,GAAG,OAAO,CAAC,2BAA2B,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,EACtF,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B;IACH;IAEU,cAAc,GAAA;AACtB,QAAA,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE;AACnC,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;QAC7B,IAAI,UAAU,EAAE;AACd,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;QAC7B;IACF;+GAxEW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,sBAAA,EAAA,EAAA,iBAAA,EAAA,wBAAA,EAAA,UAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECrBpC,0+FAwFA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED3EI,iBAAiB,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,mBAAA,EAAA,yBAAA,EAAA,2BAAA,EAAA,sCAAA,EAAA,0BAAA,EAAA,2BAAA,EAAA,kCAAA,CAAA,EAAA,QAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAGjB,aAAa,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,YAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,WAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACd,kBAAkB,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAJlB,QAAQ,wCACR,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAMP,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAbnC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,EAAA,eAAA,EAEhB,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACP,iBAAiB;wBACjB,QAAQ;wBACR,gBAAgB;wBAChB,aAAa;wBACb,cAAc;wBACd;AACD,qBAAA,EAAA,QAAA,EAAA,0+FAAA,EAAA;;;AEjBH;;AAEG;MAKU,kBAAkB,CAAA;AAC7B,IAAA,SAAS,CAAC,KAAgC,EAAA;QACxC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,oBAAoB;QAC7B;AAEA,QAAA,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;QACtE,OAAO,CAAA,YAAA,EAAe,YAAY,CAAA,QAAA,CAAU;IAC9C;+GARW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA,CAAA;6GAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,gBAAA,EAAA,CAAA,CAAA;;4FAAlB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAJ9B,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA;AACJ,oBAAA,IAAI,EAAE,gBAAgB;AACtB,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACMD;MAkBa,4BAA4B,CAAA;AAjBzC,IAAA,WAAA,GAAA;AAkBW,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,+CAAiB;;AAGtC,QAAA,IAAA,CAAA,yBAAyB,GAAG,KAAK,CAAC,IAAI,qEAAC;AAEhD;;;AAGG;AACM,QAAA,IAAA,CAAA,uBAAuB,GAAG,KAAK,CAAC,QAAQ,kEAA2B;;AAGzD,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;AAK5C,IAAA;IAHW,cAAc,GAAA;AACtB,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B;+GAjBW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA5B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,4BAA4B,ujBChCzC,w0HA6GA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDzFI,iBAAiB,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,mBAAA,EAAA,yBAAA,EAAA,2BAAA,EAAA,sCAAA,EAAA,0BAAA,EAAA,2BAAA,EAAA,kCAAA,CAAA,EAAA,QAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,qBAAqB,wEAErB,aAAa,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,YAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,WAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAGd,uBAAuB,qMALvB,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAGhB,kBAAkB,EAAA,IAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAClB,SAAS,yCAET,kBAAkB,EAAA,IAAA,EAAA,gBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAIT,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAjBxC,SAAS;+BACE,4BAA4B,EAAA,UAAA,EAE1B,IAAI,EAAA,OAAA,EACP;wBACP,iBAAiB;wBACjB,qBAAqB;wBACrB,gBAAgB;wBAChB,aAAa;wBACb,cAAc;wBACd,kBAAkB;wBAClB,SAAS;wBACT,uBAAuB;wBACvB;qBACD,EAAA,eAAA,EACgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,w0HAAA,EAAA;;;AEMjD;;;AAGG;MAcU,+BAA+B,CAAA;AA6B1C,IAAA,WAAA,GAAA;AA5BA;;;AAGG;AACM,QAAA,IAAA,CAAA,uBAAuB,GAAG,KAAK,CAAC,QAAQ,kEAA2B;AAE5E;;AAEG;AACM,QAAA,IAAA,CAAA,oBAAoB,GAAG,KAAK,CAAC,IAAI,gEAAC;AAE3C;;;AAGG;AACgB,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,4DAAC;AAEnD;;AAEG;AACgB,QAAA,IAAA,CAAA,4BAA4B,GAAG,MAAM,CAAC,IAAI,GAAG,EAAU,wEAAC;AAE1D,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAEzC,QAAA,IAAA,CAAA,0BAA0B,GAAG,QAAQ,CAAC,MACvD,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,sEAC3E;;;QAKC,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC,gBAAgB,EAAE;AACnD,gBAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;YACjC;AACF,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;AACH,IAAA,mBAAmB,CAAC,QAAiB,EAAA;AACnC,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrC;AAEA;;;;AAIG;AACH,IAAA,YAAY,CAAC,IAAkB,EAAA;AAC7B,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,KAAK,aAAa;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC,MAAM;QACpD,MAAM,cAAc,GAAG,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC;AAC9D,QAAA,IAAI,cAAc,EAAE,aAAa,EAAE;AACjC,YAAA,IAAI;AACF,gBAAA,MAAM,YAAY,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC;;AAE9E,gBAAA,IAAI,YAAY;AAAE,oBAAA,OAAO,YAAY;YACvC;YAAE,OAAO,GAAG,EAAE;;gBAEZ,OAAO,CAAC,IAAI,CAAC,CAAA,gCAAA,EAAmC,IAAI,CAAC,QAAQ,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC;YACxE;QACF;AAEA,QAAA,IAAI,WAAW,IAAI,cAAc,EAAE,cAAc,EAAE;YACjD,OAAO,cAAc,CAAC,cAAc;QACtC;AACA,QAAA,IAAI,CAAC,WAAW,IAAI,cAAc,EAAE,cAAc,EAAE;YAClD,OAAO,cAAc,CAAC,cAAc;QACtC;;QAGA,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAClC,WAAW,GAAG,OAAO,CAAC,2BAA2B,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC;;AAEtF,QAAA,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B;IACH;AAEU,IAAA,uBAAuB,CAAC,SAAiB,EAAA;AACjD,QAAA,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC,IAAG;AAC3C,YAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACvB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/D,YAAA,OAAO,IAAI;AACb,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;AAKG;AACO,IAAA,gBAAgB,CAAC,GAA4B,EAAA;QACrD,OAAO,GAAG,CAAC;AACT,cAAE,OAAO,CAAC,WAAW;AACrB,cAAE,IAAI,CAAC,gBAAgB;AACrB,kBAAE,OAAO,CAAC,gBAAgB;AAC1B,kBAAE,OAAO,CAAC,gBAAgB,CAAC;IACjC;AAEU,IAAA,WAAW,CAAC,IAAmB,EAAA;AACvC,QAAA,OAAO,IAAI,CAAC,IAAI,KAAK,sBAAsB;YACzC,IAAI,CAAC,IAAI,KAAK,gBAAgB;YAC9B,IAAI,CAAC,IAAI,KAAK;cACZ,IAAI,CAAC;cACL,SAAS;IACf;AAEU,IAAA,oCAAoC,CAC5C,GAA4B,EAAA;;AAG5B,QAAA,OAAO,GAAG,CAAC,MAAM,EAAE,oCAAoC,IAAI,aAAa;IAC1E;AAEA;;;;;;;;;AASG;AACO,IAAA,qCAAqC,CAAC,GAA4B,EAAA;;QAK1E,IAAI,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE;QACxC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE;AAC1E,YAAA,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,CAC3C,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAC9E;QACH;;;;QAKA,IAAI,IAAI,CAAC,oCAAoC,CAAC,GAAG,CAAC,KAAK,aAAa,EAAE;YACpE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE;QACxD;AAEA,QAAA,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC;AAEhF,QAAA,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAC/B,IAAI,IACF,IAAI,CAAC,IAAI,KAAK,sBAAsB;YACpC,IAAI,CAAC,IAAI,KAAK,gBAAgB;AAC9B,YAAA,IAAI,CAAC,IAAI,KAAK,aAAa,CAC9B;;QAED,MAAM,SAAS,GACb,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;;;;;;QAOrF,MAAM,8BAA8B,GAClC,gBAAgB;YAChB,cAAc,KAAK,CAAC,CAAC;AACrB,YAAA,CAAC,YAAY;AACb,aAAC,CAAC,GAAG,CAAC,gBAAgB,IAAI,SAAS,KAAK,GAAG,CAAC,MAAM,EAAE,8BAA8B,IAAI,CAAC,CAAC,CAAC;QAE3F,IAAI,CAAC,8BAA8B,EAAE;YACnC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE;QACxD;QAEA,MAAM,aAAa,GAAoB,EAAE;QACzC,MAAM,eAAe,GAAoB,EAAE;;QAG3C,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,KAAI;YAC9B,MAAM,kBAAkB,GACtB,GAAG,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,qBAAqB;;AAGnF,YAAA,IAAI,KAAK,IAAI,cAAc,IAAI,kBAAkB,EAAE;AACjD,gBAAA,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5B;iBAAO;AACL,gBAAA,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE;IAC3C;AAEA;;;;;;AAMG;AACK,IAAA,qBAAqB,CAAC,OAAwB,EAAA;QAIpD,IAAI,cAAc,GAAG,CAAC;QACtB,IAAI,gBAAgB,GAAG,KAAK;AAC5B,QAAA,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE;gBAC9B,gBAAgB,GAAG,IAAI;YACzB;YACA,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE;gBACpC,IAAI,gBAAgB,EAAE;oBACpB,cAAc,GAAG,CAAC;oBAClB;gBACF;qBAAO,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;;oBAEnC;gBACF;qBAAO;;oBAEL,cAAc,GAAG,CAAC,CAAC;oBACnB;gBACF;YACF;QACF;AACA,QAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE;IAC7C;+GAlOW,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAA/B,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,+BAAA,EAAA,MAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECrD5C,kkJAgHA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDjEI,aAAa,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,YAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,WAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACd,kBAAkB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,4BAA4B,EAAA,QAAA,EAAA,4BAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,2BAAA,EAAA,yBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAJ5B,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAOP,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAb3C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,+BAA+B,cAE7B,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACP,gBAAgB;wBAChB,aAAa;wBACb,cAAc;wBACd,kBAAkB;wBAClB;AACD,qBAAA,EAAA,QAAA,EAAA,kkJAAA,EAAA;;;AE9CH;;;AAGG;MAOU,4BAA4B,CAAA;AANzC,IAAA,WAAA,GAAA;AAOE;;AAEG;QAEH,IAAA,CAAA,MAAM,GAAG,KAAK;AAEd;;AAEG;QAEH,IAAA,CAAA,QAAQ,GAAG,KAAK;AAEhB;;AAEG;QAEH,IAAA,CAAA,OAAO,GAAG,EAAE;AAEZ;;AAEG;QAEH,IAAA,CAAA,IAAI,GAA8B,KAAK;AAEvC;;AAEG;AAEH,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAQ;AACzC,IAAA;+GA9BY,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA5B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,4BAA4B,yNCfzC,sZAkBA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,SAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,OAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,kBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,SAAA,EAAA,UAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAoB,aAAa,sEAA/B,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAE9B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBANxC,SAAS;+BACE,4BAA4B,EAAA,UAAA,EAE1B,IAAI,EAAA,OAAA,EACP,CAAC,aAAa,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAA,QAAA,EAAA,sZAAA,EAAA;;sBAMxD;;sBAMA;;sBAMA;;sBAMA;;sBAMA;;;AElCH;;;;;AAKG;MASU,sBAAsB,CAAA;AARnC,IAAA,WAAA,GAAA;QASW,IAAA,CAAA,IAAI,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAqB;QACjC,IAAA,CAAA,OAAO,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,SAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAa;AAEpB,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAE3C,QAAA,IAAA,CAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;YAC5C,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;AAC5C,QAAA,CAAC,wDAAC;AAEF;;;;AAIG;AACM,QAAA,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,YAAA,MAAM,GAAG,GACP,IAAI,CAAC,YAAY,EAAE,KAAK;AACtB,kBAAE,OAAO,CAAC,2BAA2B;AACrC,kBAAE,OAAO,CAAC,iCAAiC,CAAC;AAChD,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;YAC1B,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;AACjG,QAAA,CAAC,qDAAC;AAEF;;;;AAIG;AACM,QAAA,IAAA,CAAA,uBAAuB,GAAG,QAAQ,CAAC,MAAK;AAC/C,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAA,MAAM,IAAI,GACR,GAAG,CAAC,IAAI,IAAI,QAAQ,IAAI,GAAG,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,GAAG,EAAE;AAC3F,YAAA,IAAI,GAAW;YACf,IAAI,IAAI,EAAE;gBACR,GAAG;AACD,oBAAA,IAAI,CAAC,YAAY,EAAE,KAAK;AACtB,0BAAE,OAAO,CAAC,4BAA4B;AACtC,0BAAE,OAAO,CAAC,iCAAiC,CAAC;YAClD;iBAAO;gBACL,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAC/F;AACA,YAAA,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;AACrD,QAAA,CAAC,mEAAC;AACH,IAAA;+GA5CY,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAAtB,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECvBnC,imDAiDA,EAAA,MAAA,EAAA,CAAA,yGAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED5BY,OAAO,mFAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,SAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,OAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,kBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,SAAA,EAAA,UAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAE,QAAQ,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAEjD,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBARlC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EAGnB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAAA,QAAA,EAAA,imDAAA,EAAA,MAAA,EAAA,CAAA,yGAAA,CAAA,EAAA;;;AEhB/D;;;AAGG;MAQU,yBAAyB,CAAA;AAPtC,IAAA,WAAA,GAAA;AAQE;;AAEG;AACM,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,gDAAU;AAEzC;;AAEG;AACM,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAU;AAE1C;;AAEG;AACM,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAA4B,UAAU,gDAAC;AAE5D;;AAEG;AACM,QAAA,IAAA,CAAA,YAAY,GAAG,KAAK,CAAC,KAAK,wDAAC;AAEpC;;AAEG;AACM,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAC,KAAK,oDAAC;AAEhC;;AAEG;QACM,IAAA,CAAA,iBAAiB,GAAG,MAAM,EAAa;AAYjD,IAAA;AAVC;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAC1B,YAAA,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE;AACtB,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW;AAClC,SAAA,CAAC;IACJ;+GAxCW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAzB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,YAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EChBtC,udAoBA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDNY,aAAa,sEAAE,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAE9B,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAPrC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,IAAA,EAE5B,EAAE,KAAK,EAAE,YAAY,EAAE,EAAA,UAAA,EACjB,IAAI,EAAA,OAAA,EACP,CAAC,aAAa,EAAE,gBAAgB,CAAC,EAAA,QAAA,EAAA,udAAA,EAAA;;;AEY5C;;;;AAIG;MAoBU,eAAe,CAAA;AAgF1B,IAAA,WAAA,GAAA;AA/EA;;;AAGG;QAEH,IAAA,CAAA,SAAS,GAAG,KAAK;AAEjB;;AAEG;QAEH,IAAA,CAAA,QAAQ,GAAG,KAAK;AAEhB;;AAEG;QAEH,IAAA,CAAA,MAAM,GAAG,EAAE;AAmBX;;;AAGG;AAEH,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,YAAY,EAAa;AAEzC;;AAEG;AAEH,QAAA,IAAA,CAAA,QAAQ,GAAG,IAAI,YAAY,EAAQ;AAEnC;;AAEG;AACM,QAAA,IAAA,CAAA,QAAQ,GAAG,eAAe,CAAC,sBAAsB,oDAAC;AAE3D;;AAEG;AACc,QAAA,IAAA,CAAA,eAAe,GAAG,SAAS,CAA6B,qBAAqB,2DAAC;AAEtF,QAAA,IAAA,CAAA,WAAW,GAAG,CAAA,KAAA,EAAQ,MAAM,CAAC,UAAU,EAAE,EAAE;AAE5C,QAAA,IAAA,CAAA,OAAO,GAAe;AAC5B,YAAA,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC;AAC7B,YAAA,WAAW,EAAE,EAAE;AACf,YAAA,eAAe,EAAE,KAAK;AACtB,YAAA,KAAK,EAAE,OAAO,CAAC,2BAA2B,CAAC;AAC3C,YAAA,WAAW,EAAE,OAAO,CAAC,2BAA2B,CAAC;AACjD,YAAA,oBAAoB,EAAE,KAAK;AAC3B,YAAA,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC;AAC/B,YAAA,gBAAgB,EAAE,OAAO,CAAC,QAAQ,CAAC;AACnC,YAAA,cAAc,EAAE,OAAO,CACrB,2EAA2E,CAC5E;AACD,YAAA,kBAAkB,EAAE;AAClB,gBAAA,IAAI,EAAE,iBAAiB;AACvB,gBAAA,MAAM,EAAE;AACT;SACF;;QAIC,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,aAAa;AACvD,YAAA,IAAI,CAAC,SAAS;gBAAE;;;AAGhB,YAAA,IAAI,SAAS,CAAC,SAAS,GAAG,EAAE,EAAE;AAC5B,gBAAA,SAAS,CAAC,SAAS,GAAG,CAAC;YACzB;AACF,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;AAKG;IACH,IACI,MAAM,CAAC,KAA0B,EAAA;AACnC,QAAA,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE;IAC9C;AACA,IAAA,IAAI,MAAM,GAAA;QACR,OAAO,IAAI,CAAC,OAAO;IACrB;AAEA;;;;AAIG;AACH,IAAA,WAAW,CAAC,MAAa,EAAA;QACvB,MAAM,CAAC,cAAc,EAAE;QACvB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE;AAClB,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;AAClB,YAAA,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI,CAAC,MAAM;AACpB,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW;AAClC,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,MAAM,GAAG,EAAE;IAClB;AAEA;;;AAGG;IACH,MAAM,GAAA;AACJ,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;IACtB;+GAlIW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAAf,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,OAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,YAAA,EAAA,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,UAAA,EAAA,SAAA,EAqDU,sBAAsB,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECvG5D,2jLA4JA,2CDvHI,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,2BAA2B,EAAA,QAAA,EAAA,2BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC3B,aAAa,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACb,OAAO,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACP,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAGhB,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAC,IAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,SAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,OAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,kBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,SAAA,EAAA,UAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EARb,gBAAgB,6CAMhB,kBAAkB,EAAA,IAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAClB,SAAS,EAAA,IAAA,EAAA,OAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAET,UAAU,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAKD,eAAe,EAAA,UAAA,EAAA,CAAA;kBAnB3B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,EAAA,eAAA,EAEN,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACP,gBAAgB;wBAChB,WAAW;wBACX,2BAA2B;wBAC3B,aAAa;wBACb,OAAO;wBACP,gBAAgB;wBAChB,kBAAkB;wBAClB,SAAS;wBACT,aAAa;wBACb;AACD,qBAAA,EAAA,UAAA,EACW,IAAI,EAAA,IAAA,EACV,EAAE,KAAK,EAAE,YAAY,EAAE,EAAA,QAAA,EAAA,2jLAAA,EAAA;;sBAO5B;;sBAMA;;sBAMA;;sBAQA;;sBAIA;;sBAEA;;sBAUA;;sBAMA;AAMmC,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAAA,sBAAsB,0EAKe,qBAAqB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA;sBA0C7F;;;AEtJH;;AAEG;;;;"}
1
+ {"version":3,"file":"c8y-ngx-components-ai-ai-chat.mjs","sources":["../../ai/ai-chat/ai-chat-tool-call.component.ts","../../ai/ai-chat/ai-chat-tool-call.component.html","../../ai/ai-chat/json-to-markdown.pipe.ts","../../ai/ai-chat/ai-chat-assistant-part.component.ts","../../ai/ai-chat/ai-chat-assistant-part.component.html","../../ai/ai-chat/ai-chat-assistant-message.component.ts","../../ai/ai-chat/ai-chat-assistant-message.component.html","../../ai/ai-chat/ai-chat-message-action.component.ts","../../ai/ai-chat/ai-chat-message-action.component.html","../../ai/ai-chat/ai-chat-message.component.ts","../../ai/ai-chat/ai-chat-message.component.html","../../ai/ai-chat/ai-chat-suggestion.component.ts","../../ai/ai-chat/ai-chat-suggestion.component.html","../../ai/ai-chat/ai-chat.component.ts","../../ai/ai-chat/ai-chat.component.html","../../ai/ai-chat/c8y-ngx-components-ai-ai-chat.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, input, signal, Type } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { ToolCallConfig, ToolCallPart } from '@c8y/ngx-components/ai';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { JsonPipe, NgComponentOutlet } from '@angular/common';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\n\n@Component({\n selector: 'c8y-ai-chat-tool-call',\n templateUrl: './ai-chat-tool-call.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgComponentOutlet,\n JsonPipe,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule\n ]\n})\nexport class AiChatToolCallComponent {\n /**\n * The tool call part to render. This includes all information about the tool call, including the name of the tool,\n * the input provided and (once available) the output from the tool.\n */\n readonly tool = input.required<ToolCallPart>();\n\n /**\n * Whether the tool call is still in progress.\n */\n readonly isExecuting = input.required<boolean>();\n\n /**\n * A custom component to render the details of the tool call. If not provided, the default details section will be shown.\n */\n readonly toolDetailsComponent = input<Type<unknown> | undefined>(undefined);\n\n /**\n * Shows the default details section for a tool call.\n */\n readonly showDefaultToolDetails = input<boolean>(false);\n\n /**\n * The label to show while the tool is executing. If not provided, a default label will be generated based on the tool name.\n */\n readonly executingLabel = input<string | undefined>(undefined);\n /**\n * The label to show once the tool has completed. If not provided, a default label will be generated based on the tool name and whether the tool call was successful or resulted in an error.\n */\n readonly completedLabel = input<string | undefined>(undefined);\n\n /**\n * A function that can generate a label for this tool call based on the tool call data.\n */\n readonly labelProvider = input<ToolCallConfig['labelProvider']>();\n\n protected readonly expanded = signal(false);\n protected readonly everExpanded = signal(false);\n\n private readonly translateService = inject(TranslateService);\n\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n if (this.labelProvider()) {\n try {\n const dynamicLabel = this.labelProvider()(tool, this.translateService);\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, report it then fall back to default logic\n console.error(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && this.executingLabel()) {\n return this.executingLabel();\n }\n if (!isExecuting && this.completedLabel()) {\n return this.completedLabel();\n }\n\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n { toolName: tool.toolName }\n );\n }\n\n protected toggleExpanded(): void {\n const willExpand = !this.expanded();\n this.expanded.set(willExpand);\n if (willExpand) {\n this.everExpanded.set(true);\n }\n }\n}\n","@let _tool = tool();\n@let showDetails = showDefaultToolDetails() || toolDetailsComponent() || _tool.error;\n@let isToolExpanded = expanded();\n\n<fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n [attr.aria-label]=\"'Tool call: ' + _tool.toolName\"\n>\n <button\n class=\"btn-clean ai-tool-call__btn\"\n [attr.aria-expanded]=\"showDetails ? isToolExpanded : null\"\n [attr.aria-controls]=\"showDetails ? 'tool-call-' + _tool.toolCallId : null\"\n type=\"button\"\n [attr.data-cy]=\"'tool-call-' + _tool.toolName\"\n [disabled]=\"!showDetails || null\"\n (click)=\"toggleExpanded()\"\n >\n @if (isExecuting()) {\n <i\n class=\"icon-spin icon-14 text-primary m-r-4\"\n c8yIcon=\"spinner\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <!-- Treat it as an error if a tool still thinks its executing when the message containing it is not -->\n @if (_tool.error || isExecuting()) {\n <i\n class=\"icon-14 text-danger m-r-4\"\n [c8yIcon]=\"'exclamation-circle'\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <i\n class=\"icon-14 text-success m-r-4\"\n [c8yIcon]=\"'check'\"\n aria-hidden=\"true\"\n ></i>\n }\n }\n <span class=\"small\">{{ getToolLabel(_tool) | translate }}</span>\n\n @if (showDetails) {\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"isToolExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n <!-- If this is an artifact tool, render it - but do so lazily only on first open,\n since these components could be heavyweight (e.g. Monaco)\n -->\n @if (showDetails && (isToolExpanded || everExpanded())) {\n <div\n class=\"collapse tool-details m-t-8 p-8 b-r-4\"\n [attr.aria-label]=\"'Tool details for message latest tool: ' + _tool.toolName\"\n role=\"region\"\n [collapse]=\"!isToolExpanded\"\n [id]=\"'tool-call-' + _tool.toolCallId\"\n [isAnimated]=\"true\"\n data-cy=\"ai-tool-component\"\n >\n @if (toolDetailsComponent()) {\n <ng-container\n [ngComponentOutlet]=\"toolDetailsComponent()\"\n [ngComponentOutletInputs]=\"{ tool: _tool }\"\n ></ng-container>\n } @else {\n @let noneLabel = '(no data)' | translate;\n\n <p class=\"text-label-small\">{{ 'Tool input' | translate }}</p>\n <pre class=\"fit-w small\">{{ _tool.input || noneLabel | json }}</pre>\n\n @if (_tool.type === 'tool-result') {\n <p class=\"text-label-small\">{{ 'Tool output' | translate }}</p>\n @if (\n typeof _tool.output === 'string' || _tool.output === undefined || _tool.output === null\n ) {\n <pre class=\"fit-w small\">{{ _tool.output || noneLabel }}</pre>\n } @else {\n <pre class=\"fit-w small\">{{ _tool.output | json }}</pre>\n }\n }\n }\n </div>\n }\n</fieldset>\n","import { Pipe, PipeTransform } from '@angular/core';\n\n/**\n * Converts a JSON string to a markdown code block.\n */\n@Pipe({\n name: 'jsonToMarkdown',\n standalone: true\n})\nexport class JsonToMarkdownPipe implements PipeTransform {\n transform(value: string | null | undefined): string {\n if (!value) {\n return '```json\\nnull\\n```';\n }\n\n const escapedValue = value.replace(/\\\\/g, '\\\\\\\\').replace(/`/g, '\\\\`');\n return `\\`\\`\\`json\\n${escapedValue}\\n\\`\\`\\``;\n }\n}\n","import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';\nimport { AIMessagePart } from '@c8y/ngx-components/ai';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe\n} from '@c8y/ngx-components';\nimport { AsyncPipe, NgComponentOutlet } from '@angular/common';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AssistantMessageContext } from './ai-chat-assistant-message.component';\nimport { AiChatToolCallComponent } from './ai-chat-tool-call.component';\nimport { JsonToMarkdownPipe } from './json-to-markdown.pipe';\n\n/** This renders a part of an assistant message. Currently only ToolCallPart is supported, but later we can expand this to deal with all part types. */\n@Component({\n selector: 'c8y-ai-chat-assistant-part',\n templateUrl: './ai-chat-assistant-part.component.html',\n standalone: true,\n imports: [\n NgComponentOutlet,\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n MarkdownToHtmlPipe,\n AsyncPipe,\n AiChatToolCallComponent,\n JsonToMarkdownPipe\n ],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AiChatAssistantPartComponent {\n readonly part = input.required<AIMessagePart>();\n\n /** Whether this part is rendered as part of the main answer, or is an intermediate step with more muted rendering. */\n readonly displayAsPartOfMainAnswer = input(true);\n\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /** Tracks whether this is currently expanded (used for reasoning section). */\n protected readonly expanded = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update(v => !v);\n }\n}\n","@let ctx = assistantMessageContext();\n@let _config = ctx.config;\n@let toolCallConfig = _config.toolCallConfig || {};\n@let _part = part();\n\n@if (_part.type === 'text') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></p>\n} @else if (_part.type === 'reasoning') {\n @let reasoningExpanded = expanded();\n\n <fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n data-cy=\"ai-reasoning\"\n >\n <button\n class=\"btn-clean ai-tool-call__btn\"\n aria-label=\"{{ 'Toggle display of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"reasoningExpanded\"\n [attr.aria-controls]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"toggleExpanded()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'ai-sparkles'\"\n ></i>\n @let hideReasoning = 'Hide reasoning' | translate;\n @let showReasoning = 'Show reasoning' | translate;\n <span class=\"small\">{{ reasoningExpanded ? hideReasoning : showReasoning }}</span>\n <i\n class=\"m-l-4 icon-12 text-muted\"\n [c8yIcon]=\"reasoningExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse reasoning-content\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"!reasoningExpanded\"\n [id]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n data-cy=\"ai-reasoning-content\"\n >\n <div\n class=\"m-t-8 p-b-4 text-muted\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></div>\n </div>\n </fieldset>\n} @else if (_part.type === 'object') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.jsonContent | jsonToMarkdown | markdownToHtml | async\"\n data-cy=\"ai-object-content\"\n ></p>\n} @else if (_part.type === 'step-start') {\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"ai-step-start hidden-copy-label\"\n aria-hidden=\"true\"\n data-cy=\"ai-step-start-separator\"\n translate\n >--- (step separator) ---</span\n >\n} @else if (_part.type.startsWith('tool')) {\n @let tool = $any(_part);\n @let toolDisplay = toolCallConfig[tool.toolName];\n\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n translate\n [translateParams]=\"{ toolName: tool.toolName }\"\n ngNonBindable\n >--- Tool call: {{ toolName }} ---</span\n >\n\n @if (toolDisplay?.component) {\n <div data-cy=\"ai-tool-with-custom-component\">\n <ng-container\n [ngComponentOutlet]=\"toolDisplay.component\"\n [ngComponentOutletInputs]=\"{\n tool: tool,\n ctx: ctx\n }\"\n ></ng-container>\n </div>\n } @else if (!toolDisplay?.isHidden) {\n <!-- Don't allow expanding while tool call is in progress - it's unlikely to have anything worth rendering,\n and complicates implementation for the client to have to check for the isExecuting case.\n -->\n <c8y-ai-chat-tool-call\n [tool]=\"tool\"\n [isExecuting]=\"tool.type !== 'tool-result' && ctx.isMessageLoading\"\n [toolDetailsComponent]=\"_config.toolDetailsComponent?.(tool)\"\n [showDefaultToolDetails]=\"_config.showDefaultToolDetails === 'all'\"\n [executingLabel]=\"toolDisplay?.executingLabel\"\n [completedLabel]=\"toolDisplay?.completedLabel\"\n [labelProvider]=\"toolDisplay?.labelProvider\"\n ></c8y-ai-chat-tool-call>\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n signal\n} from '@angular/core';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport {\n AIAssistantMessage,\n AIMessagePart,\n AssistantMessageDisplayConfig,\n ToolCallPart\n} from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AiChatAssistantPartComponent } from './ai-chat-assistant-part.component';\n\n/**\n * Context object which includes the inputs needed for assistant message rendering.\n * If creating a custom component for assistant message rendering, you will receive this as an input.\n */\nexport interface AssistantMessageContext {\n message: AIAssistantMessage;\n config: AssistantMessageDisplayConfig;\n\n /** The message response is currently streaming in (not yet complete). */\n isMessageLoading: boolean;\n\n /** A number identifying this message in the chat history numbered from the latest - 0 is the latest, -1 is the previous, etc. */\n messageDisplayIndex: number;\n}\n\n/**\n * This is the default component used to render the contents of a message from the AI assistant, including\n * the main answer text, text from earlier steps, reasoning text and tool calls.\n */\n@Component({\n selector: 'c8y-ai-chat-assistant-message',\n templateUrl: './ai-chat-assistant-message.component.html',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule,\n AiChatAssistantPartComponent\n ]\n})\nexport class AiChatAssistantMessageComponent {\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /**\n * By default this component will render a \"Working...\" indicator while streaming results. This input can turn that off if required.\n */\n readonly showWorkingIndicator = input(true);\n\n /**\n * Whether the thinking section is expanded. Initialized to false unless the message is still loading.\n * Call setThinkingExpanded() via viewChild to control this programmatically. Does nothing if appearance does not distinguish thinking steps.\n */\n protected readonly thinkingExpanded = signal(false);\n\n /**\n * Tracks which reasoning sections are expanded, keyed by step index.\n */\n protected readonly expandedReasoningStepIndices = signal(new Set<number>());\n\n private readonly translateService = inject(TranslateService);\n\n protected readonly thinkingAndMainAnswerParts = computed(() =>\n this.splitContentIntoThinkingAndMainAnswer(this.assistantMessageContext())\n );\n\n constructor() {\n // Expand when we initially set the message loading flag, without overwriting the value\n // any other time\n effect(() => {\n if (this.assistantMessageContext().isMessageLoading) {\n this.thinkingExpanded.set(true);\n }\n });\n }\n\n /**\n * This is public and exists for agent-chat to collapse older messages.\n * @param expanded Whether the thinking section should be expanded or not.\n */\n setThinkingExpanded(expanded: boolean): void {\n this.thinkingExpanded.set(expanded);\n }\n\n /**\n * Get a translated/translateable label for the specified tool.\n * @param tool The tool call part to get the label for.\n * @return The label to show for this tool call.\n */\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n const config = this.assistantMessageContext().config;\n const toolCallConfig = config?.toolCallConfig?.[tool.toolName];\n if (toolCallConfig?.labelProvider) {\n try {\n const dynamicLabel = toolCallConfig.labelProvider(tool, this.translateService);\n // Run it through translate in case it contains gettext values\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, so report this - then fallback to default logic\n console.warn(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && toolCallConfig?.executingLabel) {\n return toolCallConfig.executingLabel;\n }\n if (!isExecuting && toolCallConfig?.completedLabel) {\n return toolCallConfig.completedLabel;\n }\n\n // If we have no specific label configured, use the default\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n // Have to use the tool id since that's all we have\n { toolName: tool.toolName }\n );\n }\n\n protected toggleReasoningExpanded(stepIndex: number): void {\n this.expandedReasoningStepIndices.update(s => {\n const next = new Set(s);\n s.has(stepIndex) ? next.delete(stepIndex) : next.add(stepIndex);\n return next;\n });\n }\n\n /**\n * Note: ctx is passed as a parameter rather than reading the signal in the template to ensure\n * it's totally aligned with what the template is rendering.\n * @param ctx The context for the assistant message.\n * @return The label to display for the reasoning section.\n */\n protected getThinkingLabel(ctx: AssistantMessageContext): string {\n return ctx.isMessageLoading\n ? gettext('Reasoning')\n : this.thinkingExpanded()\n ? gettext('Hide reasoning')\n : gettext('Show reasoning');\n }\n\n protected getToolName(part: AIMessagePart): string | undefined {\n return part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n ? part.toolName\n : undefined;\n }\n\n protected experimental_nonFinalStepTextDisplay(\n ctx: AssistantMessageContext\n ): AssistantMessageDisplayConfig['experimental_nonFinalStepTextDisplay'] {\n // For now be conservative with the old behaviour, but hope to change this once we've got working really smoothly.\n return ctx.config?.experimental_nonFinalStepTextDisplay || 'main-answer';\n }\n\n /**\n * Splits the assistant message content into two arrays: thinking content and main answer content.\n * This also removes hidden tools.\n *\n * If using the experimental rendering modes, main answer content is text in the final step (if conditions are met) plus any tool calls configured to be shown with the main answer.\n * Thinking content is everything else (reasoning, earlier text, tool calls not shown with main answer).\n *\n * @param ctx The context for the assistant message.\n * @return An object with thinkingParts and mainAnswerParts arrays.\n */\n protected splitContentIntoThinkingAndMainAnswer(ctx: AssistantMessageContext): {\n thinkingParts: AIMessagePart[];\n mainAnswerParts: AIMessagePart[];\n } {\n // Remove hidden tools\n let content = ctx.message?.content || [];\n if (Object.values(ctx.config?.toolCallConfig || {}).some(c => c?.isHidden)) {\n content = (ctx.message?.content || []).filter(\n part => !ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isHidden\n );\n }\n\n // Putting this check here keeps things safe by ensuring there is no chance of any rendering differences\n // during streaming unless in one of the experimental modes. This means the rest of this method only applies\n // to the experimental rendering.\n if (this.experimental_nonFinalStepTextDisplay(ctx) === 'main-answer') {\n return { thinkingParts: [], mainAnswerParts: content };\n }\n\n const { finalStepStart, finalStepHasText } = this.findFinalStepWithText(content);\n\n const hasToolCalls = content.some(\n part =>\n part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n );\n // Since we don't bother with a step-start at index 0 for the first step, add one\n const stepCount =\n content.filter((part, index) => index > 0 && part.type === 'step-start').length + 1;\n\n // The final step text goes in the main answer area if there are no pending tool calls\n // (since otherwise the tools would show below it), and\n // message has finished loading, or we're expecting more steps than this.\n // Note that we check all steps for toolCalls not just the current one, for the sake of \"fake\" tool calls created by preprocessAgentMessage\n // where additional step boundaries may be added to simplify parsing.\n const shouldShowLastTextAsMainAnswer =\n finalStepHasText &&\n finalStepStart !== -1 &&\n !hasToolCalls &&\n (!ctx.isMessageLoading || stepCount >= (ctx.config?.experimental_expectedStepCount || 2));\n\n if (!shouldShowLastTextAsMainAnswer) {\n return { thinkingParts: content, mainAnswerParts: [] };\n }\n\n const thinkingParts: AIMessagePart[] = [];\n const mainAnswerParts: AIMessagePart[] = [];\n\n // Split the content: final step and promoted tool calls go to main answer, everything else to thinking\n content.forEach((part, index) => {\n const isPromotedToolCall =\n ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isShownWithMainAnswer;\n\n // This ensures promoted tool calls never go to the collapseable thinking area\n if (index >= finalStepStart || isPromotedToolCall) {\n mainAnswerParts.push(part);\n } else {\n thinkingParts.push(part);\n }\n });\n\n return { thinkingParts, mainAnswerParts };\n }\n\n /**\n * Scans backwards through the content parts to find the step-start index for the last step\n * that contains at least one text part. Skips trailing empty steps (step-start with no text after).\n *\n * @returns `finalStepStart` — index of the step-start part, or 0 if content belongs to the implicit first step.\n * `finalStepHasText` — whether a step with text was found at all.\n */\n private findFinalStepWithText(content: AIMessagePart[]): {\n finalStepStart: number;\n finalStepHasText: boolean;\n } {\n let finalStepStart = 0;\n let finalStepHasText = false;\n for (let i = content.length - 1; i >= 0; i--) {\n if (content[i].type === 'text') {\n finalStepHasText = true;\n }\n if (content[i].type === 'step-start') {\n if (finalStepHasText) {\n finalStepStart = i;\n break;\n } else if (i === content.length - 1) {\n // Trailing empty step-start — keep looking\n continue;\n } else {\n // step-start found but no text in that step\n finalStepStart = -1;\n break;\n }\n }\n }\n return { finalStepStart, finalStepHasText };\n }\n}\n","@let ctx = assistantMessageContext();\n@let parts = ctx.message.content;\n@let _config = ctx.config;\n\n<!-- \nWe show the assistant message in (up to) 3 slots:\n- collapsible thinking block (for intermediate step text, standard tool calls, etc)\n- special \"artifact\" tools that update user artifacts and need prominent display (e.g. for code edits made by the AI)\n- the main answer (typically from the final step)\n\nThis is a standard approach for AI chats - step text and tools from an LLM are treated as a work log, i.e. useful to \ndisplay progress while streaming the response, but only the text from the last step after all tool calls gives the main answer of the AI to the user. \n\nDepending on configuration, we have an experimental option (if we need it) to style the thinking block the same as the main answer. \n\nOnce the message finishes loading we know the final step IS the main content, but if it's still steaming \nwe don't know for sure which step has the final/main answer until the LLM has actually finished so have to take a heuistic guess \n(and minimize jumping in the UI). \n\nFor applications where we expect tool calls in most responses, assume the 2nd step is probably the final text; \nfor applications where tool calls are less ubiquitous, assume the first step is main answer until proved otherwise. \nThis minimizes jumping (except when there are >2 steps, which is rare).\n\n-->\n\n@let contentSplit = thinkingAndMainAnswerParts();\n@let nonFinalStepTextDisplay = experimental_nonFinalStepTextDisplay(ctx);\n\n<!-- Thinking steps section - holds reasoning, text from non-final steps, and standard/non-artifact tool calls -->\n\n@if (contentSplit.thinkingParts.length > 0) {\n <div\n class=\"m-b-8 text-muted\"\n [class.thinking-block]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block'\"\n [class.small]=\"nonFinalStepTextDisplay === 'muted-main-answer'\"\n [class.thinking-steps-appearance]=\"nonFinalStepTextDisplay\"\n data-cy=\"thinking-steps\"\n >\n @if (nonFinalStepTextDisplay === 'collapsible-thinking-block') {\n <button\n class=\"btn btn-clean btn-xs text-muted p-l-0\"\n aria-label=\"{{ 'Toggle collapse of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"thinkingExpanded()\"\n [attr.aria-controls]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"thinkingExpanded.set(!thinkingExpanded())\"\n >\n <span class=\"small\">{{ getThinkingLabel(ctx) }}</span>\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"thinkingExpanded() ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n }\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block' && !thinkingExpanded()\"\n [id]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n >\n <div\n [class]=\"\n nonFinalStepTextDisplay === 'collapsible-thinking-block'\n ? 'thinking-content bg-level-1 m-t-8 p-8 b-r-4 border-left-accent small m-b-0 text-muted'\n : ''\n \"\n >\n @for (part of contentSplit.thinkingParts; track $index) {\n @if (part.type !== 'step-start' || $index > 0) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"nonFinalStepTextDisplay !== 'muted-main-answer'\"\n ></c8y-ai-chat-assistant-part>\n }\n }\n </div>\n </div>\n </div>\n}\n\n<!-- Main answer area contains the text from the final step, and \n any promoted tool calls which are too important to be hidden in the collapeable thinking area -->\n<div\n class=\"message-content\"\n data-cy=\"ai-main-answer-content\"\n>\n @for (part of contentSplit.mainAnswerParts; track $index) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"true\"\n ></c8y-ai-chat-assistant-part>\n }\n</div>\n\n@if (ctx.isMessageLoading && showWorkingIndicator()) {\n <!-- Once the message starts to stream, show a small/low-key thinking indicator -->\n <div\n class=\"text-muted text-12 fade-in-out d-flex j-c-end\"\n aria-live=\"polite\"\n role=\"status\"\n data-cy=\"working-indicator\"\n >\n {{ 'Working…' | translate }}\n </div>\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An action button that can be added to chat messages.\n * Typically used for actions like copying, regenerating, or providing feedback on messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message-action',\n templateUrl: './ai-chat-message-action.component.html',\n standalone: true,\n imports: [TooltipModule, C8yTranslatePipe, IconDirective]\n})\nexport class AiChatMessageActionComponent {\n /**\n * Set to true to use content projection for custom action button content.\n */\n @Input()\n custom = false;\n\n /**\n * Disables the action button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * Tooltip text displayed when hovering over the action button.\n */\n @Input()\n tooltip = '';\n\n /**\n * Icon to display in the action button.\n */\n @Input()\n icon: SupportedIconsSuggestions = 'cog';\n\n /**\n * Emitted when the action button is clicked.\n */\n @Output()\n actionClicked = new EventEmitter<void>();\n}\n","@if (!custom) {\n <button\n class=\"btn btn-dot text-muted\"\n [attr.aria-label]=\"tooltip | translate\"\n [tooltip]=\"tooltip | translate\"\n [adaptivePosition]=\"true\"\n [delay]=\"500\"\n (click)=\"actionClicked.emit()\"\n [disabled]=\"disabled\"\n >\n <i\n class=\"text-12\"\n [c8yIcon]=\"icon\"\n ></i>\n </button>\n} @else {\n <ng-content></ng-content>\n}\n","import { Component, computed, input, inject, ChangeDetectionStrategy } from '@angular/core';\n\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { C8yTranslatePipe, DatePipe } from '@c8y/ngx-components';\nimport { NgClass } from '@angular/common';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { TranslateService } from '@ngx-translate/core';\n\n/**\n * A container for content and actions that should be rendered for each chat message.\n *\n * Project content into this component to display the message, for example add an `<ai-chat-assistant-message>`\n * for assistant messages, and a simple `markdownToHtml | async` rendering of the content for user messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message',\n templateUrl: './ai-chat-message.component.html',\n styleUrl: './ai-chat-message.component.scss',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgClass, TooltipModule, C8yTranslatePipe, DatePipe]\n})\nexport class AiChatMessageComponent {\n readonly role = input<AIMessage['role']>();\n readonly message = input<AIMessage>();\n\n private readonly translateService = inject(TranslateService);\n\n private readonly roleResolved = computed(() => {\n return this.message()?.role || this.role();\n });\n\n /**\n * Generates an accessible label for the message container.\n * Includes the role (user or assistant) and timestamp if available.\n * @returns The aria-label string for screen readers\n */\n readonly ariaLabel = computed(() => {\n const tpl =\n this.roleResolved() === 'user'\n ? gettext('You said: \"{{ message }}\"')\n : gettext('Assistant said: \"{{ message }}\"');\n const msg = this.message();\n return this.translateService.instant(tpl, { message: msg?.content || gettext('No response.') });\n });\n\n /**\n * Generates an accessible label for the message content.\n * Prefixes the content with contextual information about who sent it.\n * @returns The aria-label string with prefixed role information\n */\n readonly messageContentAriaLabel = computed(() => {\n const msg = this.message();\n const time =\n msg.role != 'system' && msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString() : '';\n let tpl: string;\n if (time) {\n tpl =\n this.roleResolved() === 'user'\n ? gettext('User message at {{ time }}')\n : gettext('Assistant message at {{ time }}');\n } else {\n tpl = this.roleResolved() === 'user' ? gettext('User message') : gettext('Assistant message');\n }\n return this.translateService.instant(tpl, { time });\n });\n}\n","<div\n class=\"d-col p-t-16\"\n [attr.aria-label]=\"ariaLabel()\"\n role=\"article\"\n>\n <div\n class=\"chat-message text-break-word\"\n [ngClass]=\"{\n 'user-message': message()?.role === 'user' || role() === 'user',\n 'agent-message': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n >\n {{ `====== ${messageContentAriaLabel()} ======` }}</span\n >\n\n <!-- Apply the class and aria-label to both the main content and whatever is projected, so we get the same styling by default -->\n <div\n class=\"message-content\"\n [attr.aria-label]=\"messageContentAriaLabel()\"\n >\n <div style=\"display: contents\">\n <ng-content select=\":not(c8y-ai-chat-message-action)\"></ng-content>\n </div>\n </div>\n @if (message()?.timestamp) {\n <div class=\"message-timestamp\">\n <span [tooltip]=\"message()?.timestamp | c8yDate\">\n {{ message()?.timestamp | c8yDate: 'adaptiveDate' }}\n </span>\n </div>\n }\n </div>\n <div\n class=\"message-action\"\n [attr.aria-label]=\"'Message actions' | translate\"\n role=\"toolbar\"\n [ngClass]=\"{\n 'user-action showOnHover': message()?.role === 'user' || role() === 'user',\n 'agent-action p-l-16': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <ng-content select=\"c8y-ai-chat-message-action\"></ng-content>\n </div>\n</div>\n","import { Component, input, output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\n\n/**\n * A suggestion chip that can be displayed in the chat interface.\n * When clicked, it automatically populates and sends a predefined prompt.\n */\n@Component({\n selector: 'c8y-ai-chat-suggestion',\n templateUrl: './ai-chat-suggestion.component.html',\n host: { class: 'd-contents' },\n standalone: true,\n imports: [IconDirective, C8yTranslatePipe]\n})\nexport class AiChatSuggestionComponent {\n /**\n * The visible label text displayed on the suggestion chip.\n */\n readonly label = input.required<string>();\n\n /**\n * The prompt text that will be sent when the suggestion is clicked.\n */\n readonly prompt = input.required<string>();\n\n /**\n * Icon to display alongside the suggestion label.\n */\n readonly icon = input<SupportedIconsSuggestions>('c8y-bulb');\n\n /**\n * When true, uses AI-styled buttons instead of default styling.\n */\n readonly useAiButtons = input(false);\n\n /**\n * Disables the suggestion chip when true.\n */\n readonly disabled = input(false);\n\n /**\n * Emitted when the suggestion is clicked, providing the prompt as an AIMessage.\n */\n readonly suggestionClicked = output<AIMessage>();\n\n /**\n * Handles suggestion click and emits the prompt as a user message.\n */\n suggest() {\n this.suggestionClicked.emit({\n content: this.prompt(),\n role: 'user',\n timestamp: new Date().toISOString()\n });\n }\n}\n","@if (!useAiButtons()) {\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <i [c8yIcon]=\"icon()\"></i>\n {{ label() | translate }}\n </button>\n} @else {\n <button\n class=\"btn btn-sm btn-ai\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <span>{{ label() | translate }}</span>\n </button>\n}\n","import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n contentChildren,\n effect,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n TemplateRef,\n viewChild\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe,\n NumberPipe,\n TextareaAutoresizeDirective\n} from '@c8y/ngx-components';\nimport { AIMessage, ChatConfig } from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AiChatMessageComponent } from './ai-chat-message.component';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An interactive chat interface component for AI-powered conversations.\n * Displays messages in a conversation format with support for loading states,\n * custom configuration, and markdown formatting.\n */\n@Component({\n selector: 'c8y-ai-chat',\n templateUrl: './ai-chat.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n FormsModule,\n TextareaAutoresizeDirective,\n IconDirective,\n NgClass,\n NgTemplateOutlet,\n MarkdownToHtmlPipe,\n AsyncPipe,\n TooltipModule,\n NumberPipe\n ],\n standalone: true,\n host: { class: 'd-contents' }\n})\nexport class AiChatComponent {\n /**\n * Indicates whether the chat is currently processing a request.\n * When true, displays a cancel button instead of send button and disables the input.\n */\n @Input()\n isLoading = false;\n\n /**\n * Disables the chat input and send button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * The current text in the chat input field. Supports two-way binding.\n */\n @Input()\n prompt = '';\n\n /**\n * Template for rendering custom suggestions below the input field. Can be used to provide predefined prompts or actions\n * from a dynamic source such as the AI. To use this, wrap your suggestion components in an `<ng-template #suggestionsRef>`\n * (where `suggestionsRef` matches the suggestionsTemplate reference);\n */\n @Input()\n suggestionsTemplate?: TemplateRef<any>;\n\n /** Template for customizing the welcome view using `<ng-template>`. */\n @Input() welcomeTemplate?: TemplateRef<any>;\n\n @Input() cumulativeUsage?: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n } | null = null;\n\n /**\n * Emitted when the user sends a message.\n * Provides an AIMessage object with role, content, and timestamp.\n */\n @Output()\n onMessage = new EventEmitter<AIMessage>();\n\n /**\n * Emitted when the user cancels an ongoing operation during loading state.\n */\n @Output()\n onCancel = new EventEmitter<void>();\n\n /**\n * Child message components displayed in the chat.\n */\n readonly messages = contentChildren(AiChatMessageComponent);\n\n /**\n * Reference to the scroll container for the chat messages.\n */\n private readonly scrollContainer = viewChild<ElementRef<HTMLDivElement>>('chatScrollContainer');\n\n readonly componentId = `chat-${crypto.randomUUID()}`;\n\n private _config: ChatConfig = {\n headline: gettext('Welcome!'),\n welcomeText: '',\n welcomePosition: 'top',\n title: gettext('What can I help you with?'),\n placeholder: gettext('Type your message here...'),\n scrollbarOnlyOnHover: false,\n sendButtonText: gettext('Send'),\n cancelButtonText: gettext('Cancel'),\n disclaimerText: gettext(\n 'AI-generated responses can contain errors. Verify the details before use.'\n ),\n userInterfaceIcons: {\n send: 'arrow-circle-up',\n cancel: 'stop-circle'\n }\n };\n\n constructor() {\n // Auto-scroll to bottom when messages change\n effect(() => {\n this.messages(); // track changes\n const container = this.scrollContainer()?.nativeElement;\n if (!container) return;\n // In column-reverse, scrollTop=0 IS the visual bottom.\n // Only snap back if user is already near the bottom (wasn't scrolled up).\n if (container.scrollTop < 50) {\n container.scrollTop = 0;\n }\n });\n }\n\n /**\n * Configuration object for customizing labels, placeholders, and icons.\n * Accepts partial configuration to override defaults.\n * @param value Partial configuration to merge with defaults.\n * @returns The complete configuration object.\n */\n @Input()\n set config(value: Partial<ChatConfig>) {\n this._config = { ...this._config, ...value };\n }\n get config(): ChatConfig {\n return this._config;\n }\n\n /**\n * Handles message submission when the user sends a message.\n * Emits the onMessage event and clears the input.\n * @param $event The event object from the form submission\n */\n sendMessage($event: Event): void {\n $event.preventDefault();\n if (!this.prompt) return;\n this.onMessage.emit({\n role: 'user',\n content: this.prompt,\n timestamp: new Date().toISOString()\n });\n this.prompt = '';\n }\n\n /**\n * Handles cancellation of ongoing operations during loading state.\n * Emits the onCancel event.\n */\n cancel(): void {\n this.onCancel.emit();\n }\n}\n","<div\n class=\"d-col fit-h fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-balance\">{{ config.title | translate }}</p>\n }\n <div class=\"text-balance chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-8 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{ config.placeholder | translate }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n ></textarea>\n <div class=\"chat-input-group-btn\">\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted m-b-8 text-10 p-l-16\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <span\n class=\"tag tag--info m-l-auto\"\n [tooltip]=\"\n 'Input tokens: {{ input }} \\n Output tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0) |\n c8yNumber : 'floor':'1.0-0' } }}\n </span>\n }\n </div>\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2"],"mappings":"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"}
@@ -2039,7 +2039,12 @@ class AlarmsListComponent {
2039
2039
  return scrollTopPixels > this.HIDE_INTERVAL_COUNTDOWN_SCROLL;
2040
2040
  }
2041
2041
  verifyIfFiltersMatchingAlarm() {
2042
- this.activeChildParam$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd && this.activatedRoute.children.length > 0), switchMap(() => this.activatedRoute.children[0].params), map(params => params.id), distinctUntilChanged(), shareReplay(), takeUntil(this.destroy$));
2042
+ this.activeChildParam$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd && this.activatedRoute.children.length > 0), switchMap(() => this.activatedRoute.children[0].params), map(params => params.id), distinctUntilChanged(),
2043
+ // takeUntil MUST come before shareReplay: shareReplay() (no refCount) subscribes to the
2044
+ // long-lived router.events and never unsubscribes on its own. With takeUntil downstream,
2045
+ // destroy$ only detaches consumers while shareReplay keeps the source subscription alive,
2046
+ // and its operator closures (which capture `this`) leak the whole component tree.
2047
+ takeUntil(this.destroy$), shareReplay());
2043
2048
  // done to get the first navigation
2044
2049
  this.activeChildParam$.subscribe();
2045
2050
  }
@@ -2498,7 +2503,9 @@ class AlarmsComponent {
2498
2503
  .pipe(takeUntil(this.destroy$), filter(() => !this.isListScrolled()))
2499
2504
  .subscribe(value => this.changeInterval(value));
2500
2505
  }
2501
- this.alarmsViewService.closeDetailsView$.subscribe(async () => await this.alarmsViewService.closeDetailsView(this.activatedRoute));
2506
+ this.alarmsViewService.closeDetailsView$
2507
+ .pipe(takeUntil(this.destroy$))
2508
+ .subscribe(async () => await this.alarmsViewService.closeDetailsView(this.activatedRoute));
2502
2509
  }
2503
2510
  ngOnDestroy() {
2504
2511
  this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ALARMS.EVENTS.ALARMS, {
@@ -2589,9 +2596,9 @@ class AlarmsComponent {
2589
2596
  this.isLoading$.next(true);
2590
2597
  const additionalFilter = {};
2591
2598
  if (this.contextSourceId) {
2592
- (additionalFilter.source = this.contextSourceId),
2593
- (additionalFilter.withSourceAssets = true),
2594
- (additionalFilter.withSourceDevices = true);
2599
+ additionalFilter.source = this.contextSourceId;
2600
+ additionalFilter.withSourceAssets = true;
2601
+ additionalFilter.withSourceDevices = true;
2595
2602
  }
2596
2603
  if (this.typeFilters.length > 0) {
2597
2604
  additionalFilter.type = this.typeFilters.map(({ filters }) => filters.type).join(',');