@memberjunction/ng-core-entity-forms 5.38.0 → 5.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts +10 -0
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +645 -531
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.d.ts +13 -4
- package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +374 -326
- package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +2 -3
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +1 -2
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.d.ts +24 -0
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +381 -224
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +39 -41
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +8 -9
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +71 -73
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js +3 -3
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIModelCost/mjaimodelcost.form.component.js +10 -6
- package/dist/lib/generated/Entities/MJAIModelCost/mjaimodelcost.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js +3 -3
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js +47 -39
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js +58 -24
- package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJIntegrationObjectField/mjintegrationobjectfield.form.component.js +10 -8
- package/dist/lib/generated/Entities/MJIntegrationObjectField/mjintegrationobjectfield.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJScheduledJob/mjscheduledjob.form.component.js +27 -25
- package/dist/lib/generated/Entities/MJScheduledJob/mjscheduledjob.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTagSynonym/mjtagsynonym.form.component.js +8 -6
- package/dist/lib/generated/Entities/MJTagSynonym/mjtagsynonym.form.component.js.map +1 -1
- package/package.json +36 -36
- package/dist/lib/custom/Queries/query-category-dialog.component.d.ts +0 -34
- package/dist/lib/custom/Queries/query-category-dialog.component.d.ts.map +0 -1
- package/dist/lib/custom/Queries/query-category-dialog.component.js +0 -203
- package/dist/lib/custom/Queries/query-category-dialog.component.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Component, Input, ViewChild, ChangeDetectionStrategy } from '@angular/core';
|
|
2
2
|
import { Subject } from 'rxjs';
|
|
3
3
|
import { RunView } from '@memberjunction/core';
|
|
4
|
-
import { UUIDsEqual } from '@memberjunction/global';
|
|
4
|
+
import { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';
|
|
5
5
|
import * as d3 from 'd3';
|
|
6
6
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
@@ -42,7 +42,7 @@ function AIAgentRunAnalyticsComponent_Conditional_2_Template(rf, ctx) { if (rf &
|
|
|
42
42
|
i0.ɵɵtextInterpolate(ctx_r1.error);
|
|
43
43
|
} }
|
|
44
44
|
function AIAgentRunAnalyticsComponent_Conditional_3_ng_template_2_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
-
i0.ɵɵelement(0, "i",
|
|
45
|
+
i0.ɵɵelement(0, "i", 66);
|
|
46
46
|
i0.ɵɵtext(1, " Overview ");
|
|
47
47
|
} }
|
|
48
48
|
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -63,15 +63,64 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_27_Template(rf,
|
|
|
63
63
|
i0.ɵɵadvance();
|
|
64
64
|
i0.ɵɵtextInterpolate1("", ctx_r1.actionMetrics.statusBreakdown.failed, " failed");
|
|
65
65
|
} }
|
|
66
|
-
function
|
|
66
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_40_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
i0.ɵɵelementStart(0, "span");
|
|
68
|
+
i0.ɵɵtext(1);
|
|
69
|
+
i0.ɵɵpipe(2, "number");
|
|
70
|
+
i0.ɵɵelementEnd();
|
|
71
|
+
} if (rf & 2) {
|
|
72
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
73
|
+
i0.ɵɵadvance();
|
|
74
|
+
i0.ɵɵtextInterpolate1("incl. ", i0.ɵɵpipeBind1(2, 1, ctx_r1.promptMetrics.tokenUsage.totalCacheRead + ctx_r1.promptMetrics.tokenUsage.totalCacheWrite), " cached");
|
|
75
|
+
} }
|
|
76
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
77
|
+
i0.ɵɵelementStart(0, "span");
|
|
78
|
+
i0.ɵɵtext(1);
|
|
79
|
+
i0.ɵɵelementEnd();
|
|
80
|
+
} if (rf & 2) {
|
|
81
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
82
|
+
i0.ɵɵadvance();
|
|
83
|
+
i0.ɵɵtextInterpolate2("input ", ctx_r1.formatCost(ctx_r1.inputCost), " \u00B7 output ", ctx_r1.formatCost(ctx_r1.outputCost));
|
|
84
|
+
} }
|
|
85
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
86
|
+
i0.ɵɵelementStart(0, "span", 26);
|
|
87
|
+
i0.ɵɵtext(1);
|
|
88
|
+
i0.ɵɵpipe(2, "number");
|
|
89
|
+
i0.ɵɵelementEnd();
|
|
90
|
+
} if (rf & 2) {
|
|
91
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
92
|
+
i0.ɵɵadvance();
|
|
93
|
+
i0.ɵɵtextInterpolate2("saved ", ctx_r1.formatCost(ctx_r1.cacheSavings), " (", i0.ɵɵpipeBind2(2, 2, ctx_r1.cacheSavingsPct, "1.0-0"), "%) via cache");
|
|
94
|
+
} }
|
|
95
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_55_Template(rf, ctx) { if (rf & 1) {
|
|
96
|
+
i0.ɵɵelementStart(0, "span");
|
|
97
|
+
i0.ɵɵtext(1);
|
|
98
|
+
i0.ɵɵpipe(2, "number");
|
|
99
|
+
i0.ɵɵelementEnd();
|
|
100
|
+
} if (rf & 2) {
|
|
101
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
102
|
+
i0.ɵɵadvance();
|
|
103
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.promptMetrics.tokenUsage.totalCacheWrite), " written");
|
|
104
|
+
} }
|
|
105
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_56_Template(rf, ctx) { if (rf & 1) {
|
|
106
|
+
i0.ɵɵelementStart(0, "span");
|
|
107
|
+
i0.ɵɵtext(1);
|
|
108
|
+
i0.ɵɵpipe(2, "number");
|
|
109
|
+
i0.ɵɵelementEnd();
|
|
110
|
+
} if (rf & 2) {
|
|
111
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
112
|
+
i0.ɵɵadvance();
|
|
113
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(2, 1, ctx_r1.cacheHitRatePct, "1.0-0"), "% hit rate");
|
|
114
|
+
} }
|
|
115
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_ng_template_69_Template(rf, ctx) { if (rf & 1) {
|
|
67
116
|
i0.ɵɵelement(0, "i", 22);
|
|
68
117
|
i0.ɵɵtext(1, " Prompt Analytics ");
|
|
69
118
|
} }
|
|
70
|
-
function
|
|
119
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_71_Template(rf, ctx) { if (rf & 1) {
|
|
71
120
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
72
|
-
i0.ɵɵelementStart(0, "div",
|
|
73
|
-
i0.ɵɵlistener("click", function
|
|
74
|
-
i0.ɵɵelement(2, "i",
|
|
121
|
+
i0.ɵɵelementStart(0, "div", 38)(1, "button", 43);
|
|
122
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_71_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleViewMode()); });
|
|
123
|
+
i0.ɵɵelement(2, "i", 44);
|
|
75
124
|
i0.ɵɵtext(3);
|
|
76
125
|
i0.ɵɵelementEnd()();
|
|
77
126
|
} if (rf & 2) {
|
|
@@ -81,20 +130,20 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_53_Template(rf,
|
|
|
81
130
|
i0.ɵɵadvance();
|
|
82
131
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.viewMode === "grid" ? "Expand All" : "Collapse All", " ");
|
|
83
132
|
} }
|
|
84
|
-
function
|
|
85
|
-
i0.ɵɵelementStart(0, "div",
|
|
86
|
-
i0.ɵɵelement(1, "i",
|
|
133
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_72_Template(rf, ctx) { if (rf & 1) {
|
|
134
|
+
i0.ɵɵelementStart(0, "div", 39);
|
|
135
|
+
i0.ɵɵelement(1, "i", 67);
|
|
87
136
|
i0.ɵɵelementStart(2, "p");
|
|
88
137
|
i0.ɵɵtext(3, "No prompt executions found in this agent run.");
|
|
89
138
|
i0.ɵɵelementEnd();
|
|
90
|
-
i0.ɵɵelementStart(4, "p",
|
|
139
|
+
i0.ɵɵelementStart(4, "p", 68);
|
|
91
140
|
i0.ɵɵtext(5, "This agent run may have only executed actions without any AI prompts.");
|
|
92
141
|
i0.ɵɵelementEnd()();
|
|
93
142
|
} }
|
|
94
|
-
function
|
|
95
|
-
i0.ɵɵelementStart(0, "div",
|
|
96
|
-
i0.ɵɵelement(1, "span",
|
|
97
|
-
i0.ɵɵelementStart(2, "span",
|
|
143
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Conditional_12_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
144
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
145
|
+
i0.ɵɵelement(1, "span", 78);
|
|
146
|
+
i0.ɵɵelementStart(2, "span", 79);
|
|
98
147
|
i0.ɵɵtext(3);
|
|
99
148
|
i0.ɵɵelementEnd()();
|
|
100
149
|
} if (rf & 2) {
|
|
@@ -105,9 +154,9 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_55_Conditional_1
|
|
|
105
154
|
i0.ɵɵadvance(2);
|
|
106
155
|
i0.ɵɵtextInterpolate3("", item_r6.key, ": ", item_r6.value.count, " (", (item_r6.value.count / ctx_r1.promptMetrics.totalCount * 100).toFixed(1), "%)");
|
|
107
156
|
} }
|
|
108
|
-
function
|
|
109
|
-
i0.ɵɵelementStart(0, "div",
|
|
110
|
-
i0.ɵɵrepeaterCreate(1,
|
|
157
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
158
|
+
i0.ɵɵelementStart(0, "div", 71);
|
|
159
|
+
i0.ɵɵrepeaterCreate(1, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Conditional_12_For_2_Template, 4, 5, "div", 77, i0.ɵɵcomponentInstance().trackByKey, true);
|
|
111
160
|
i0.ɵɵpipe(3, "keyvalue");
|
|
112
161
|
i0.ɵɵelementEnd();
|
|
113
162
|
} if (rf & 2) {
|
|
@@ -115,58 +164,58 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_55_Conditional_1
|
|
|
115
164
|
i0.ɵɵadvance();
|
|
116
165
|
i0.ɵɵrepeater(i0.ɵɵpipeBind1(3, 0, ctx_r1.promptMetrics.byModel));
|
|
117
166
|
} }
|
|
118
|
-
function
|
|
167
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template(rf, ctx) { if (rf & 1) {
|
|
119
168
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
120
|
-
i0.ɵɵelementStart(0, "div",
|
|
121
|
-
i0.ɵɵlistener("click", function
|
|
169
|
+
i0.ɵɵelementStart(0, "div", 40)(1, "div", 46)(2, "div", 47);
|
|
170
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template_div_click_2_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("modelDistribution")); });
|
|
122
171
|
i0.ɵɵelementStart(3, "h3");
|
|
123
|
-
i0.ɵɵelement(4, "i",
|
|
172
|
+
i0.ɵɵelement(4, "i", 69);
|
|
124
173
|
i0.ɵɵtext(5, " Prompts by Model");
|
|
125
174
|
i0.ɵɵelementEnd();
|
|
126
|
-
i0.ɵɵelementStart(6, "button",
|
|
127
|
-
i0.ɵɵelement(7, "i",
|
|
175
|
+
i0.ɵɵelementStart(6, "button", 49);
|
|
176
|
+
i0.ɵɵelement(7, "i", 44);
|
|
128
177
|
i0.ɵɵelementEnd()();
|
|
129
|
-
i0.ɵɵelementStart(8, "div",
|
|
130
|
-
i0.ɵɵelement(10, "div",
|
|
131
|
-
i0.ɵɵconditionalCreate(12,
|
|
178
|
+
i0.ɵɵelementStart(8, "div", 50)(9, "div", 51);
|
|
179
|
+
i0.ɵɵelement(10, "div", 70, 2);
|
|
180
|
+
i0.ɵɵconditionalCreate(12, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Conditional_12_Template, 4, 2, "div", 71);
|
|
132
181
|
i0.ɵɵelementEnd()()();
|
|
133
|
-
i0.ɵɵelementStart(13, "div",
|
|
134
|
-
i0.ɵɵlistener("click", function
|
|
182
|
+
i0.ɵɵelementStart(13, "div", 46)(14, "div", 47);
|
|
183
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template_div_click_14_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("executionTime")); });
|
|
135
184
|
i0.ɵɵelementStart(15, "h3");
|
|
136
|
-
i0.ɵɵelement(16, "i",
|
|
185
|
+
i0.ɵɵelement(16, "i", 36);
|
|
137
186
|
i0.ɵɵtext(17, " Average Execution Time by Vendor");
|
|
138
187
|
i0.ɵɵelementEnd();
|
|
139
|
-
i0.ɵɵelementStart(18, "button",
|
|
140
|
-
i0.ɵɵelement(19, "i",
|
|
188
|
+
i0.ɵɵelementStart(18, "button", 49);
|
|
189
|
+
i0.ɵɵelement(19, "i", 44);
|
|
141
190
|
i0.ɵɵelementEnd()();
|
|
142
|
-
i0.ɵɵelementStart(20, "div",
|
|
143
|
-
i0.ɵɵelement(22, "div",
|
|
191
|
+
i0.ɵɵelementStart(20, "div", 50)(21, "div", 51);
|
|
192
|
+
i0.ɵɵelement(22, "div", 72, 3);
|
|
144
193
|
i0.ɵɵelementEnd()()();
|
|
145
|
-
i0.ɵɵelementStart(24, "div",
|
|
146
|
-
i0.ɵɵlistener("click", function
|
|
194
|
+
i0.ɵɵelementStart(24, "div", 46)(25, "div", 47);
|
|
195
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template_div_click_25_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("costByVendor")); });
|
|
147
196
|
i0.ɵɵelementStart(26, "h3");
|
|
148
197
|
i0.ɵɵelement(27, "i", 31);
|
|
149
198
|
i0.ɵɵtext(28, " Cost Distribution by Vendor");
|
|
150
199
|
i0.ɵɵelementEnd();
|
|
151
|
-
i0.ɵɵelementStart(29, "button",
|
|
152
|
-
i0.ɵɵelement(30, "i",
|
|
200
|
+
i0.ɵɵelementStart(29, "button", 49);
|
|
201
|
+
i0.ɵɵelement(30, "i", 44);
|
|
153
202
|
i0.ɵɵelementEnd()();
|
|
154
|
-
i0.ɵɵelementStart(31, "div",
|
|
155
|
-
i0.ɵɵelement(33, "div",
|
|
156
|
-
i0.ɵɵelementStart(35, "div",
|
|
203
|
+
i0.ɵɵelementStart(31, "div", 50)(32, "div", 51);
|
|
204
|
+
i0.ɵɵelement(33, "div", 73, 4);
|
|
205
|
+
i0.ɵɵelementStart(35, "div", 74);
|
|
157
206
|
i0.ɵɵtext(36);
|
|
158
207
|
i0.ɵɵelementEnd()()()();
|
|
159
|
-
i0.ɵɵelementStart(37, "div",
|
|
160
|
-
i0.ɵɵlistener("click", function
|
|
208
|
+
i0.ɵɵelementStart(37, "div", 46)(38, "div", 47);
|
|
209
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template_div_click_38_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("tokenUsage")); });
|
|
161
210
|
i0.ɵɵelementStart(39, "h3");
|
|
162
|
-
i0.ɵɵelement(40, "i",
|
|
211
|
+
i0.ɵɵelement(40, "i", 75);
|
|
163
212
|
i0.ɵɵtext(41, " Token Usage by Model");
|
|
164
213
|
i0.ɵɵelementEnd();
|
|
165
|
-
i0.ɵɵelementStart(42, "button",
|
|
166
|
-
i0.ɵɵelement(43, "i",
|
|
214
|
+
i0.ɵɵelementStart(42, "button", 49);
|
|
215
|
+
i0.ɵɵelement(43, "i", 44);
|
|
167
216
|
i0.ɵɵelementEnd()();
|
|
168
|
-
i0.ɵɵelementStart(44, "div",
|
|
169
|
-
i0.ɵɵelement(46, "div",
|
|
217
|
+
i0.ɵɵelementStart(44, "div", 50)(45, "div", 51);
|
|
218
|
+
i0.ɵɵelement(46, "div", 76, 5);
|
|
170
219
|
i0.ɵɵelementEnd()()()();
|
|
171
220
|
} if (rf & 2) {
|
|
172
221
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -191,55 +240,55 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_55_Template(rf,
|
|
|
191
240
|
i0.ɵɵadvance(6);
|
|
192
241
|
i0.ɵɵproperty("ngClass", ctx_r1.expandedCharts["tokenUsage"] ? "fa-compress" : "fa-expand");
|
|
193
242
|
} }
|
|
194
|
-
function
|
|
243
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template(rf, ctx) { if (rf & 1) {
|
|
195
244
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
196
|
-
i0.ɵɵelementStart(0, "div",
|
|
197
|
-
i0.ɵɵlistener("click", function
|
|
245
|
+
i0.ɵɵelementStart(0, "div", 41)(1, "div", 46)(2, "div", 47);
|
|
246
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template_div_click_2_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("promptTime")); });
|
|
198
247
|
i0.ɵɵelementStart(3, "h3");
|
|
199
|
-
i0.ɵɵelement(4, "i",
|
|
248
|
+
i0.ɵɵelement(4, "i", 80);
|
|
200
249
|
i0.ɵɵtext(5, " Average Execution Time by Prompt");
|
|
201
250
|
i0.ɵɵelementEnd();
|
|
202
|
-
i0.ɵɵelementStart(6, "button",
|
|
203
|
-
i0.ɵɵelement(7, "i",
|
|
251
|
+
i0.ɵɵelementStart(6, "button", 49);
|
|
252
|
+
i0.ɵɵelement(7, "i", 44);
|
|
204
253
|
i0.ɵɵelementEnd()();
|
|
205
|
-
i0.ɵɵelementStart(8, "div",
|
|
206
|
-
i0.ɵɵelement(10, "div",
|
|
254
|
+
i0.ɵɵelementStart(8, "div", 50)(9, "div", 51);
|
|
255
|
+
i0.ɵɵelement(10, "div", 81, 6);
|
|
207
256
|
i0.ɵɵelementEnd()()();
|
|
208
|
-
i0.ɵɵelementStart(12, "div",
|
|
209
|
-
i0.ɵɵlistener("click", function
|
|
257
|
+
i0.ɵɵelementStart(12, "div", 46)(13, "div", 47);
|
|
258
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template_div_click_13_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("promptToken")); });
|
|
210
259
|
i0.ɵɵelementStart(14, "h3");
|
|
211
|
-
i0.ɵɵelement(15, "i",
|
|
260
|
+
i0.ɵɵelement(15, "i", 82);
|
|
212
261
|
i0.ɵɵtext(16, " Token Usage by Prompt");
|
|
213
262
|
i0.ɵɵelementEnd();
|
|
214
|
-
i0.ɵɵelementStart(17, "button",
|
|
215
|
-
i0.ɵɵelement(18, "i",
|
|
263
|
+
i0.ɵɵelementStart(17, "button", 49);
|
|
264
|
+
i0.ɵɵelement(18, "i", 44);
|
|
216
265
|
i0.ɵɵelementEnd()();
|
|
217
|
-
i0.ɵɵelementStart(19, "div",
|
|
218
|
-
i0.ɵɵelement(21, "div",
|
|
266
|
+
i0.ɵɵelementStart(19, "div", 50)(20, "div", 51);
|
|
267
|
+
i0.ɵɵelement(21, "div", 83, 7);
|
|
219
268
|
i0.ɵɵelementEnd()()();
|
|
220
|
-
i0.ɵɵelementStart(23, "div",
|
|
221
|
-
i0.ɵɵlistener("click", function
|
|
269
|
+
i0.ɵɵelementStart(23, "div", 46)(24, "div", 47);
|
|
270
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template_div_click_24_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("promptCost")); });
|
|
222
271
|
i0.ɵɵelementStart(25, "h3");
|
|
223
|
-
i0.ɵɵelement(26, "i",
|
|
272
|
+
i0.ɵɵelement(26, "i", 69);
|
|
224
273
|
i0.ɵɵtext(27, " Cost Distribution by Prompt");
|
|
225
274
|
i0.ɵɵelementEnd();
|
|
226
|
-
i0.ɵɵelementStart(28, "button",
|
|
227
|
-
i0.ɵɵelement(29, "i",
|
|
275
|
+
i0.ɵɵelementStart(28, "button", 49);
|
|
276
|
+
i0.ɵɵelement(29, "i", 44);
|
|
228
277
|
i0.ɵɵelementEnd()();
|
|
229
|
-
i0.ɵɵelementStart(30, "div",
|
|
230
|
-
i0.ɵɵelement(32, "div",
|
|
278
|
+
i0.ɵɵelementStart(30, "div", 50)(31, "div", 51);
|
|
279
|
+
i0.ɵɵelement(32, "div", 84, 8);
|
|
231
280
|
i0.ɵɵelementEnd()()();
|
|
232
|
-
i0.ɵɵelementStart(34, "div",
|
|
233
|
-
i0.ɵɵlistener("click", function
|
|
281
|
+
i0.ɵɵelementStart(34, "div", 46)(35, "div", 47);
|
|
282
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template_div_click_35_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("promptCount")); });
|
|
234
283
|
i0.ɵɵelementStart(36, "h3");
|
|
235
|
-
i0.ɵɵelement(37, "i",
|
|
284
|
+
i0.ɵɵelement(37, "i", 85);
|
|
236
285
|
i0.ɵɵtext(38, " Prompt Execution Count");
|
|
237
286
|
i0.ɵɵelementEnd();
|
|
238
|
-
i0.ɵɵelementStart(39, "button",
|
|
239
|
-
i0.ɵɵelement(40, "i",
|
|
287
|
+
i0.ɵɵelementStart(39, "button", 49);
|
|
288
|
+
i0.ɵɵelement(40, "i", 44);
|
|
240
289
|
i0.ɵɵelementEnd()();
|
|
241
|
-
i0.ɵɵelementStart(41, "div",
|
|
242
|
-
i0.ɵɵelement(43, "div",
|
|
290
|
+
i0.ɵɵelementStart(41, "div", 50)(42, "div", 51);
|
|
291
|
+
i0.ɵɵelement(43, "div", 86, 9);
|
|
243
292
|
i0.ɵɵelementEnd()()()();
|
|
244
293
|
} if (rf & 2) {
|
|
245
294
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -260,7 +309,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_56_Template(rf,
|
|
|
260
309
|
i0.ɵɵadvance(6);
|
|
261
310
|
i0.ɵɵproperty("ngClass", ctx_r1.expandedCharts["promptCount"] ? "fa-compress" : "fa-expand");
|
|
262
311
|
} }
|
|
263
|
-
function
|
|
312
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_79_For_16_Template(rf, ctx) { if (rf & 1) {
|
|
264
313
|
i0.ɵɵelementStart(0, "tr")(1, "td");
|
|
265
314
|
i0.ɵɵtext(2);
|
|
266
315
|
i0.ɵɵelementEnd();
|
|
@@ -273,7 +322,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_61_For_16_Templa
|
|
|
273
322
|
i0.ɵɵelementStart(7, "td");
|
|
274
323
|
i0.ɵɵtext(8);
|
|
275
324
|
i0.ɵɵelementEnd();
|
|
276
|
-
i0.ɵɵelementStart(9, "td")(10, "span",
|
|
325
|
+
i0.ɵɵelementStart(9, "td")(10, "span", 87);
|
|
277
326
|
i0.ɵɵtext(11);
|
|
278
327
|
i0.ɵɵelementEnd()()();
|
|
279
328
|
} if (rf & 2) {
|
|
@@ -290,8 +339,8 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_61_For_16_Templa
|
|
|
290
339
|
i0.ɵɵadvance(3);
|
|
291
340
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.calculatePromptSuccessRate(prompt_r8.key), "% ");
|
|
292
341
|
} }
|
|
293
|
-
function
|
|
294
|
-
i0.ɵɵelementStart(0, "div",
|
|
342
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_79_Template(rf, ctx) { if (rf & 1) {
|
|
343
|
+
i0.ɵɵelementStart(0, "div", 45)(1, "table")(2, "thead")(3, "tr")(4, "th");
|
|
295
344
|
i0.ɵɵtext(5, "Prompt Name");
|
|
296
345
|
i0.ɵɵelementEnd();
|
|
297
346
|
i0.ɵɵelementStart(6, "th");
|
|
@@ -307,7 +356,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_61_Template(rf,
|
|
|
307
356
|
i0.ɵɵtext(13, "Success Rate");
|
|
308
357
|
i0.ɵɵelementEnd()()();
|
|
309
358
|
i0.ɵɵelementStart(14, "tbody");
|
|
310
|
-
i0.ɵɵrepeaterCreate(15,
|
|
359
|
+
i0.ɵɵrepeaterCreate(15, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_79_For_16_Template, 12, 5, "tr", null, i0.ɵɵcomponentInstance().trackByKey, true);
|
|
311
360
|
i0.ɵɵpipe(17, "keyvalue");
|
|
312
361
|
i0.ɵɵelementEnd()()();
|
|
313
362
|
} if (rf & 2) {
|
|
@@ -315,11 +364,11 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_61_Template(rf,
|
|
|
315
364
|
i0.ɵɵadvance(15);
|
|
316
365
|
i0.ɵɵrepeater(i0.ɵɵpipeBind1(17, 0, ctx_r1.promptMetrics.byPrompt));
|
|
317
366
|
} }
|
|
318
|
-
function
|
|
367
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_ng_template_81_Template(rf, ctx) { if (rf & 1) {
|
|
319
368
|
i0.ɵɵelement(0, "i", 29);
|
|
320
369
|
i0.ɵɵtext(1, " Action Analytics ");
|
|
321
370
|
} }
|
|
322
|
-
function
|
|
371
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_110_For_16_Template(rf, ctx) { if (rf & 1) {
|
|
323
372
|
i0.ɵɵelementStart(0, "tr")(1, "td");
|
|
324
373
|
i0.ɵɵtext(2);
|
|
325
374
|
i0.ɵɵelementEnd();
|
|
@@ -329,7 +378,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_92_For_16_Templa
|
|
|
329
378
|
i0.ɵɵelementStart(5, "td");
|
|
330
379
|
i0.ɵɵtext(6);
|
|
331
380
|
i0.ɵɵelementEnd();
|
|
332
|
-
i0.ɵɵelementStart(7, "td")(8, "span",
|
|
381
|
+
i0.ɵɵelementStart(7, "td")(8, "span", 87);
|
|
333
382
|
i0.ɵɵtext(9);
|
|
334
383
|
i0.ɵɵelementEnd()();
|
|
335
384
|
i0.ɵɵelementStart(10, "td");
|
|
@@ -351,8 +400,8 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_92_For_16_Templa
|
|
|
351
400
|
i0.ɵɵadvance(2);
|
|
352
401
|
i0.ɵɵtextInterpolate(ctx_r1.getActionType(action_r9.key));
|
|
353
402
|
} }
|
|
354
|
-
function
|
|
355
|
-
i0.ɵɵelementStart(0, "div",
|
|
403
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_110_Template(rf, ctx) { if (rf & 1) {
|
|
404
|
+
i0.ɵɵelementStart(0, "div", 45)(1, "table")(2, "thead")(3, "tr")(4, "th");
|
|
356
405
|
i0.ɵɵtext(5, "Action Name");
|
|
357
406
|
i0.ɵɵelementEnd();
|
|
358
407
|
i0.ɵɵelementStart(6, "th");
|
|
@@ -368,7 +417,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_92_Template(rf,
|
|
|
368
417
|
i0.ɵɵtext(13, "Type");
|
|
369
418
|
i0.ɵɵelementEnd()()();
|
|
370
419
|
i0.ɵɵelementStart(14, "tbody");
|
|
371
|
-
i0.ɵɵrepeaterCreate(15,
|
|
420
|
+
i0.ɵɵrepeaterCreate(15, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_110_For_16_Template, 12, 11, "tr", null, i0.ɵɵcomponentInstance().trackByKey, true);
|
|
372
421
|
i0.ɵɵpipe(17, "keyvalue");
|
|
373
422
|
i0.ɵɵelementEnd()()();
|
|
374
423
|
} if (rf & 2) {
|
|
@@ -376,11 +425,11 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_92_Template(rf,
|
|
|
376
425
|
i0.ɵɵadvance(15);
|
|
377
426
|
i0.ɵɵrepeater(i0.ɵɵpipeBind1(17, 0, ctx_r1.actionMetrics.byAction));
|
|
378
427
|
} }
|
|
379
|
-
function
|
|
380
|
-
i0.ɵɵelementStart(0, "div",
|
|
428
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_112_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
429
|
+
i0.ɵɵelementStart(0, "div", 91)(1, "span", 92);
|
|
381
430
|
i0.ɵɵtext(2);
|
|
382
431
|
i0.ɵɵelementEnd();
|
|
383
|
-
i0.ɵɵelementStart(3, "span",
|
|
432
|
+
i0.ɵɵelementStart(3, "span", 93);
|
|
384
433
|
i0.ɵɵtext(4);
|
|
385
434
|
i0.ɵɵelementEnd()();
|
|
386
435
|
} if (rf & 2) {
|
|
@@ -390,34 +439,34 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_94_For_8_Templat
|
|
|
390
439
|
i0.ɵɵadvance(2);
|
|
391
440
|
i0.ɵɵtextInterpolate(error_r10.message);
|
|
392
441
|
} }
|
|
393
|
-
function
|
|
394
|
-
i0.ɵɵelementStart(0, "div",
|
|
395
|
-
i0.ɵɵelement(2, "i",
|
|
442
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_112_Template(rf, ctx) { if (rf & 1) {
|
|
443
|
+
i0.ɵɵelementStart(0, "div", 56)(1, "h3");
|
|
444
|
+
i0.ɵɵelement(2, "i", 88);
|
|
396
445
|
i0.ɵɵtext(3, " Common Errors ");
|
|
397
446
|
i0.ɵɵelementEnd();
|
|
398
|
-
i0.ɵɵelementStart(4, "p",
|
|
447
|
+
i0.ɵɵelementStart(4, "p", 89);
|
|
399
448
|
i0.ɵɵtext(5, " This section shows the most frequent error messages from failed actions, helping identify systemic issues that may need attention. ");
|
|
400
449
|
i0.ɵɵelementEnd();
|
|
401
|
-
i0.ɵɵelementStart(6, "div",
|
|
402
|
-
i0.ɵɵrepeaterCreate(7,
|
|
450
|
+
i0.ɵɵelementStart(6, "div", 90);
|
|
451
|
+
i0.ɵɵrepeaterCreate(7, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_112_For_8_Template, 5, 2, "div", 91, i0.ɵɵcomponentInstance().trackByErrorMessage, true);
|
|
403
452
|
i0.ɵɵelementEnd()();
|
|
404
453
|
} if (rf & 2) {
|
|
405
454
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
406
455
|
i0.ɵɵadvance(7);
|
|
407
456
|
i0.ɵɵrepeater(ctx_r1.getTopErrors());
|
|
408
457
|
} }
|
|
409
|
-
function
|
|
410
|
-
i0.ɵɵelementStart(0, "div",
|
|
411
|
-
i0.ɵɵelement(1, "i",
|
|
458
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_Conditional_113_Template(rf, ctx) { if (rf & 1) {
|
|
459
|
+
i0.ɵɵelementStart(0, "div", 57);
|
|
460
|
+
i0.ɵɵelement(1, "i", 94);
|
|
412
461
|
i0.ɵɵelementStart(2, "p");
|
|
413
462
|
i0.ɵɵtext(3, "No action errors detected in this run. All actions completed successfully!");
|
|
414
463
|
i0.ɵɵelementEnd()();
|
|
415
464
|
} }
|
|
416
|
-
function
|
|
417
|
-
i0.ɵɵelement(0, "i",
|
|
465
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_ng_template_115_Template(rf, ctx) { if (rf & 1) {
|
|
466
|
+
i0.ɵɵelement(0, "i", 95);
|
|
418
467
|
i0.ɵɵtext(1, " Model Performance Comparison ");
|
|
419
468
|
} }
|
|
420
|
-
function
|
|
469
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_For_139_Template(rf, ctx) { if (rf & 1) {
|
|
421
470
|
i0.ɵɵelementStart(0, "tr")(1, "td");
|
|
422
471
|
i0.ɵɵtext(2);
|
|
423
472
|
i0.ɵɵelementEnd();
|
|
@@ -464,20 +513,20 @@ function AIAgentRunAnalyticsComponent_Conditional_3_For_121_Template(rf, ctx) {
|
|
|
464
513
|
i0.ɵɵadvance(3);
|
|
465
514
|
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(18, 11, model_r11.outputTokens, "1.0-0"));
|
|
466
515
|
} }
|
|
467
|
-
function
|
|
468
|
-
i0.ɵɵelement(0, "i",
|
|
516
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_ng_template_141_Template(rf, ctx) { if (rf & 1) {
|
|
517
|
+
i0.ɵɵelement(0, "i", 96);
|
|
469
518
|
i0.ɵɵtext(1, " Execution Timeline Analysis ");
|
|
470
519
|
} }
|
|
471
|
-
function
|
|
472
|
-
i0.ɵɵelementStart(0, "div",
|
|
473
|
-
i0.ɵɵelement(1, "i",
|
|
474
|
-
i0.ɵɵelementStart(2, "span",
|
|
520
|
+
function AIAgentRunAnalyticsComponent_Conditional_3_For_169_Template(rf, ctx) { if (rf & 1) {
|
|
521
|
+
i0.ɵɵelementStart(0, "div", 65);
|
|
522
|
+
i0.ɵɵelement(1, "i", 44);
|
|
523
|
+
i0.ɵɵelementStart(2, "span", 97);
|
|
475
524
|
i0.ɵɵtext(3);
|
|
476
525
|
i0.ɵɵelementEnd();
|
|
477
|
-
i0.ɵɵelementStart(4, "span",
|
|
526
|
+
i0.ɵɵelementStart(4, "span", 98);
|
|
478
527
|
i0.ɵɵtext(5);
|
|
479
528
|
i0.ɵɵelementEnd();
|
|
480
|
-
i0.ɵɵelementStart(6, "span",
|
|
529
|
+
i0.ɵɵelementStart(6, "span", 99);
|
|
481
530
|
i0.ɵɵtext(7);
|
|
482
531
|
i0.ɵɵelementEnd()();
|
|
483
532
|
} if (rf & 2) {
|
|
@@ -533,133 +582,154 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
533
582
|
i0.ɵɵelementStart(34, "div", 24);
|
|
534
583
|
i0.ɵɵtext(35);
|
|
535
584
|
i0.ɵɵelementEnd();
|
|
536
|
-
i0.ɵɵelementStart(36, "div",
|
|
585
|
+
i0.ɵɵelementStart(36, "div", 32)(37, "span");
|
|
537
586
|
i0.ɵɵtext(38);
|
|
538
|
-
i0.ɵɵ
|
|
539
|
-
i0.ɵɵ
|
|
540
|
-
i0.ɵɵ
|
|
587
|
+
i0.ɵɵpipe(39, "number");
|
|
588
|
+
i0.ɵɵelementEnd();
|
|
589
|
+
i0.ɵɵconditionalCreate(40, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_40_Template, 3, 3, "span");
|
|
590
|
+
i0.ɵɵconditionalCreate(41, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_41_Template, 2, 2, "span");
|
|
591
|
+
i0.ɵɵconditionalCreate(42, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_42_Template, 3, 5, "span", 26);
|
|
592
|
+
i0.ɵɵelementEnd()()();
|
|
593
|
+
i0.ɵɵelementStart(43, "div", 20)(44, "div", 33);
|
|
594
|
+
i0.ɵɵelement(45, "i", 34);
|
|
595
|
+
i0.ɵɵelementEnd();
|
|
596
|
+
i0.ɵɵelementStart(46, "div", 23)(47, "h3");
|
|
597
|
+
i0.ɵɵtext(48, "Prompt Cache");
|
|
598
|
+
i0.ɵɵelementEnd();
|
|
599
|
+
i0.ɵɵelementStart(49, "div", 24);
|
|
600
|
+
i0.ɵɵtext(50);
|
|
601
|
+
i0.ɵɵpipe(51, "number");
|
|
541
602
|
i0.ɵɵelementEnd();
|
|
542
|
-
i0.ɵɵelementStart(
|
|
543
|
-
i0.ɵɵtext(
|
|
603
|
+
i0.ɵɵelementStart(52, "div", 32)(53, "span");
|
|
604
|
+
i0.ɵɵtext(54, "tokens read from cache");
|
|
544
605
|
i0.ɵɵelementEnd();
|
|
545
|
-
i0.ɵɵ
|
|
546
|
-
i0.ɵɵ
|
|
606
|
+
i0.ɵɵconditionalCreate(55, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_55_Template, 3, 3, "span");
|
|
607
|
+
i0.ɵɵconditionalCreate(56, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_56_Template, 3, 4, "span");
|
|
608
|
+
i0.ɵɵelementEnd()()();
|
|
609
|
+
i0.ɵɵelementStart(57, "div", 20)(58, "div", 35);
|
|
610
|
+
i0.ɵɵelement(59, "i", 36);
|
|
611
|
+
i0.ɵɵelementEnd();
|
|
612
|
+
i0.ɵɵelementStart(60, "div", 23)(61, "h3");
|
|
613
|
+
i0.ɵɵtext(62, "Execution Time");
|
|
547
614
|
i0.ɵɵelementEnd();
|
|
548
|
-
i0.ɵɵelementStart(
|
|
549
|
-
i0.ɵɵtext(
|
|
615
|
+
i0.ɵɵelementStart(63, "div", 24);
|
|
616
|
+
i0.ɵɵtext(64);
|
|
617
|
+
i0.ɵɵelementEnd();
|
|
618
|
+
i0.ɵɵelementStart(65, "div", 25)(66, "span");
|
|
619
|
+
i0.ɵɵtext(67);
|
|
550
620
|
i0.ɵɵelementEnd()()()()()();
|
|
551
|
-
i0.ɵɵelementStart(
|
|
552
|
-
i0.ɵɵtemplate(
|
|
553
|
-
i0.ɵɵelementStart(
|
|
554
|
-
i0.ɵɵconditionalCreate(
|
|
555
|
-
i0.ɵɵconditionalCreate(
|
|
556
|
-
i0.ɵɵconditionalCreate(
|
|
557
|
-
i0.ɵɵconditionalCreate(
|
|
558
|
-
i0.ɵɵelementStart(
|
|
559
|
-
i0.ɵɵlistener("click", function
|
|
560
|
-
i0.ɵɵelement(
|
|
561
|
-
i0.ɵɵtext(
|
|
562
|
-
i0.ɵɵelementEnd();
|
|
563
|
-
i0.ɵɵconditionalCreate(
|
|
621
|
+
i0.ɵɵelementStart(68, "mj-accordion-panel", 17);
|
|
622
|
+
i0.ɵɵtemplate(69, AIAgentRunAnalyticsComponent_Conditional_3_ng_template_69_Template, 2, 0, "ng-template", 18);
|
|
623
|
+
i0.ɵɵelementStart(70, "div", 37);
|
|
624
|
+
i0.ɵɵconditionalCreate(71, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_71_Template, 4, 2, "div", 38);
|
|
625
|
+
i0.ɵɵconditionalCreate(72, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_72_Template, 6, 0, "div", 39);
|
|
626
|
+
i0.ɵɵconditionalCreate(73, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_73_Template, 48, 14, "div", 40);
|
|
627
|
+
i0.ɵɵconditionalCreate(74, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_74_Template, 45, 12, "div", 41);
|
|
628
|
+
i0.ɵɵelementStart(75, "div", 42)(76, "button", 43);
|
|
629
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Template_button_click_76_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.promptDetailsExpanded = !ctx_r1.promptDetailsExpanded); });
|
|
630
|
+
i0.ɵɵelement(77, "i", 44);
|
|
631
|
+
i0.ɵɵtext(78, " Detailed Prompt Metrics ");
|
|
632
|
+
i0.ɵɵelementEnd();
|
|
633
|
+
i0.ɵɵconditionalCreate(79, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_79_Template, 18, 2, "div", 45);
|
|
564
634
|
i0.ɵɵelementEnd()()();
|
|
565
|
-
i0.ɵɵelementStart(
|
|
566
|
-
i0.ɵɵtemplate(
|
|
567
|
-
i0.ɵɵelementStart(
|
|
568
|
-
i0.ɵɵlistener("click", function
|
|
569
|
-
i0.ɵɵelementStart(
|
|
570
|
-
i0.ɵɵelement(
|
|
571
|
-
i0.ɵɵtext(
|
|
572
|
-
i0.ɵɵelementEnd();
|
|
573
|
-
i0.ɵɵelementStart(
|
|
574
|
-
i0.ɵɵelement(
|
|
635
|
+
i0.ɵɵelementStart(80, "mj-accordion-panel", 17);
|
|
636
|
+
i0.ɵɵtemplate(81, AIAgentRunAnalyticsComponent_Conditional_3_ng_template_81_Template, 2, 0, "ng-template", 18);
|
|
637
|
+
i0.ɵɵelementStart(82, "div", 37)(83, "div", 40)(84, "div", 46)(85, "div", 47);
|
|
638
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Template_div_click_85_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("actionSuccess")); });
|
|
639
|
+
i0.ɵɵelementStart(86, "h3");
|
|
640
|
+
i0.ɵɵelement(87, "i", 48);
|
|
641
|
+
i0.ɵɵtext(88, " Action Success Rate");
|
|
642
|
+
i0.ɵɵelementEnd();
|
|
643
|
+
i0.ɵɵelementStart(89, "button", 49);
|
|
644
|
+
i0.ɵɵelement(90, "i", 44);
|
|
575
645
|
i0.ɵɵelementEnd()();
|
|
576
|
-
i0.ɵɵelementStart(
|
|
577
|
-
i0.ɵɵelement(
|
|
646
|
+
i0.ɵɵelementStart(91, "div", 50)(92, "div", 51);
|
|
647
|
+
i0.ɵɵelement(93, "div", 52, 0);
|
|
578
648
|
i0.ɵɵelementEnd()()();
|
|
579
|
-
i0.ɵɵelementStart(
|
|
580
|
-
i0.ɵɵlistener("click", function
|
|
581
|
-
i0.ɵɵelementStart(
|
|
582
|
-
i0.ɵɵelement(
|
|
583
|
-
i0.ɵɵtext(
|
|
584
|
-
i0.ɵɵelementEnd();
|
|
585
|
-
i0.ɵɵelementStart(
|
|
586
|
-
i0.ɵɵelement(
|
|
649
|
+
i0.ɵɵelementStart(95, "div", 46)(96, "div", 47);
|
|
650
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Template_div_click_96_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleChartExpansion("stepType")); });
|
|
651
|
+
i0.ɵɵelementStart(97, "h3");
|
|
652
|
+
i0.ɵɵelement(98, "i", 53);
|
|
653
|
+
i0.ɵɵtext(99, " Step Type Distribution");
|
|
654
|
+
i0.ɵɵelementEnd();
|
|
655
|
+
i0.ɵɵelementStart(100, "button", 49);
|
|
656
|
+
i0.ɵɵelement(101, "i", 44);
|
|
587
657
|
i0.ɵɵelementEnd()();
|
|
588
|
-
i0.ɵɵelementStart(
|
|
589
|
-
i0.ɵɵelement(
|
|
658
|
+
i0.ɵɵelementStart(102, "div", 50)(103, "div", 51);
|
|
659
|
+
i0.ɵɵelement(104, "div", 54, 1);
|
|
590
660
|
i0.ɵɵelementEnd()()()();
|
|
591
|
-
i0.ɵɵelementStart(
|
|
592
|
-
i0.ɵɵlistener("click", function
|
|
593
|
-
i0.ɵɵelement(
|
|
594
|
-
i0.ɵɵtext(
|
|
661
|
+
i0.ɵɵelementStart(106, "div", 42)(107, "button", 43);
|
|
662
|
+
i0.ɵɵlistener("click", function AIAgentRunAnalyticsComponent_Conditional_3_Template_button_click_107_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.actionDetailsExpanded = !ctx_r1.actionDetailsExpanded); });
|
|
663
|
+
i0.ɵɵelement(108, "i", 44);
|
|
664
|
+
i0.ɵɵtext(109, " Detailed Action Metrics ");
|
|
595
665
|
i0.ɵɵelementEnd();
|
|
596
|
-
i0.ɵɵconditionalCreate(
|
|
666
|
+
i0.ɵɵconditionalCreate(110, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_110_Template, 18, 2, "div", 45);
|
|
597
667
|
i0.ɵɵelementEnd();
|
|
598
|
-
i0.ɵɵelementStart(
|
|
599
|
-
i0.ɵɵconditionalCreate(
|
|
600
|
-
i0.ɵɵconditionalCreate(
|
|
668
|
+
i0.ɵɵelementStart(111, "div", 55);
|
|
669
|
+
i0.ɵɵconditionalCreate(112, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_112_Template, 9, 0, "div", 56);
|
|
670
|
+
i0.ɵɵconditionalCreate(113, AIAgentRunAnalyticsComponent_Conditional_3_Conditional_113_Template, 4, 0, "div", 57);
|
|
601
671
|
i0.ɵɵelementEnd()()();
|
|
602
|
-
i0.ɵɵelementStart(
|
|
603
|
-
i0.ɵɵtemplate(
|
|
604
|
-
i0.ɵɵelementStart(
|
|
605
|
-
i0.ɵɵtext(
|
|
672
|
+
i0.ɵɵelementStart(114, "mj-accordion-panel", 17);
|
|
673
|
+
i0.ɵɵtemplate(115, AIAgentRunAnalyticsComponent_Conditional_3_ng_template_115_Template, 2, 0, "ng-template", 18);
|
|
674
|
+
i0.ɵɵelementStart(116, "div", 37)(117, "div", 58)(118, "table")(119, "thead")(120, "tr")(121, "th");
|
|
675
|
+
i0.ɵɵtext(122, "Model");
|
|
606
676
|
i0.ɵɵelementEnd();
|
|
607
|
-
i0.ɵɵelementStart(
|
|
608
|
-
i0.ɵɵtext(
|
|
677
|
+
i0.ɵɵelementStart(123, "th");
|
|
678
|
+
i0.ɵɵtext(124, "Vendor");
|
|
609
679
|
i0.ɵɵelementEnd();
|
|
610
|
-
i0.ɵɵelementStart(
|
|
611
|
-
i0.ɵɵtext(
|
|
680
|
+
i0.ɵɵelementStart(125, "th");
|
|
681
|
+
i0.ɵɵtext(126, "Prompts");
|
|
612
682
|
i0.ɵɵelementEnd();
|
|
613
|
-
i0.ɵɵelementStart(
|
|
614
|
-
i0.ɵɵtext(
|
|
683
|
+
i0.ɵɵelementStart(127, "th");
|
|
684
|
+
i0.ɵɵtext(128, "Avg Time");
|
|
615
685
|
i0.ɵɵelementEnd();
|
|
616
|
-
i0.ɵɵelementStart(
|
|
617
|
-
i0.ɵɵtext(
|
|
686
|
+
i0.ɵɵelementStart(129, "th");
|
|
687
|
+
i0.ɵɵtext(130, "Total Cost");
|
|
618
688
|
i0.ɵɵelementEnd();
|
|
619
|
-
i0.ɵɵelementStart(
|
|
620
|
-
i0.ɵɵtext(
|
|
689
|
+
i0.ɵɵelementStart(131, "th");
|
|
690
|
+
i0.ɵɵtext(132, "Avg Cost/Prompt");
|
|
621
691
|
i0.ɵɵelementEnd();
|
|
622
|
-
i0.ɵɵelementStart(
|
|
623
|
-
i0.ɵɵtext(
|
|
692
|
+
i0.ɵɵelementStart(133, "th");
|
|
693
|
+
i0.ɵɵtext(134, "Input Tokens");
|
|
624
694
|
i0.ɵɵelementEnd();
|
|
625
|
-
i0.ɵɵelementStart(
|
|
626
|
-
i0.ɵɵtext(
|
|
695
|
+
i0.ɵɵelementStart(135, "th");
|
|
696
|
+
i0.ɵɵtext(136, "Output Tokens");
|
|
627
697
|
i0.ɵɵelementEnd()()();
|
|
628
|
-
i0.ɵɵelementStart(
|
|
629
|
-
i0.ɵɵrepeaterCreate(
|
|
698
|
+
i0.ɵɵelementStart(137, "tbody");
|
|
699
|
+
i0.ɵɵrepeaterCreate(138, AIAgentRunAnalyticsComponent_Conditional_3_For_139_Template, 19, 14, "tr", null, i0.ɵɵcomponentInstance().trackByModelName, true);
|
|
630
700
|
i0.ɵɵelementEnd()()()()();
|
|
631
|
-
i0.ɵɵelementStart(
|
|
632
|
-
i0.ɵɵtemplate(
|
|
633
|
-
i0.ɵɵelementStart(
|
|
634
|
-
i0.ɵɵtext(
|
|
701
|
+
i0.ɵɵelementStart(140, "mj-accordion-panel", 17);
|
|
702
|
+
i0.ɵɵtemplate(141, AIAgentRunAnalyticsComponent_Conditional_3_ng_template_141_Template, 2, 0, "ng-template", 18);
|
|
703
|
+
i0.ɵɵelementStart(142, "div", 37)(143, "div", 59)(144, "div", 60)(145, "span", 61);
|
|
704
|
+
i0.ɵɵtext(146, "Total Steps");
|
|
635
705
|
i0.ɵɵelementEnd();
|
|
636
|
-
i0.ɵɵelementStart(
|
|
637
|
-
i0.ɵɵtext(
|
|
706
|
+
i0.ɵɵelementStart(147, "span", 62);
|
|
707
|
+
i0.ɵɵtext(148);
|
|
638
708
|
i0.ɵɵelementEnd()();
|
|
639
|
-
i0.ɵɵelementStart(
|
|
640
|
-
i0.ɵɵtext(
|
|
709
|
+
i0.ɵɵelementStart(149, "div", 60)(150, "span", 61);
|
|
710
|
+
i0.ɵɵtext(151, "Parallel Executions");
|
|
641
711
|
i0.ɵɵelementEnd();
|
|
642
|
-
i0.ɵɵelementStart(
|
|
643
|
-
i0.ɵɵtext(
|
|
712
|
+
i0.ɵɵelementStart(152, "span", 62);
|
|
713
|
+
i0.ɵɵtext(153);
|
|
644
714
|
i0.ɵɵelementEnd()();
|
|
645
|
-
i0.ɵɵelementStart(
|
|
646
|
-
i0.ɵɵtext(
|
|
715
|
+
i0.ɵɵelementStart(154, "div", 60)(155, "span", 61);
|
|
716
|
+
i0.ɵɵtext(156, "Max Nesting Depth");
|
|
647
717
|
i0.ɵɵelementEnd();
|
|
648
|
-
i0.ɵɵelementStart(
|
|
649
|
-
i0.ɵɵtext(
|
|
718
|
+
i0.ɵɵelementStart(157, "span", 62);
|
|
719
|
+
i0.ɵɵtext(158);
|
|
650
720
|
i0.ɵɵelementEnd()();
|
|
651
|
-
i0.ɵɵelementStart(
|
|
652
|
-
i0.ɵɵtext(
|
|
721
|
+
i0.ɵɵelementStart(159, "div", 60)(160, "span", 61);
|
|
722
|
+
i0.ɵɵtext(161, "Sub-Agent Runs");
|
|
653
723
|
i0.ɵɵelementEnd();
|
|
654
|
-
i0.ɵɵelementStart(
|
|
655
|
-
i0.ɵɵtext(
|
|
724
|
+
i0.ɵɵelementStart(162, "span", 62);
|
|
725
|
+
i0.ɵɵtext(163);
|
|
656
726
|
i0.ɵɵelementEnd()()();
|
|
657
|
-
i0.ɵɵelementStart(
|
|
658
|
-
i0.ɵɵtext(
|
|
727
|
+
i0.ɵɵelementStart(164, "div", 63)(165, "h3");
|
|
728
|
+
i0.ɵɵtext(166, "Steps by Type");
|
|
659
729
|
i0.ɵɵelementEnd();
|
|
660
|
-
i0.ɵɵelementStart(
|
|
661
|
-
i0.ɵɵrepeaterCreate(
|
|
662
|
-
i0.ɵɵpipe(
|
|
730
|
+
i0.ɵɵelementStart(167, "div", 64);
|
|
731
|
+
i0.ɵɵrepeaterCreate(168, AIAgentRunAnalyticsComponent_Conditional_3_For_169_Template, 8, 4, "div", 65, i0.ɵɵcomponentInstance().trackByKey, true);
|
|
732
|
+
i0.ɵɵpipe(170, "keyvalue");
|
|
663
733
|
i0.ɵɵelementEnd()()()()();
|
|
664
734
|
} if (rf & 2) {
|
|
665
735
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -680,7 +750,19 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
680
750
|
i0.ɵɵadvance(8);
|
|
681
751
|
i0.ɵɵtextInterpolate(ctx_r1.formatCost(ctx_r1.promptMetrics.costBreakdown.totalCost));
|
|
682
752
|
i0.ɵɵadvance(3);
|
|
683
|
-
i0.ɵɵtextInterpolate1("",
|
|
753
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(39, 41, ctx_r1.totalTokensProcessed), " tokens");
|
|
754
|
+
i0.ɵɵadvance(2);
|
|
755
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.tokenUsage.totalCacheRead > 0 || ctx_r1.promptMetrics.tokenUsage.totalCacheWrite > 0 ? 40 : -1);
|
|
756
|
+
i0.ɵɵadvance();
|
|
757
|
+
i0.ɵɵconditional(ctx_r1.inputCost > 0 || ctx_r1.outputCost > 0 ? 41 : -1);
|
|
758
|
+
i0.ɵɵadvance();
|
|
759
|
+
i0.ɵɵconditional(ctx_r1.cacheSavings > 0 ? 42 : -1);
|
|
760
|
+
i0.ɵɵadvance(8);
|
|
761
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(51, 43, ctx_r1.promptMetrics.tokenUsage.totalCacheRead));
|
|
762
|
+
i0.ɵɵadvance(5);
|
|
763
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.tokenUsage.totalCacheWrite > 0 ? 55 : -1);
|
|
764
|
+
i0.ɵɵadvance();
|
|
765
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.tokenUsage.totalCacheRead > 0 || ctx_r1.promptMetrics.tokenUsage.totalCacheWrite > 0 ? 56 : -1);
|
|
684
766
|
i0.ɵɵadvance(8);
|
|
685
767
|
i0.ɵɵtextInterpolate(ctx_r1.formatDuration(ctx_r1.promptMetrics.totalExecutionTime + ctx_r1.actionMetrics.totalExecutionTime));
|
|
686
768
|
i0.ɵɵadvance(3);
|
|
@@ -688,17 +770,17 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
688
770
|
i0.ɵɵadvance();
|
|
689
771
|
i0.ɵɵproperty("Expanded", true);
|
|
690
772
|
i0.ɵɵadvance(3);
|
|
691
|
-
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ?
|
|
773
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ? 71 : -1);
|
|
692
774
|
i0.ɵɵadvance();
|
|
693
|
-
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount === 0 ?
|
|
775
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount === 0 ? 72 : -1);
|
|
694
776
|
i0.ɵɵadvance();
|
|
695
|
-
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ?
|
|
777
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ? 73 : -1);
|
|
696
778
|
i0.ɵɵadvance();
|
|
697
|
-
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ?
|
|
779
|
+
i0.ɵɵconditional(ctx_r1.promptMetrics.totalCount > 0 ? 74 : -1);
|
|
698
780
|
i0.ɵɵadvance(3);
|
|
699
781
|
i0.ɵɵproperty("ngClass", ctx_r1.promptDetailsExpanded ? "fa-chevron-up" : "fa-chevron-down");
|
|
700
782
|
i0.ɵɵadvance(2);
|
|
701
|
-
i0.ɵɵconditional(ctx_r1.promptDetailsExpanded ?
|
|
783
|
+
i0.ɵɵconditional(ctx_r1.promptDetailsExpanded ? 79 : -1);
|
|
702
784
|
i0.ɵɵadvance();
|
|
703
785
|
i0.ɵɵproperty("Expanded", true);
|
|
704
786
|
i0.ɵɵadvance(4);
|
|
@@ -712,11 +794,11 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
712
794
|
i0.ɵɵadvance(7);
|
|
713
795
|
i0.ɵɵproperty("ngClass", ctx_r1.actionDetailsExpanded ? "fa-chevron-up" : "fa-chevron-down");
|
|
714
796
|
i0.ɵɵadvance(2);
|
|
715
|
-
i0.ɵɵconditional(ctx_r1.actionDetailsExpanded ?
|
|
797
|
+
i0.ɵɵconditional(ctx_r1.actionDetailsExpanded ? 110 : -1);
|
|
716
798
|
i0.ɵɵadvance(2);
|
|
717
|
-
i0.ɵɵconditional(ctx_r1.actionMetrics.errorAnalysis.size > 0 ?
|
|
799
|
+
i0.ɵɵconditional(ctx_r1.actionMetrics.errorAnalysis.size > 0 ? 112 : -1);
|
|
718
800
|
i0.ɵɵadvance();
|
|
719
|
-
i0.ɵɵconditional(ctx_r1.actionMetrics.errorAnalysis.size === 0 ?
|
|
801
|
+
i0.ɵɵconditional(ctx_r1.actionMetrics.errorAnalysis.size === 0 ? 113 : -1);
|
|
720
802
|
i0.ɵɵadvance();
|
|
721
803
|
i0.ɵɵproperty("Expanded", true);
|
|
722
804
|
i0.ɵɵadvance(24);
|
|
@@ -732,7 +814,7 @@ function AIAgentRunAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf &
|
|
|
732
814
|
i0.ɵɵadvance(5);
|
|
733
815
|
i0.ɵɵtextInterpolate(ctx_r1.subAgentRuns.length);
|
|
734
816
|
i0.ɵɵadvance(5);
|
|
735
|
-
i0.ɵɵrepeater(i0.ɵɵpipeBind1(
|
|
817
|
+
i0.ɵɵrepeater(i0.ɵɵpipeBind1(170, 45, ctx_r1.timelineMetrics.stepsByType));
|
|
736
818
|
} }
|
|
737
819
|
export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
738
820
|
/** Helper method to create tracked setTimeout calls */
|
|
@@ -752,6 +834,9 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
752
834
|
this.activeTimeouts.splice(index, 1);
|
|
753
835
|
}
|
|
754
836
|
}
|
|
837
|
+
static { this.UNIT_DIVISORS = {
|
|
838
|
+
'Per Million Tokens': 1_000_000, 'Per Hundred Thousand Tokens': 100_000, 'Per Thousand Tokens': 1_000
|
|
839
|
+
}; }
|
|
755
840
|
constructor(cdr, costService) {
|
|
756
841
|
super();
|
|
757
842
|
this.cdr = cdr;
|
|
@@ -779,6 +864,8 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
779
864
|
// Data
|
|
780
865
|
this.agentRun = null;
|
|
781
866
|
this.allPromptRuns = [];
|
|
867
|
+
// Per model+vendor cache pricing (currency-per-token), loaded from AIModelCost for the cost split.
|
|
868
|
+
this.cacheRates = new Map();
|
|
782
869
|
this.allActionLogs = [];
|
|
783
870
|
this.allSteps = [];
|
|
784
871
|
this.subAgentRuns = [];
|
|
@@ -942,6 +1029,8 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
942
1029
|
}
|
|
943
1030
|
// Load all prompt runs for the agent run hierarchy
|
|
944
1031
|
this.allPromptRuns = await this.loadAllPromptRuns(agentRunIds);
|
|
1032
|
+
// Load cache pricing so cost can be split (input/output) and cache savings computed
|
|
1033
|
+
await this.loadCacheRates();
|
|
945
1034
|
if (results[2].Success) {
|
|
946
1035
|
const actionSteps = results[2].Results || [];
|
|
947
1036
|
// Now load the actual action logs
|
|
@@ -973,8 +1062,8 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
973
1062
|
byVendor: new Map(),
|
|
974
1063
|
byPrompt: new Map(),
|
|
975
1064
|
statusBreakdown: { success: 0, failed: 0, timeout: 0 },
|
|
976
|
-
costBreakdown: { totalCost: 0, byModel: new Map(), byVendor: new Map() },
|
|
977
|
-
tokenUsage: { totalInput: 0, totalOutput: 0, byModel: new Map() }
|
|
1065
|
+
costBreakdown: { totalCost: 0, byModel: new Map(), byVendor: new Map(), inputCost: 0, outputCost: 0, savings: 0, unratedCost: 0 },
|
|
1066
|
+
tokenUsage: { totalInput: 0, totalOutput: 0, totalCacheRead: 0, totalCacheWrite: 0, byModel: new Map() }
|
|
978
1067
|
};
|
|
979
1068
|
}
|
|
980
1069
|
initializeActionMetrics() {
|
|
@@ -997,6 +1086,33 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
997
1086
|
criticalPath: { steps: [], totalTime: 0 }
|
|
998
1087
|
};
|
|
999
1088
|
}
|
|
1089
|
+
/** Stable rate-map key for a model+vendor pair. */
|
|
1090
|
+
rateKey(modelID, vendorID) {
|
|
1091
|
+
return `${NormalizeUUID(modelID ?? '')}|${NormalizeUUID(vendorID ?? '')}`;
|
|
1092
|
+
}
|
|
1093
|
+
/** Load active realtime AIModelCost rates and normalize each to currency-per-token. */
|
|
1094
|
+
async loadCacheRates() {
|
|
1095
|
+
this.cacheRates.clear();
|
|
1096
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
1097
|
+
const res = await rv.RunView({
|
|
1098
|
+
EntityName: 'MJ: AI Model Costs',
|
|
1099
|
+
ExtraFilter: `Status='Active' AND ProcessingType='Realtime'`,
|
|
1100
|
+
Fields: ['ModelID', 'VendorID', 'InputPricePerUnit', 'OutputPricePerUnit', 'CacheReadPricePerUnit', 'CacheWritePricePerUnit', 'UnitType'],
|
|
1101
|
+
ResultType: 'simple'
|
|
1102
|
+
});
|
|
1103
|
+
if (!res.Success)
|
|
1104
|
+
return;
|
|
1105
|
+
for (const row of res.Results || []) {
|
|
1106
|
+
const divisor = AIAgentRunAnalyticsComponent.UNIT_DIVISORS[row.UnitType ?? ''] ?? 1_000_000;
|
|
1107
|
+
const input = (row.InputPricePerUnit ?? 0) / divisor;
|
|
1108
|
+
this.cacheRates.set(this.rateKey(row.ModelID, row.VendorID), {
|
|
1109
|
+
inputRate: input,
|
|
1110
|
+
outputRate: (row.OutputPricePerUnit ?? 0) / divisor,
|
|
1111
|
+
cacheReadRate: (row.CacheReadPricePerUnit ?? row.InputPricePerUnit ?? 0) / divisor,
|
|
1112
|
+
cacheWriteRate: (row.CacheWritePricePerUnit ?? row.InputPricePerUnit ?? 0) / divisor
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1000
1116
|
calculatePromptMetrics() {
|
|
1001
1117
|
const metrics = this.initializePromptMetrics();
|
|
1002
1118
|
for (const promptRun of this.allPromptRuns) {
|
|
@@ -1047,6 +1163,24 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
1047
1163
|
const outputTokens = promptRun.TokensCompletion || 0;
|
|
1048
1164
|
metrics.tokenUsage.totalInput += inputTokens;
|
|
1049
1165
|
metrics.tokenUsage.totalOutput += outputTokens;
|
|
1166
|
+
// Provider prompt-cache tokens (read = cache hits, write = cache creation). Summed from the
|
|
1167
|
+
// child prompt runs' persisted TokensCacheRead/TokensCacheWrite columns.
|
|
1168
|
+
const cacheReadTokens = promptRun.TokensCacheRead || 0;
|
|
1169
|
+
const cacheWriteTokens = promptRun.TokensCacheWrite || 0;
|
|
1170
|
+
metrics.tokenUsage.totalCacheRead += cacheReadTokens;
|
|
1171
|
+
metrics.tokenUsage.totalCacheWrite += cacheWriteTokens;
|
|
1172
|
+
// Rate-derived cost split + cache savings. inputCost folds uncached + cache read + cache write
|
|
1173
|
+
// (each at its own rate); savings = the discount vs. pricing all input at the full input rate.
|
|
1174
|
+
// Runs whose model+vendor has no rate row are tracked separately so the split isn't silently off.
|
|
1175
|
+
const rate = this.cacheRates.get(this.rateKey(promptRun.ModelID, promptRun.VendorID));
|
|
1176
|
+
if (rate) {
|
|
1177
|
+
metrics.costBreakdown.inputCost += inputTokens * rate.inputRate + cacheReadTokens * rate.cacheReadRate + cacheWriteTokens * rate.cacheWriteRate;
|
|
1178
|
+
metrics.costBreakdown.outputCost += outputTokens * rate.outputRate;
|
|
1179
|
+
metrics.costBreakdown.savings += cacheReadTokens * (rate.inputRate - rate.cacheReadRate) + cacheWriteTokens * (rate.inputRate - rate.cacheWriteRate);
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
metrics.costBreakdown.unratedCost += cost;
|
|
1183
|
+
}
|
|
1050
1184
|
const modelTokens = metrics.tokenUsage.byModel.get(model) || { input: 0, output: 0 };
|
|
1051
1185
|
modelTokens.input += inputTokens;
|
|
1052
1186
|
modelTokens.output += outputTokens;
|
|
@@ -1229,6 +1363,29 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
1229
1363
|
return `$${cost.toFixed(3)}`;
|
|
1230
1364
|
return `$${cost.toFixed(2)}`;
|
|
1231
1365
|
}
|
|
1366
|
+
/** Total tokens the models processed across this run, including cached input (true throughput). */
|
|
1367
|
+
get totalTokensProcessed() {
|
|
1368
|
+
const u = this.promptMetrics.tokenUsage;
|
|
1369
|
+
return u.totalInput + u.totalOutput + u.totalCacheRead + u.totalCacheWrite;
|
|
1370
|
+
}
|
|
1371
|
+
/** Rate-derived input-side dollars (uncached + cache read + cache write). */
|
|
1372
|
+
get inputCost() { return this.promptMetrics.costBreakdown.inputCost; }
|
|
1373
|
+
/** Rate-derived output dollars. */
|
|
1374
|
+
get outputCost() { return this.promptMetrics.costBreakdown.outputCost; }
|
|
1375
|
+
/** Net dollars saved by caching vs. pricing all input at the full input rate. */
|
|
1376
|
+
get cacheSavings() { return this.promptMetrics.costBreakdown.savings; }
|
|
1377
|
+
/** Savings as a % of what the run would have cost with no caching. */
|
|
1378
|
+
get cacheSavingsPct() {
|
|
1379
|
+
const cb = this.promptMetrics.costBreakdown;
|
|
1380
|
+
const fullPrice = cb.totalCost + cb.savings;
|
|
1381
|
+
return fullPrice > 0 ? (cb.savings / fullPrice) * 100 : 0;
|
|
1382
|
+
}
|
|
1383
|
+
/** Percentage of input tokens served from the provider's prompt cache across this agent run. */
|
|
1384
|
+
get cacheHitRatePct() {
|
|
1385
|
+
const u = this.promptMetrics.tokenUsage;
|
|
1386
|
+
const totalInput = u.totalInput + u.totalCacheRead + u.totalCacheWrite;
|
|
1387
|
+
return totalInput > 0 ? (u.totalCacheRead / totalInput) * 100 : 0;
|
|
1388
|
+
}
|
|
1232
1389
|
refresh() {
|
|
1233
1390
|
this.loadData();
|
|
1234
1391
|
}
|
|
@@ -2130,11 +2287,11 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
2130
2287
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.promptTokenDistributionChart = _t.first);
|
|
2131
2288
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.promptCostDistributionChart = _t.first);
|
|
2132
2289
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.promptCountByNameChart = _t.first);
|
|
2133
|
-
} }, inputs: { agentRunId: "agentRunId" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 3, consts: [["actionSuccessRateChart", ""], ["stepTypeChart", ""], ["modelDistributionChart", ""], ["executionTimeChart", ""], ["costByVendorChart", ""], ["tokenUsageChart", ""], ["promptTimeDistributionChart", ""], ["promptTokenDistributionChart", ""], ["promptCostDistributionChart", ""], ["promptCountByNameChart", ""], [1, "analytics-container"], [1, "loading-state"], [1, "error-state"], [1, "analytics-content"], [1, "fas", "fa-spinner", "fa-spin", "fa-2x"], [1, "fas", "fa-exclamation-triangle", "fa-2x"], ["mjButton", "", 3, "click"], [3, "Expanded"], ["mjAccordionTitle", ""], [1, "summary-cards"], [1, "summary-card"], [1, "card-icon", "prompts"], [1, "fas", "fa-microchip"], [1, "card-content"], [1, "metric-value"], [1, "metric-detail"], [1, "success"], [1, "failed"], [1, "card-icon", "actions"], [1, "fas", "fa-cog"], [1, "card-icon", "cost"], [1, "fas", "fa-dollar-sign"], [1, "card-icon", "time"], [1, "fas", "fa-clock"], [1, "analytics-panel"], [1, "view-mode-toggle"], [1, "no-data-message"], [1, "charts-grid"], [1, "charts-grid", 2, "margin-top", "20px"], [1, "detailed-metrics"], ["mjButton", "", "variant", "flat", 3, "click"], [1, "fas", 3, "ngClass"], [1, "metrics-table"], [1, "chart-card"], [1, "chart-card-header", 3, "click"], [1, "fas", "fa-chart-bar"], [1, "expand-btn"], [1, "chart-card-body"], [1, "chart-container"], ["id", "actionSuccessRateChart"], [1, "fas", "fa-layer-group"], ["id", "stepTypeChart"], [1, "error-analysis-section"], [1, "error-analysis"], [1, "no-errors"], [1, "model-comparison"], [1, "timeline-stats"], [1, "stat-item"], [1, "stat-label"], [1, "stat-value"], [1, "step-breakdown"], [1, "step-type-list"], [1, "step-type-item"], [1, "fas", "fa-tachometer-alt"], [1, "fas", "fa-info-circle"], [1, "small"], [1, "fas", "fa-chart-pie"], ["id", "modelDistributionChart"], [1, "chart-legend"], ["id", "executionTimeChart"], ["id", "costByVendorChart"], [1, "chart-total"], [1, "fas", "fa-coins"], ["id", "tokenUsageChart"], [1, "legend-item"], [1, "legend-color"], [1, "legend-label"], [1, "fas", "fa-hourglass-half"], ["id", "promptTimeDistributionChart"], [1, "fas", "fa-database"], ["id", "promptTokenDistributionChart"], ["id", "promptCostDistributionChart"], [1, "fas", "fa-list-ol"], ["id", "promptCountByNameChart"], [1, "success-rate"], [1, "fas", "fa-exclamation-triangle"], [1, "error-analysis-description"], [1, "error-list"], [1, "error-item"], [1, "error-count"], [1, "error-message"], [1, "fas", "fa-check-circle"], [1, "fas", "fa-chart-line"], [1, "fas", "fa-stream"], [1, "type-name"], [1, "type-count"], [1, "type-percentage"]], template: function AIAgentRunAnalyticsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2290
|
+
} }, inputs: { agentRunId: "agentRunId" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 3, consts: [["actionSuccessRateChart", ""], ["stepTypeChart", ""], ["modelDistributionChart", ""], ["executionTimeChart", ""], ["costByVendorChart", ""], ["tokenUsageChart", ""], ["promptTimeDistributionChart", ""], ["promptTokenDistributionChart", ""], ["promptCostDistributionChart", ""], ["promptCountByNameChart", ""], [1, "analytics-container"], [1, "loading-state"], [1, "error-state"], [1, "analytics-content"], [1, "fas", "fa-spinner", "fa-spin", "fa-2x"], [1, "fas", "fa-exclamation-triangle", "fa-2x"], ["mjButton", "", 3, "click"], [3, "Expanded"], ["mjAccordionTitle", ""], [1, "summary-cards"], [1, "summary-card"], [1, "card-icon", "prompts"], [1, "fas", "fa-microchip"], [1, "card-content"], [1, "metric-value"], [1, "metric-detail"], [1, "success"], [1, "failed"], [1, "card-icon", "actions"], [1, "fas", "fa-cog"], [1, "card-icon", "cost"], [1, "fas", "fa-dollar-sign"], [1, "metric-detail", "cache-detail"], [1, "card-icon", "cache"], [1, "fas", "fa-bolt"], [1, "card-icon", "time"], [1, "fas", "fa-clock"], [1, "analytics-panel"], [1, "view-mode-toggle"], [1, "no-data-message"], [1, "charts-grid"], [1, "charts-grid", 2, "margin-top", "20px"], [1, "detailed-metrics"], ["mjButton", "", "variant", "flat", 3, "click"], [1, "fas", 3, "ngClass"], [1, "metrics-table"], [1, "chart-card"], [1, "chart-card-header", 3, "click"], [1, "fas", "fa-chart-bar"], [1, "expand-btn"], [1, "chart-card-body"], [1, "chart-container"], ["id", "actionSuccessRateChart"], [1, "fas", "fa-layer-group"], ["id", "stepTypeChart"], [1, "error-analysis-section"], [1, "error-analysis"], [1, "no-errors"], [1, "model-comparison"], [1, "timeline-stats"], [1, "stat-item"], [1, "stat-label"], [1, "stat-value"], [1, "step-breakdown"], [1, "step-type-list"], [1, "step-type-item"], [1, "fas", "fa-tachometer-alt"], [1, "fas", "fa-info-circle"], [1, "small"], [1, "fas", "fa-chart-pie"], ["id", "modelDistributionChart"], [1, "chart-legend"], ["id", "executionTimeChart"], ["id", "costByVendorChart"], [1, "chart-total"], [1, "fas", "fa-coins"], ["id", "tokenUsageChart"], [1, "legend-item"], [1, "legend-color"], [1, "legend-label"], [1, "fas", "fa-hourglass-half"], ["id", "promptTimeDistributionChart"], [1, "fas", "fa-database"], ["id", "promptTokenDistributionChart"], ["id", "promptCostDistributionChart"], [1, "fas", "fa-list-ol"], ["id", "promptCountByNameChart"], [1, "success-rate"], [1, "fas", "fa-exclamation-triangle"], [1, "error-analysis-description"], [1, "error-list"], [1, "error-item"], [1, "error-count"], [1, "error-message"], [1, "fas", "fa-check-circle"], [1, "fas", "fa-chart-line"], [1, "fas", "fa-stream"], [1, "type-name"], [1, "type-count"], [1, "type-percentage"]], template: function AIAgentRunAnalyticsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2134
2291
|
i0.ɵɵelementStart(0, "div", 10);
|
|
2135
2292
|
i0.ɵɵconditionalCreate(1, AIAgentRunAnalyticsComponent_Conditional_1_Template, 4, 0, "div", 11);
|
|
2136
2293
|
i0.ɵɵconditionalCreate(2, AIAgentRunAnalyticsComponent_Conditional_2_Template, 6, 1, "div", 12);
|
|
2137
|
-
i0.ɵɵconditionalCreate(3, AIAgentRunAnalyticsComponent_Conditional_3_Template,
|
|
2294
|
+
i0.ɵɵconditionalCreate(3, AIAgentRunAnalyticsComponent_Conditional_3_Template, 171, 47, "div", 13);
|
|
2138
2295
|
i0.ɵɵelementEnd();
|
|
2139
2296
|
} if (rf & 2) {
|
|
2140
2297
|
i0.ɵɵadvance();
|
|
@@ -2143,11 +2300,11 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
2143
2300
|
i0.ɵɵconditional(ctx.error && !ctx.isLoading ? 2 : -1);
|
|
2144
2301
|
i0.ɵɵadvance();
|
|
2145
2302
|
i0.ɵɵconditional(!ctx.isLoading && !ctx.error ? 3 : -1);
|
|
2146
|
-
} }, dependencies: [i2.NgClass, i3.MJButtonDirective, i3.MJAccordionPanelComponent, i3.MJAccordionTitleDirective, i2.DecimalPipe, i2.KeyValuePipe], styles: [".analytics-container[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background-color: var(--mj-bg-surface-sunken);\n}\n\n\n\n.loading-state[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 300px;\n color: var(--mj-text-muted);\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-bottom: 15px;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.summary-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.summary-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.summary-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\n}\n\n.card-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 20px;\n font-size: 24px;\n color: var(--mj-text-inverse);\n}\n\n.card-icon.prompts[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.card-icon.actions[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.card-icon.cost[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.card-icon.time[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.card-content[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.metric-detail[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.metric-detail[_ngcontent-%COMP%] .success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n margin-right: 10px;\n}\n\n.metric-detail[_ngcontent-%COMP%] .failed[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.analytics-panel[_ngcontent-%COMP%] {\n padding: 15px;\n}\n\n\n\n.analytics-content[_ngcontent-%COMP%] mj-accordion-panel[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 12px;\n}\n\n\n\n.charts-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));\n gap: 20px;\n margin-bottom: 20px;\n}\n\n\n\n.chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n transition: all 0.3s ease;\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.chart-card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.chart-card-header[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.chart-card-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.chart-card-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-text-muted);\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.chart-card-body[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] .chart-card-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] .chart-container[_ngcontent-%COMP%] > div[_ngcontent-%COMP%] {\n min-height: 400px;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n margin-bottom: 16px;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.chart-container[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.chart-container[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 10px 0;\n font-size: 15px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.chart-container[_ngcontent-%COMP%] > div[_ngcontent-%COMP%] {\n min-height: 220px;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n\n\n.chart-container[_ngcontent-%COMP%] svg[_ngcontent-%COMP%] {\n display: block;\n margin: 0 auto;\n}\n\n.chart-legend[_ngcontent-%COMP%] {\n margin-top: 10px;\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n}\n\n.legend-color[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n border-radius: 3px;\n}\n\n.chart-total[_ngcontent-%COMP%] {\n text-align: center;\n margin-top: 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n\n\n.detailed-metrics[_ngcontent-%COMP%] {\n margin-top: 20px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 20px;\n}\n\n.detailed-metrics[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n margin-bottom: 15px;\n}\n\n.detailed-metrics[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.metrics-table[_ngcontent-%COMP%] {\n overflow-x: auto;\n}\n\n.metrics-table[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n}\n\n.metrics-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n}\n\n.metrics-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.metrics-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.success-rate[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.success-rate.high[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.success-rate.medium[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.success-rate.low[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.error-analysis[_ngcontent-%COMP%] {\n margin-top: 30px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.error-analysis[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 15px 0;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-analysis-description[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n.error-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.error-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px;\n background-color: var(--mj-bg-surface);\n border-radius: 4px;\n font-size: 14px;\n}\n\n.error-count[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.error-message[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n\n\n.no-errors[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.no-errors[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n color: var(--mj-status-success);\n}\n\n.no-errors[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.no-data-message[_ngcontent-%COMP%] {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.no-data-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 20px;\n color: var(--mj-border-strong);\n}\n\n.no-data-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 10px 0;\n font-size: 16px;\n}\n\n.no-data-message[_ngcontent-%COMP%] p.small[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-disabled);\n}\n\n\n\n.model-comparison[_ngcontent-%COMP%] {\n overflow-x: auto;\n}\n\n.model-comparison[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n}\n\n.model-comparison[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n white-space: nowrap;\n}\n\n.model-comparison[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.model-comparison[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n\n\n.timeline-stats[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 20px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n}\n\n.stat-label[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.stat-value[_ngcontent-%COMP%] {\n font-size: 32px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.step-breakdown[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 15px 0;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.step-type-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 12px;\n}\n\n.step-type-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n border: 1px solid var(--mj-border-default);\n}\n\n.step-type-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 30px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.type-name[_ngcontent-%COMP%] {\n flex: 1;\n font-weight: 500;\n}\n\n.type-count[_ngcontent-%COMP%] {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.type-percentage[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: 5px;\n}\n\n\n\n@media (max-width: 768px) {\n .summary-cards[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .charts-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .timeline-stats[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n}"], changeDetection: 0 }); }
|
|
2303
|
+
} }, dependencies: [i2.NgClass, i3.MJButtonDirective, i3.MJAccordionPanelComponent, i3.MJAccordionTitleDirective, i2.DecimalPipe, i2.KeyValuePipe], styles: [".analytics-container[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background-color: var(--mj-bg-surface-sunken);\n}\n\n\n\n.loading-state[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 300px;\n color: var(--mj-text-muted);\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-bottom: 15px;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.summary-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.summary-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.summary-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\n}\n\n.card-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 20px;\n font-size: 24px;\n color: var(--mj-text-inverse);\n}\n\n.card-icon.prompts[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.card-icon.actions[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.card-icon.cost[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.card-icon.time[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.card-icon.cache[_ngcontent-%COMP%] {\n background: var(--mj-status-info);\n}\n\n.card-content[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.metric-detail[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.metric-detail[_ngcontent-%COMP%] .success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n margin-right: 10px;\n}\n\n.metric-detail[_ngcontent-%COMP%] .failed[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.metric-detail.cache-detail[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: block;\n}\n\n\n\n.analytics-panel[_ngcontent-%COMP%] {\n padding: 15px;\n}\n\n\n\n.analytics-content[_ngcontent-%COMP%] mj-accordion-panel[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 12px;\n}\n\n\n\n.charts-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));\n gap: 20px;\n margin-bottom: 20px;\n}\n\n\n\n.chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n transition: all 0.3s ease;\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.chart-card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.chart-card-header[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.chart-card-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.chart-card-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-text-muted);\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.chart-card-body[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] .chart-card-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n.chart-card.expanded[_ngcontent-%COMP%] .chart-container[_ngcontent-%COMP%] > div[_ngcontent-%COMP%] {\n min-height: 400px;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n margin-bottom: 16px;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.chart-container[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.chart-container[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 10px 0;\n font-size: 15px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.chart-container[_ngcontent-%COMP%] > div[_ngcontent-%COMP%] {\n min-height: 220px;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n\n\n.chart-container[_ngcontent-%COMP%] svg[_ngcontent-%COMP%] {\n display: block;\n margin: 0 auto;\n}\n\n.chart-legend[_ngcontent-%COMP%] {\n margin-top: 10px;\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n}\n\n.legend-color[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n border-radius: 3px;\n}\n\n.chart-total[_ngcontent-%COMP%] {\n text-align: center;\n margin-top: 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n\n\n.detailed-metrics[_ngcontent-%COMP%] {\n margin-top: 20px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 20px;\n}\n\n.detailed-metrics[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n margin-bottom: 15px;\n}\n\n.detailed-metrics[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.metrics-table[_ngcontent-%COMP%] {\n overflow-x: auto;\n}\n\n.metrics-table[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n}\n\n.metrics-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n}\n\n.metrics-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.metrics-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.success-rate[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.success-rate.high[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.success-rate.medium[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.success-rate.low[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.error-analysis[_ngcontent-%COMP%] {\n margin-top: 30px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.error-analysis[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 15px 0;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-analysis-description[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n.error-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.error-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px;\n background-color: var(--mj-bg-surface);\n border-radius: 4px;\n font-size: 14px;\n}\n\n.error-count[_ngcontent-%COMP%] {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.error-message[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n\n\n.no-errors[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.no-errors[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n color: var(--mj-status-success);\n}\n\n.no-errors[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.no-data-message[_ngcontent-%COMP%] {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.no-data-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 20px;\n color: var(--mj-border-strong);\n}\n\n.no-data-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 10px 0;\n font-size: 16px;\n}\n\n.no-data-message[_ngcontent-%COMP%] p.small[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-disabled);\n}\n\n\n\n.model-comparison[_ngcontent-%COMP%] {\n overflow-x: auto;\n}\n\n.model-comparison[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n}\n\n.model-comparison[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n white-space: nowrap;\n}\n\n.model-comparison[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.model-comparison[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n\n\n.timeline-stats[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 20px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n}\n\n.stat-label[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.stat-value[_ngcontent-%COMP%] {\n font-size: 32px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.step-breakdown[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 15px 0;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.step-type-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 12px;\n}\n\n.step-type-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n border: 1px solid var(--mj-border-default);\n}\n\n.step-type-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 30px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.type-name[_ngcontent-%COMP%] {\n flex: 1;\n font-weight: 500;\n}\n\n.type-count[_ngcontent-%COMP%] {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.type-percentage[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: 5px;\n}\n\n\n\n@media (max-width: 768px) {\n .summary-cards[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .charts-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .timeline-stats[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n}"], changeDetection: 0 }); }
|
|
2147
2304
|
}
|
|
2148
2305
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AIAgentRunAnalyticsComponent, [{
|
|
2149
2306
|
type: Component,
|
|
2150
|
-
args: [{ standalone: false, selector: 'mj-ai-agent-run-analytics', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"analytics-container\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <i class=\"fas fa-spinner fa-spin fa-2x\"></i>\n <p>Loading analytics data...</p>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle fa-2x\"></i>\n <p>{{ error }}</p>\n <button mjButton (click)=\"loadData()\">Retry</button>\n </div>\n }\n\n <!-- Analytics Content -->\n @if (!isLoading && !error) {\n <div class=\"analytics-content\">\n <!-- Summary Cards -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-tachometer-alt\"></i> Overview\n </ng-template>\n <div class=\"summary-cards\">\n <div class=\"summary-card\">\n <div class=\"card-icon prompts\">\n <i class=\"fas fa-microchip\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Prompts</h3>\n <div class=\"metric-value\">{{ promptMetrics.totalCount }}</div>\n <div class=\"metric-detail\">\n <span class=\"success\">{{ promptMetrics.statusBreakdown.success }} successful</span>\n @if (promptMetrics.statusBreakdown.failed > 0) {\n <span class=\"failed\">{{ promptMetrics.statusBreakdown.failed }} failed</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon actions\">\n <i class=\"fas fa-cog\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Actions</h3>\n <div class=\"metric-value\">{{ actionMetrics.totalCount }}</div>\n <div class=\"metric-detail\">\n <span class=\"success\">{{ actionMetrics.statusBreakdown.success }} successful</span>\n @if (actionMetrics.statusBreakdown.failed > 0) {\n <span class=\"failed\">{{ actionMetrics.statusBreakdown.failed }} failed</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon cost\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Cost</h3>\n <div class=\"metric-value\">{{ formatCost(promptMetrics.costBreakdown.totalCost) }}</div>\n <div class=\"metric-detail\">\n <span>{{ promptMetrics.tokenUsage.totalInput + promptMetrics.tokenUsage.totalOutput }} tokens</span>\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon time\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Execution Time</h3>\n <div class=\"metric-value\">{{ formatDuration(promptMetrics.totalExecutionTime + actionMetrics.totalExecutionTime) }}</div>\n <div class=\"metric-detail\">\n <span>{{ timelineMetrics.totalSteps }} total steps</span>\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Prompt Analytics -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-microchip\"></i> Prompt Analytics\n </ng-template>\n <div class=\"analytics-panel\">\n <!-- View Mode Toggle -->\n @if (promptMetrics.totalCount > 0) {\n <div class=\"view-mode-toggle\">\n <button mjButton\n variant=\"flat\"\n (click)=\"toggleViewMode()\">\n <i class=\"fas\" [ngClass]=\"viewMode === 'grid' ? 'fa-expand-arrows-alt' : 'fa-compress-arrows-alt'\"></i>\n {{ viewMode === 'grid' ? 'Expand All' : 'Collapse All' }}\n </button>\n </div>\n }\n <!-- No prompts message -->\n @if (promptMetrics.totalCount === 0) {\n <div class=\"no-data-message\">\n <i class=\"fas fa-info-circle\"></i>\n <p>No prompt executions found in this agent run.</p>\n <p class=\"small\">This agent run may have only executed actions without any AI prompts.</p>\n </div>\n }\n @if (promptMetrics.totalCount > 0) {\n <div class=\"charts-grid\">\n <!-- Model Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['modelDistribution']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('modelDistribution')\">\n <h3><i class=\"fas fa-chart-pie\"></i> Prompts by Model</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['modelDistribution'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"modelDistributionChart\" #modelDistributionChart></div>\n @if (promptMetrics.byModel.size > 0) {\n <div class=\"chart-legend\">\n @for (item of promptMetrics.byModel | keyvalue; track trackByKey($index, item)) {\n <div class=\"legend-item\">\n <span class=\"legend-color\" [style.backgroundColor]=\"getModelColor(item.key)\"></span>\n <span class=\"legend-label\">{{ item.key }}: {{ item.value.count }} ({{ (item.value.count / promptMetrics.totalCount * 100).toFixed(1) }}%)</span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Execution Time by Vendor -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['executionTime']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('executionTime')\">\n <h3><i class=\"fas fa-clock\"></i> Average Execution Time by Vendor</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['executionTime'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"executionTimeChart\" #executionTimeChart></div>\n </div>\n </div>\n </div>\n <!-- Cost by Vendor -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['costByVendor']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('costByVendor')\">\n <h3><i class=\"fas fa-dollar-sign\"></i> Cost Distribution by Vendor</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['costByVendor'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"costByVendorChart\" #costByVendorChart></div>\n <div class=\"chart-total\">Total: {{ formatCost(promptMetrics.costBreakdown.totalCost) }}</div>\n </div>\n </div>\n </div>\n <!-- Token Usage -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['tokenUsage']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('tokenUsage')\">\n <h3><i class=\"fas fa-coins\"></i> Token Usage by Model</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['tokenUsage'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"tokenUsageChart\" #tokenUsageChart></div>\n </div>\n </div>\n </div>\n </div>\n }\n <!-- Additional Prompt Analytics Charts -->\n @if (promptMetrics.totalCount > 0) {\n <div class=\"charts-grid\" style=\"margin-top: 20px;\">\n <!-- Prompt Execution Time Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptTime']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptTime')\">\n <h3><i class=\"fas fa-hourglass-half\"></i> Average Execution Time by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptTime'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptTimeDistributionChart\" #promptTimeDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Token Usage -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptToken']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptToken')\">\n <h3><i class=\"fas fa-database\"></i> Token Usage by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptToken'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptTokenDistributionChart\" #promptTokenDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Cost Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptCost']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptCost')\">\n <h3><i class=\"fas fa-chart-pie\"></i> Cost Distribution by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptCost'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptCostDistributionChart\" #promptCostDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Count by Name -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptCount']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptCount')\">\n <h3><i class=\"fas fa-list-ol\"></i> Prompt Execution Count</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptCount'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptCountByNameChart\" #promptCountByNameChart></div>\n </div>\n </div>\n </div>\n </div>\n }\n <!-- Detailed Prompt Metrics -->\n <div class=\"detailed-metrics\">\n <button mjButton\n variant=\"flat\"\n (click)=\"promptDetailsExpanded = !promptDetailsExpanded\">\n <i class=\"fas\" [ngClass]=\"promptDetailsExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n Detailed Prompt Metrics\n </button>\n @if (promptDetailsExpanded) {\n <div class=\"metrics-table\">\n <table>\n <thead>\n <tr>\n <th>Prompt Name</th>\n <th>Count</th>\n <th>Avg Time</th>\n <th>Total Time</th>\n <th>Success Rate</th>\n </tr>\n </thead>\n <tbody>\n @for (prompt of promptMetrics.byPrompt | keyvalue; track trackByKey($index, prompt)) {\n <tr>\n <td>{{ prompt.key }}</td>\n <td>{{ prompt.value.count }}</td>\n <td>{{ formatDuration(prompt.value.avgTime) }}</td>\n <td>{{ formatDuration(prompt.value.totalTime) }}</td>\n <td>\n <span class=\"success-rate\">\n <!-- Calculate success rate for this prompt -->\n {{ calculatePromptSuccessRate(prompt.key) }}%\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Action Analytics -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-cog\"></i> Action Analytics\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"charts-grid\">\n <!-- Action Success Rate -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['actionSuccess']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('actionSuccess')\">\n <h3><i class=\"fas fa-chart-bar\"></i> Action Success Rate</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['actionSuccess'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"actionSuccessRateChart\" #actionSuccessRateChart></div>\n </div>\n </div>\n </div>\n <!-- Step Type Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['stepType']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('stepType')\">\n <h3><i class=\"fas fa-layer-group\"></i> Step Type Distribution</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['stepType'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"stepTypeChart\" #stepTypeChart></div>\n </div>\n </div>\n </div>\n </div>\n <!-- Detailed Action Metrics -->\n <div class=\"detailed-metrics\">\n <button mjButton\n variant=\"flat\"\n (click)=\"actionDetailsExpanded = !actionDetailsExpanded\">\n <i class=\"fas\" [ngClass]=\"actionDetailsExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n Detailed Action Metrics\n </button>\n @if (actionDetailsExpanded) {\n <div class=\"metrics-table\">\n <table>\n <thead>\n <tr>\n <th>Action Name</th>\n <th>Count</th>\n <th>Avg Time</th>\n <th>Success Rate</th>\n <th>Type</th>\n </tr>\n </thead>\n <tbody>\n @for (action of actionMetrics.byAction | keyvalue; track trackByKey($index, action)) {\n <tr>\n <td>{{ action.key }}</td>\n <td>{{ action.value.count }}</td>\n <td>{{ formatDuration(action.value.avgTime) }}</td>\n <td>\n <span class=\"success-rate\" [class.high]=\"action.value.successRate > 0.9\"\n [class.medium]=\"action.value.successRate > 0.7 && action.value.successRate <= 0.9\"\n [class.low]=\"action.value.successRate <= 0.7\">\n {{ (action.value.successRate * 100).toFixed(1) }}%\n </span>\n </td>\n <td>{{ getActionType(action.key) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n <!-- Error Analysis -->\n <div class=\"error-analysis-section\">\n @if (actionMetrics.errorAnalysis.size > 0) {\n <div class=\"error-analysis\">\n <h3>\n <i class=\"fas fa-exclamation-triangle\"></i>\n Common Errors\n </h3>\n <p class=\"error-analysis-description\">\n This section shows the most frequent error messages from failed actions, helping identify systemic issues that may need attention.\n </p>\n <div class=\"error-list\">\n @for (error of getTopErrors(); track trackByErrorMessage($index, error)) {\n <div class=\"error-item\">\n <span class=\"error-count\">{{ error.count }}x</span>\n <span class=\"error-message\">{{ error.message }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (actionMetrics.errorAnalysis.size === 0) {\n <div class=\"no-errors\">\n <i class=\"fas fa-check-circle\"></i>\n <p>No action errors detected in this run. All actions completed successfully!</p>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Model Performance Comparison -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-chart-line\"></i> Model Performance Comparison\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"model-comparison\">\n <table>\n <thead>\n <tr>\n <th>Model</th>\n <th>Vendor</th>\n <th>Prompts</th>\n <th>Avg Time</th>\n <th>Total Cost</th>\n <th>Avg Cost/Prompt</th>\n <th>Input Tokens</th>\n <th>Output Tokens</th>\n </tr>\n </thead>\n <tbody>\n @for (model of getModelPerformanceData(); track trackByModelName($index, model)) {\n <tr>\n <td>{{ model.name }}</td>\n <td>{{ model.vendor }}</td>\n <td>{{ model.count }}</td>\n <td>{{ formatDuration(model.avgTime) }}</td>\n <td>{{ formatCost(model.totalCost) }}</td>\n <td>{{ formatCost(model.avgCost) }}</td>\n <td>{{ model.inputTokens | number:'1.0-0' }}</td>\n <td>{{ model.outputTokens | number:'1.0-0' }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Timeline Analysis -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-stream\"></i> Execution Timeline Analysis\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"timeline-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Total Steps</span>\n <span class=\"stat-value\">{{ timelineMetrics.totalSteps }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Parallel Executions</span>\n <span class=\"stat-value\">{{ timelineMetrics.parallelExecutions }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Max Nesting Depth</span>\n <span class=\"stat-value\">{{ timelineMetrics.deepestNesting }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Sub-Agent Runs</span>\n <span class=\"stat-value\">{{ subAgentRuns.length }}</span>\n </div>\n </div>\n <div class=\"step-breakdown\">\n <h3>Steps by Type</h3>\n <div class=\"step-type-list\">\n @for (type of timelineMetrics.stepsByType | keyvalue; track trackByKey($index, type)) {\n <div class=\"step-type-item\">\n <i class=\"fas\" [ngClass]=\"getStepTypeIcon(type.key)\"></i>\n <span class=\"type-name\">{{ type.key }}</span>\n <span class=\"type-count\">{{ type.value }}</span>\n <span class=\"type-percentage\">({{ (type.value / timelineMetrics.totalSteps * 100).toFixed(1) }}%)</span>\n </div>\n }\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n </div>\n }\n</div>", styles: [".analytics-container {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background-color: var(--mj-bg-surface-sunken);\n}\n\n/* Loading and Error States */\n.loading-state,\n.error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 300px;\n color: var(--mj-text-muted);\n}\n\n.loading-state i,\n.error-state i {\n margin-bottom: 15px;\n}\n\n.error-state {\n color: var(--mj-status-error);\n}\n\n/* Summary Cards */\n.summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.summary-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.summary-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\n}\n\n.card-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 20px;\n font-size: 24px;\n color: var(--mj-text-inverse);\n}\n\n.card-icon.prompts {\n background: var(--mj-brand-primary);\n}\n\n.card-icon.actions {\n background: var(--mj-status-error);\n}\n\n.card-icon.cost {\n background: var(--mj-status-success);\n}\n\n.card-icon.time {\n background: var(--mj-status-warning);\n}\n\n.card-content h3 {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.metric-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.metric-detail {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.metric-detail .success {\n color: var(--mj-status-success);\n margin-right: 10px;\n}\n\n.metric-detail .failed {\n color: var(--mj-status-error);\n}\n\n/* Analytics Panels */\n.analytics-panel {\n padding: 15px;\n}\n\n/* Accordion Panel Styling */\n.analytics-content mj-accordion-panel {\n display: block;\n margin-bottom: 12px;\n}\n\n/* Charts */\n.charts-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));\n gap: 20px;\n margin-bottom: 20px;\n}\n\n/* Chart Cards */\n.chart-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n transition: all 0.3s ease;\n}\n\n.chart-card.expanded {\n grid-column: 1 / -1;\n}\n\n.chart-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.chart-card-header:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.chart-card-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.chart-card-header h3 i {\n font-size: 16px;\n color: var(--mj-text-muted);\n}\n\n.expand-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.expand-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.chart-card-body {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n}\n\n.chart-card.expanded .chart-card-body {\n padding: 24px;\n}\n\n.chart-card.expanded .chart-container > div {\n min-height: 400px;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n justify-content: flex-end;\n margin-bottom: 16px;\n}\n\n.view-mode-toggle button {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.chart-container {\n position: relative;\n}\n\n.chart-container h3 {\n margin: 0 0 10px 0;\n font-size: 15px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.chart-container > div {\n min-height: 220px;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n/* Ensure SVG charts are centered */\n.chart-container svg {\n display: block;\n margin: 0 auto;\n}\n\n.chart-legend {\n margin-top: 10px;\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n}\n\n.legend-color {\n width: 16px;\n height: 16px;\n border-radius: 3px;\n}\n\n.chart-total {\n text-align: center;\n margin-top: 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n/* Detailed Metrics */\n.detailed-metrics {\n margin-top: 20px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 20px;\n}\n\n.detailed-metrics button {\n margin-bottom: 15px;\n}\n\n.detailed-metrics button i {\n margin-right: 8px;\n}\n\n.metrics-table {\n overflow-x: auto;\n}\n\n.metrics-table table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.metrics-table th {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n}\n\n.metrics-table td {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.metrics-table tr:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.success-rate {\n font-weight: 500;\n}\n\n.success-rate.high {\n color: var(--mj-status-success);\n}\n\n.success-rate.medium {\n color: var(--mj-status-warning);\n}\n\n.success-rate.low {\n color: var(--mj-status-error);\n}\n\n/* Error Analysis */\n.error-analysis {\n margin-top: 30px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.error-analysis h3 {\n margin: 0 0 15px 0;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-analysis-description {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n.error-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.error-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px;\n background-color: var(--mj-bg-surface);\n border-radius: 4px;\n font-size: 14px;\n}\n\n.error-count {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.error-message {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n/* No errors state */\n.no-errors {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.no-errors i {\n font-size: 24px;\n color: var(--mj-status-success);\n}\n\n.no-errors p {\n margin: 0;\n font-size: 14px;\n}\n\n/* No data message */\n.no-data-message {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.no-data-message i {\n font-size: 48px;\n margin-bottom: 20px;\n color: var(--mj-border-strong);\n}\n\n.no-data-message p {\n margin: 0 0 10px 0;\n font-size: 16px;\n}\n\n.no-data-message p.small {\n font-size: 14px;\n color: var(--mj-text-disabled);\n}\n\n/* Model Comparison Table */\n.model-comparison {\n overflow-x: auto;\n}\n\n.model-comparison table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.model-comparison th {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n white-space: nowrap;\n}\n\n.model-comparison td {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.model-comparison tr:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n/* Timeline Analysis */\n.timeline-stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 20px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n}\n\n.stat-label {\n font-size: 14px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.stat-value {\n font-size: 32px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.step-breakdown h3 {\n margin: 0 0 15px 0;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.step-type-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 12px;\n}\n\n.step-type-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n border: 1px solid var(--mj-border-default);\n}\n\n.step-type-item i {\n width: 30px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.type-name {\n flex: 1;\n font-weight: 500;\n}\n\n.type-count {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.type-percentage {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: 5px;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .summary-cards {\n grid-template-columns: 1fr;\n }\n \n .charts-grid {\n grid-template-columns: 1fr;\n }\n \n .timeline-stats {\n grid-template-columns: repeat(2, 1fr);\n }\n}"] }]
|
|
2307
|
+
args: [{ standalone: false, selector: 'mj-ai-agent-run-analytics', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"analytics-container\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <i class=\"fas fa-spinner fa-spin fa-2x\"></i>\n <p>Loading analytics data...</p>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle fa-2x\"></i>\n <p>{{ error }}</p>\n <button mjButton (click)=\"loadData()\">Retry</button>\n </div>\n }\n\n <!-- Analytics Content -->\n @if (!isLoading && !error) {\n <div class=\"analytics-content\">\n <!-- Summary Cards -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-tachometer-alt\"></i> Overview\n </ng-template>\n <div class=\"summary-cards\">\n <div class=\"summary-card\">\n <div class=\"card-icon prompts\">\n <i class=\"fas fa-microchip\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Prompts</h3>\n <div class=\"metric-value\">{{ promptMetrics.totalCount }}</div>\n <div class=\"metric-detail\">\n <span class=\"success\">{{ promptMetrics.statusBreakdown.success }} successful</span>\n @if (promptMetrics.statusBreakdown.failed > 0) {\n <span class=\"failed\">{{ promptMetrics.statusBreakdown.failed }} failed</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon actions\">\n <i class=\"fas fa-cog\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Actions</h3>\n <div class=\"metric-value\">{{ actionMetrics.totalCount }}</div>\n <div class=\"metric-detail\">\n <span class=\"success\">{{ actionMetrics.statusBreakdown.success }} successful</span>\n @if (actionMetrics.statusBreakdown.failed > 0) {\n <span class=\"failed\">{{ actionMetrics.statusBreakdown.failed }} failed</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon cost\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Total Cost</h3>\n <div class=\"metric-value\">{{ formatCost(promptMetrics.costBreakdown.totalCost) }}</div>\n <div class=\"metric-detail cache-detail\">\n <span>{{ totalTokensProcessed | number }} tokens</span>\n @if (promptMetrics.tokenUsage.totalCacheRead > 0 || promptMetrics.tokenUsage.totalCacheWrite > 0) {\n <span>incl. {{ (promptMetrics.tokenUsage.totalCacheRead + promptMetrics.tokenUsage.totalCacheWrite) | number }} cached</span>\n }\n @if (inputCost > 0 || outputCost > 0) {\n <span>input {{ formatCost(inputCost) }} · output {{ formatCost(outputCost) }}</span>\n }\n @if (cacheSavings > 0) {\n <span class=\"success\">saved {{ formatCost(cacheSavings) }} ({{ cacheSavingsPct | number:'1.0-0' }}%) via cache</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon cache\">\n <i class=\"fas fa-bolt\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Prompt Cache</h3>\n <div class=\"metric-value\">{{ promptMetrics.tokenUsage.totalCacheRead | number }}</div>\n <div class=\"metric-detail cache-detail\">\n <span>tokens read from cache</span>\n @if (promptMetrics.tokenUsage.totalCacheWrite > 0) {\n <span>{{ promptMetrics.tokenUsage.totalCacheWrite | number }} written</span>\n }\n @if (promptMetrics.tokenUsage.totalCacheRead > 0 || promptMetrics.tokenUsage.totalCacheWrite > 0) {\n <span>{{ cacheHitRatePct | number:'1.0-0' }}% hit rate</span>\n }\n </div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-icon time\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"card-content\">\n <h3>Execution Time</h3>\n <div class=\"metric-value\">{{ formatDuration(promptMetrics.totalExecutionTime + actionMetrics.totalExecutionTime) }}</div>\n <div class=\"metric-detail\">\n <span>{{ timelineMetrics.totalSteps }} total steps</span>\n </div>\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Prompt Analytics -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-microchip\"></i> Prompt Analytics\n </ng-template>\n <div class=\"analytics-panel\">\n <!-- View Mode Toggle -->\n @if (promptMetrics.totalCount > 0) {\n <div class=\"view-mode-toggle\">\n <button mjButton\n variant=\"flat\"\n (click)=\"toggleViewMode()\">\n <i class=\"fas\" [ngClass]=\"viewMode === 'grid' ? 'fa-expand-arrows-alt' : 'fa-compress-arrows-alt'\"></i>\n {{ viewMode === 'grid' ? 'Expand All' : 'Collapse All' }}\n </button>\n </div>\n }\n <!-- No prompts message -->\n @if (promptMetrics.totalCount === 0) {\n <div class=\"no-data-message\">\n <i class=\"fas fa-info-circle\"></i>\n <p>No prompt executions found in this agent run.</p>\n <p class=\"small\">This agent run may have only executed actions without any AI prompts.</p>\n </div>\n }\n @if (promptMetrics.totalCount > 0) {\n <div class=\"charts-grid\">\n <!-- Model Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['modelDistribution']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('modelDistribution')\">\n <h3><i class=\"fas fa-chart-pie\"></i> Prompts by Model</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['modelDistribution'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"modelDistributionChart\" #modelDistributionChart></div>\n @if (promptMetrics.byModel.size > 0) {\n <div class=\"chart-legend\">\n @for (item of promptMetrics.byModel | keyvalue; track trackByKey($index, item)) {\n <div class=\"legend-item\">\n <span class=\"legend-color\" [style.backgroundColor]=\"getModelColor(item.key)\"></span>\n <span class=\"legend-label\">{{ item.key }}: {{ item.value.count }} ({{ (item.value.count / promptMetrics.totalCount * 100).toFixed(1) }}%)</span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Execution Time by Vendor -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['executionTime']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('executionTime')\">\n <h3><i class=\"fas fa-clock\"></i> Average Execution Time by Vendor</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['executionTime'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"executionTimeChart\" #executionTimeChart></div>\n </div>\n </div>\n </div>\n <!-- Cost by Vendor -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['costByVendor']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('costByVendor')\">\n <h3><i class=\"fas fa-dollar-sign\"></i> Cost Distribution by Vendor</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['costByVendor'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"costByVendorChart\" #costByVendorChart></div>\n <div class=\"chart-total\">Total: {{ formatCost(promptMetrics.costBreakdown.totalCost) }}</div>\n </div>\n </div>\n </div>\n <!-- Token Usage -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['tokenUsage']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('tokenUsage')\">\n <h3><i class=\"fas fa-coins\"></i> Token Usage by Model</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['tokenUsage'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"tokenUsageChart\" #tokenUsageChart></div>\n </div>\n </div>\n </div>\n </div>\n }\n <!-- Additional Prompt Analytics Charts -->\n @if (promptMetrics.totalCount > 0) {\n <div class=\"charts-grid\" style=\"margin-top: 20px;\">\n <!-- Prompt Execution Time Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptTime']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptTime')\">\n <h3><i class=\"fas fa-hourglass-half\"></i> Average Execution Time by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptTime'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptTimeDistributionChart\" #promptTimeDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Token Usage -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptToken']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptToken')\">\n <h3><i class=\"fas fa-database\"></i> Token Usage by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptToken'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptTokenDistributionChart\" #promptTokenDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Cost Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptCost']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptCost')\">\n <h3><i class=\"fas fa-chart-pie\"></i> Cost Distribution by Prompt</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptCost'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptCostDistributionChart\" #promptCostDistributionChart></div>\n </div>\n </div>\n </div>\n <!-- Prompt Count by Name -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['promptCount']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('promptCount')\">\n <h3><i class=\"fas fa-list-ol\"></i> Prompt Execution Count</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['promptCount'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"promptCountByNameChart\" #promptCountByNameChart></div>\n </div>\n </div>\n </div>\n </div>\n }\n <!-- Detailed Prompt Metrics -->\n <div class=\"detailed-metrics\">\n <button mjButton\n variant=\"flat\"\n (click)=\"promptDetailsExpanded = !promptDetailsExpanded\">\n <i class=\"fas\" [ngClass]=\"promptDetailsExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n Detailed Prompt Metrics\n </button>\n @if (promptDetailsExpanded) {\n <div class=\"metrics-table\">\n <table>\n <thead>\n <tr>\n <th>Prompt Name</th>\n <th>Count</th>\n <th>Avg Time</th>\n <th>Total Time</th>\n <th>Success Rate</th>\n </tr>\n </thead>\n <tbody>\n @for (prompt of promptMetrics.byPrompt | keyvalue; track trackByKey($index, prompt)) {\n <tr>\n <td>{{ prompt.key }}</td>\n <td>{{ prompt.value.count }}</td>\n <td>{{ formatDuration(prompt.value.avgTime) }}</td>\n <td>{{ formatDuration(prompt.value.totalTime) }}</td>\n <td>\n <span class=\"success-rate\">\n <!-- Calculate success rate for this prompt -->\n {{ calculatePromptSuccessRate(prompt.key) }}%\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Action Analytics -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-cog\"></i> Action Analytics\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"charts-grid\">\n <!-- Action Success Rate -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['actionSuccess']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('actionSuccess')\">\n <h3><i class=\"fas fa-chart-bar\"></i> Action Success Rate</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['actionSuccess'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"actionSuccessRateChart\" #actionSuccessRateChart></div>\n </div>\n </div>\n </div>\n <!-- Step Type Distribution -->\n <div class=\"chart-card\" [class.expanded]=\"expandedCharts['stepType']\">\n <div class=\"chart-card-header\" (click)=\"toggleChartExpansion('stepType')\">\n <h3><i class=\"fas fa-layer-group\"></i> Step Type Distribution</h3>\n <button class=\"expand-btn\">\n <i class=\"fas\" [ngClass]=\"expandedCharts['stepType'] ? 'fa-compress' : 'fa-expand'\"></i>\n </button>\n </div>\n <div class=\"chart-card-body\">\n <div class=\"chart-container\">\n <div id=\"stepTypeChart\" #stepTypeChart></div>\n </div>\n </div>\n </div>\n </div>\n <!-- Detailed Action Metrics -->\n <div class=\"detailed-metrics\">\n <button mjButton\n variant=\"flat\"\n (click)=\"actionDetailsExpanded = !actionDetailsExpanded\">\n <i class=\"fas\" [ngClass]=\"actionDetailsExpanded ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n Detailed Action Metrics\n </button>\n @if (actionDetailsExpanded) {\n <div class=\"metrics-table\">\n <table>\n <thead>\n <tr>\n <th>Action Name</th>\n <th>Count</th>\n <th>Avg Time</th>\n <th>Success Rate</th>\n <th>Type</th>\n </tr>\n </thead>\n <tbody>\n @for (action of actionMetrics.byAction | keyvalue; track trackByKey($index, action)) {\n <tr>\n <td>{{ action.key }}</td>\n <td>{{ action.value.count }}</td>\n <td>{{ formatDuration(action.value.avgTime) }}</td>\n <td>\n <span class=\"success-rate\" [class.high]=\"action.value.successRate > 0.9\"\n [class.medium]=\"action.value.successRate > 0.7 && action.value.successRate <= 0.9\"\n [class.low]=\"action.value.successRate <= 0.7\">\n {{ (action.value.successRate * 100).toFixed(1) }}%\n </span>\n </td>\n <td>{{ getActionType(action.key) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n <!-- Error Analysis -->\n <div class=\"error-analysis-section\">\n @if (actionMetrics.errorAnalysis.size > 0) {\n <div class=\"error-analysis\">\n <h3>\n <i class=\"fas fa-exclamation-triangle\"></i>\n Common Errors\n </h3>\n <p class=\"error-analysis-description\">\n This section shows the most frequent error messages from failed actions, helping identify systemic issues that may need attention.\n </p>\n <div class=\"error-list\">\n @for (error of getTopErrors(); track trackByErrorMessage($index, error)) {\n <div class=\"error-item\">\n <span class=\"error-count\">{{ error.count }}x</span>\n <span class=\"error-message\">{{ error.message }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (actionMetrics.errorAnalysis.size === 0) {\n <div class=\"no-errors\">\n <i class=\"fas fa-check-circle\"></i>\n <p>No action errors detected in this run. All actions completed successfully!</p>\n </div>\n }\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Model Performance Comparison -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-chart-line\"></i> Model Performance Comparison\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"model-comparison\">\n <table>\n <thead>\n <tr>\n <th>Model</th>\n <th>Vendor</th>\n <th>Prompts</th>\n <th>Avg Time</th>\n <th>Total Cost</th>\n <th>Avg Cost/Prompt</th>\n <th>Input Tokens</th>\n <th>Output Tokens</th>\n </tr>\n </thead>\n <tbody>\n @for (model of getModelPerformanceData(); track trackByModelName($index, model)) {\n <tr>\n <td>{{ model.name }}</td>\n <td>{{ model.vendor }}</td>\n <td>{{ model.count }}</td>\n <td>{{ formatDuration(model.avgTime) }}</td>\n <td>{{ formatCost(model.totalCost) }}</td>\n <td>{{ formatCost(model.avgCost) }}</td>\n <td>{{ model.inputTokens | number:'1.0-0' }}</td>\n <td>{{ model.outputTokens | number:'1.0-0' }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n </mj-accordion-panel>\n <!-- Timeline Analysis -->\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-stream\"></i> Execution Timeline Analysis\n </ng-template>\n <div class=\"analytics-panel\">\n <div class=\"timeline-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Total Steps</span>\n <span class=\"stat-value\">{{ timelineMetrics.totalSteps }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Parallel Executions</span>\n <span class=\"stat-value\">{{ timelineMetrics.parallelExecutions }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Max Nesting Depth</span>\n <span class=\"stat-value\">{{ timelineMetrics.deepestNesting }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Sub-Agent Runs</span>\n <span class=\"stat-value\">{{ subAgentRuns.length }}</span>\n </div>\n </div>\n <div class=\"step-breakdown\">\n <h3>Steps by Type</h3>\n <div class=\"step-type-list\">\n @for (type of timelineMetrics.stepsByType | keyvalue; track trackByKey($index, type)) {\n <div class=\"step-type-item\">\n <i class=\"fas\" [ngClass]=\"getStepTypeIcon(type.key)\"></i>\n <span class=\"type-name\">{{ type.key }}</span>\n <span class=\"type-count\">{{ type.value }}</span>\n <span class=\"type-percentage\">({{ (type.value / timelineMetrics.totalSteps * 100).toFixed(1) }}%)</span>\n </div>\n }\n </div>\n </div>\n </div>\n </mj-accordion-panel>\n </div>\n }\n</div>", styles: [".analytics-container {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background-color: var(--mj-bg-surface-sunken);\n}\n\n/* Loading and Error States */\n.loading-state,\n.error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 300px;\n color: var(--mj-text-muted);\n}\n\n.loading-state i,\n.error-state i {\n margin-bottom: 15px;\n}\n\n.error-state {\n color: var(--mj-status-error);\n}\n\n/* Summary Cards */\n.summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.summary-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.summary-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\n}\n\n.card-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 20px;\n font-size: 24px;\n color: var(--mj-text-inverse);\n}\n\n.card-icon.prompts {\n background: var(--mj-brand-primary);\n}\n\n.card-icon.actions {\n background: var(--mj-status-error);\n}\n\n.card-icon.cost {\n background: var(--mj-status-success);\n}\n\n.card-icon.time {\n background: var(--mj-status-warning);\n}\n\n.card-icon.cache {\n background: var(--mj-status-info);\n}\n\n.card-content h3 {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.metric-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.metric-detail {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.metric-detail .success {\n color: var(--mj-status-success);\n margin-right: 10px;\n}\n\n.metric-detail .failed {\n color: var(--mj-status-error);\n}\n\n/* Cache card stacks its facts (caption / written / hit rate) one per line. */\n.metric-detail.cache-detail span {\n display: block;\n}\n\n/* Analytics Panels */\n.analytics-panel {\n padding: 15px;\n}\n\n/* Accordion Panel Styling */\n.analytics-content mj-accordion-panel {\n display: block;\n margin-bottom: 12px;\n}\n\n/* Charts */\n.charts-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));\n gap: 20px;\n margin-bottom: 20px;\n}\n\n/* Chart Cards */\n.chart-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n transition: all 0.3s ease;\n}\n\n.chart-card.expanded {\n grid-column: 1 / -1;\n}\n\n.chart-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.chart-card-header:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.chart-card-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.chart-card-header h3 i {\n font-size: 16px;\n color: var(--mj-text-muted);\n}\n\n.expand-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.expand-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.chart-card-body {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n}\n\n.chart-card.expanded .chart-card-body {\n padding: 24px;\n}\n\n.chart-card.expanded .chart-container > div {\n min-height: 400px;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n justify-content: flex-end;\n margin-bottom: 16px;\n}\n\n.view-mode-toggle button {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.chart-container {\n position: relative;\n}\n\n.chart-container h3 {\n margin: 0 0 10px 0;\n font-size: 15px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.chart-container > div {\n min-height: 220px;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n/* Ensure SVG charts are centered */\n.chart-container svg {\n display: block;\n margin: 0 auto;\n}\n\n.chart-legend {\n margin-top: 10px;\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n}\n\n.legend-color {\n width: 16px;\n height: 16px;\n border-radius: 3px;\n}\n\n.chart-total {\n text-align: center;\n margin-top: 10px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n/* Detailed Metrics */\n.detailed-metrics {\n margin-top: 20px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 20px;\n}\n\n.detailed-metrics button {\n margin-bottom: 15px;\n}\n\n.detailed-metrics button i {\n margin-right: 8px;\n}\n\n.metrics-table {\n overflow-x: auto;\n}\n\n.metrics-table table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.metrics-table th {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n}\n\n.metrics-table td {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.metrics-table tr:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.success-rate {\n font-weight: 500;\n}\n\n.success-rate.high {\n color: var(--mj-status-success);\n}\n\n.success-rate.medium {\n color: var(--mj-status-warning);\n}\n\n.success-rate.low {\n color: var(--mj-status-error);\n}\n\n/* Error Analysis */\n.error-analysis {\n margin-top: 30px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-bg-surface));\n}\n\n.error-analysis h3 {\n margin: 0 0 15px 0;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-analysis-description {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n.error-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.error-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px;\n background-color: var(--mj-bg-surface);\n border-radius: 4px;\n font-size: 14px;\n}\n\n.error-count {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.error-message {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n/* No errors state */\n.no-errors {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.no-errors i {\n font-size: 24px;\n color: var(--mj-status-success);\n}\n\n.no-errors p {\n margin: 0;\n font-size: 14px;\n}\n\n/* No data message */\n.no-data-message {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.no-data-message i {\n font-size: 48px;\n margin-bottom: 20px;\n color: var(--mj-border-strong);\n}\n\n.no-data-message p {\n margin: 0 0 10px 0;\n font-size: 16px;\n}\n\n.no-data-message p.small {\n font-size: 14px;\n color: var(--mj-text-disabled);\n}\n\n/* Model Comparison Table */\n.model-comparison {\n overflow-x: auto;\n}\n\n.model-comparison table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.model-comparison th {\n background-color: var(--mj-bg-surface-sunken);\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n border-bottom: 2px solid var(--mj-border-strong);\n white-space: nowrap;\n}\n\n.model-comparison td {\n padding: 12px;\n border-bottom: 1px solid var(--mj-border-strong);\n}\n\n.model-comparison tr:hover {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n/* Timeline Analysis */\n.timeline-stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 30px;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 20px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n}\n\n.stat-label {\n font-size: 14px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.stat-value {\n font-size: 32px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.step-breakdown h3 {\n margin: 0 0 15px 0;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.step-type-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 12px;\n}\n\n.step-type-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n border: 1px solid var(--mj-border-default);\n}\n\n.step-type-item i {\n width: 30px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.type-name {\n flex: 1;\n font-weight: 500;\n}\n\n.type-count {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.type-percentage {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: 5px;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .summary-cards {\n grid-template-columns: 1fr;\n }\n \n .charts-grid {\n grid-template-columns: 1fr;\n }\n \n .timeline-stats {\n grid-template-columns: repeat(2, 1fr);\n }\n}"] }]
|
|
2151
2308
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i1.AIAgentRunCostService }], { agentRunId: [{
|
|
2152
2309
|
type: Input
|
|
2153
2310
|
}], modelDistributionChart: [{
|
|
@@ -2181,5 +2338,5 @@ export class AIAgentRunAnalyticsComponent extends BaseAngularComponent {
|
|
|
2181
2338
|
type: ViewChild,
|
|
2182
2339
|
args: ['promptCountByNameChart', { static: false }]
|
|
2183
2340
|
}] }); })();
|
|
2184
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AIAgentRunAnalyticsComponent, { className: "AIAgentRunAnalyticsComponent", filePath: "src/lib/custom/ai-agent-run/ai-agent-run-analytics.component.ts", lineNumber:
|
|
2341
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AIAgentRunAnalyticsComponent, { className: "AIAgentRunAnalyticsComponent", filePath: "src/lib/custom/ai-agent-run/ai-agent-run-analytics.component.ts", lineNumber: 82 }); })();
|
|
2185
2342
|
//# sourceMappingURL=ai-agent-run-analytics.component.js.map
|