@memberjunction/ng-dashboards 5.26.0 → 5.27.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/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts +96 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +710 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts +52 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.js +356 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.d.ts +52 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.js +306 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.js.map +1 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +81 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +744 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts +61 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js +490 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts +77 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +673 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +65 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.js +537 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +131 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +1030 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +78 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +569 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -0
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +4 -14
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/overview/ai-overview-hub.component.d.ts +58 -0
- package/dist/AI/components/overview/ai-overview-hub.component.d.ts.map +1 -0
- package/dist/AI/components/overview/ai-overview-hub.component.js +315 -0
- package/dist/AI/components/overview/ai-overview-hub.component.js.map +1 -0
- package/dist/AI/components/prompts/prompt-management.component.js +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/index.d.ts +11 -0
- package/dist/AI/index.d.ts.map +1 -1
- package/dist/AI/index.js +13 -0
- package/dist/AI/index.js.map +1 -1
- package/dist/AI/interfaces/analytics-preferences.interface.d.ts +50 -0
- package/dist/AI/interfaces/analytics-preferences.interface.d.ts.map +1 -0
- package/dist/AI/interfaces/analytics-preferences.interface.js +9 -0
- package/dist/AI/interfaces/analytics-preferences.interface.js.map +1 -0
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +2 -2
- package/dist/MCP/index.d.ts +1 -0
- package/dist/MCP/index.d.ts.map +1 -1
- package/dist/MCP/index.js +2 -0
- package/dist/MCP/index.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts +1 -0
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +5 -4
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/MCP/mcp-resource.component.d.ts +6 -5
- package/dist/MCP/mcp-resource.component.d.ts.map +1 -1
- package/dist/MCP/mcp-resource.component.js +7 -8
- package/dist/MCP/mcp-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +27 -17
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +66 -3
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +48 -48
- package/dist/__tests__/analytics-resource.test.d.ts +0 -2
- package/dist/__tests__/analytics-resource.test.d.ts.map +0 -1
- package/dist/__tests__/analytics-resource.test.js +0 -181
- package/dist/__tests__/analytics-resource.test.js.map +0 -1
- package/dist/__tests__/dashboards.test.d.ts +0 -2
- package/dist/__tests__/dashboards.test.d.ts.map +0 -1
- package/dist/__tests__/dashboards.test.js +0 -40
- package/dist/__tests__/dashboards.test.js.map +0 -1
- package/dist/__tests__/integration-data-service.test.d.ts +0 -2
- package/dist/__tests__/integration-data-service.test.d.ts.map +0 -1
- package/dist/__tests__/integration-data-service.test.js +0 -132
- package/dist/__tests__/integration-data-service.test.js.map +0 -1
- package/dist/__tests__/mapping-validation.test.d.ts +0 -2
- package/dist/__tests__/mapping-validation.test.d.ts.map +0 -1
- package/dist/__tests__/mapping-validation.test.js +0 -170
- package/dist/__tests__/mapping-validation.test.js.map +0 -1
- package/dist/__tests__/scheduling.test.d.ts +0 -2
- package/dist/__tests__/scheduling.test.d.ts.map +0 -1
- package/dist/__tests__/scheduling.test.js +0 -205
- package/dist/__tests__/scheduling.test.js.map +0 -1
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Agent Run Analysis -- Cost Attribution Focus.
|
|
3
|
+
*
|
|
4
|
+
* Displays agent run stats, cost attribution horizontal stacked bars per agent,
|
|
5
|
+
* and a sortable recent agent runs table. All data loaded via RunView from
|
|
6
|
+
* "MJ: AI Agent Runs" and "MJ: AI Prompt Runs" entities.
|
|
7
|
+
*/
|
|
8
|
+
import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject } from '@angular/core';
|
|
9
|
+
import { Subject } from 'rxjs';
|
|
10
|
+
import { RunView } from '@memberjunction/core';
|
|
11
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
14
|
+
import * as i2 from "../analytics-filter-bar.component";
|
|
15
|
+
import * as i3 from "@angular/common";
|
|
16
|
+
const _forTrack0 = ($index, $item) => $item.AgentID;
|
|
17
|
+
const _forTrack1 = ($index, $item) => $item.field;
|
|
18
|
+
const _forTrack2 = ($index, $item) => $item.ID;
|
|
19
|
+
const _forTrack3 = ($index, $item) => $item.Label;
|
|
20
|
+
function AnalyticsAgentRunsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
22
|
+
i0.ɵɵelement(1, "mj-loading", 2);
|
|
23
|
+
i0.ɵɵelementEnd();
|
|
24
|
+
} }
|
|
25
|
+
function AnalyticsAgentRunsComponent_Conditional_2_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
27
|
+
i0.ɵɵtext(1, "No agent cost data for selected period");
|
|
28
|
+
i0.ɵɵelementEnd();
|
|
29
|
+
} }
|
|
30
|
+
function AnalyticsAgentRunsComponent_Conditional_2_For_43_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
+
i0.ɵɵelement(0, "div", 26);
|
|
32
|
+
} if (rf & 2) {
|
|
33
|
+
const seg_r1 = ctx.$implicit;
|
|
34
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
35
|
+
i0.ɵɵstyleProp("width", seg_r1.Percent, "%")("background", seg_r1.Color);
|
|
36
|
+
i0.ɵɵproperty("title", seg_r1.Label + ": " + ctx_r1.FormatCurrency(seg_r1.Value, 4));
|
|
37
|
+
} }
|
|
38
|
+
function AnalyticsAgentRunsComponent_Conditional_2_For_43_Template(rf, ctx) { if (rf & 1) {
|
|
39
|
+
i0.ɵɵelementStart(0, "div", 15)(1, "div", 22);
|
|
40
|
+
i0.ɵɵtext(2);
|
|
41
|
+
i0.ɵɵelementEnd();
|
|
42
|
+
i0.ɵɵelementStart(3, "div", 23);
|
|
43
|
+
i0.ɵɵrepeaterCreate(4, AnalyticsAgentRunsComponent_Conditional_2_For_43_For_5_Template, 1, 5, "div", 24, _forTrack3);
|
|
44
|
+
i0.ɵɵelementEnd();
|
|
45
|
+
i0.ɵɵelementStart(6, "div", 25);
|
|
46
|
+
i0.ɵɵtext(7);
|
|
47
|
+
i0.ɵɵelementEnd()();
|
|
48
|
+
} if (rf & 2) {
|
|
49
|
+
const row_r3 = ctx.$implicit;
|
|
50
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
51
|
+
i0.ɵɵadvance();
|
|
52
|
+
i0.ɵɵproperty("title", row_r3.AgentName);
|
|
53
|
+
i0.ɵɵadvance();
|
|
54
|
+
i0.ɵɵtextInterpolate(row_r3.AgentName);
|
|
55
|
+
i0.ɵɵadvance(2);
|
|
56
|
+
i0.ɵɵrepeater(row_r3.Segments);
|
|
57
|
+
i0.ɵɵadvance(3);
|
|
58
|
+
i0.ɵɵtextInterpolate(ctx_r1.FormatCurrency(row_r3.TotalCost));
|
|
59
|
+
} }
|
|
60
|
+
function AnalyticsAgentRunsComponent_Conditional_2_Conditional_44_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
61
|
+
i0.ɵɵelementStart(0, "div", 27);
|
|
62
|
+
i0.ɵɵelement(1, "span", 28);
|
|
63
|
+
i0.ɵɵtext(2);
|
|
64
|
+
i0.ɵɵelementEnd();
|
|
65
|
+
} if (rf & 2) {
|
|
66
|
+
const item_r4 = ctx.$implicit;
|
|
67
|
+
i0.ɵɵadvance();
|
|
68
|
+
i0.ɵɵstyleProp("background", item_r4.Color);
|
|
69
|
+
i0.ɵɵadvance();
|
|
70
|
+
i0.ɵɵtextInterpolate1(" ", item_r4.Label, " ");
|
|
71
|
+
} }
|
|
72
|
+
function AnalyticsAgentRunsComponent_Conditional_2_Conditional_44_Template(rf, ctx) { if (rf & 1) {
|
|
73
|
+
i0.ɵɵelementStart(0, "div", 16);
|
|
74
|
+
i0.ɵɵrepeaterCreate(1, AnalyticsAgentRunsComponent_Conditional_2_Conditional_44_For_2_Template, 3, 3, "div", 27, _forTrack3);
|
|
75
|
+
i0.ɵɵelementEnd();
|
|
76
|
+
} if (rf & 2) {
|
|
77
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
78
|
+
i0.ɵɵadvance();
|
|
79
|
+
i0.ɵɵrepeater(ctx_r1.LegendItems);
|
|
80
|
+
} }
|
|
81
|
+
function AnalyticsAgentRunsComponent_Conditional_2_For_57_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
82
|
+
i0.ɵɵelement(0, "i");
|
|
83
|
+
} if (rf & 2) {
|
|
84
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
85
|
+
i0.ɵɵclassMap(ctx_r1.SortDir === "asc" ? "fa-solid fa-caret-up" : "fa-solid fa-caret-down");
|
|
86
|
+
} }
|
|
87
|
+
function AnalyticsAgentRunsComponent_Conditional_2_For_57_Template(rf, ctx) { if (rf & 1) {
|
|
88
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
89
|
+
i0.ɵɵelementStart(0, "th", 29);
|
|
90
|
+
i0.ɵɵlistener("click", function AnalyticsAgentRunsComponent_Conditional_2_For_57_Template_th_click_0_listener() { const col_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnSort(col_r6.field)); });
|
|
91
|
+
i0.ɵɵtext(1);
|
|
92
|
+
i0.ɵɵconditionalCreate(2, AnalyticsAgentRunsComponent_Conditional_2_For_57_Conditional_2_Template, 1, 2, "i", 30);
|
|
93
|
+
i0.ɵɵelementEnd();
|
|
94
|
+
} if (rf & 2) {
|
|
95
|
+
const col_r6 = ctx.$implicit;
|
|
96
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
97
|
+
i0.ɵɵclassProp("sorted", ctx_r1.SortField === col_r6.field);
|
|
98
|
+
i0.ɵɵadvance();
|
|
99
|
+
i0.ɵɵtextInterpolate1(" ", col_r6.label, " ");
|
|
100
|
+
i0.ɵɵadvance();
|
|
101
|
+
i0.ɵɵconditional(ctx_r1.SortField === col_r6.field ? 2 : -1);
|
|
102
|
+
} }
|
|
103
|
+
function AnalyticsAgentRunsComponent_Conditional_2_Conditional_59_Template(rf, ctx) { if (rf & 1) {
|
|
104
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 31);
|
|
105
|
+
i0.ɵɵtext(2, "No runs found");
|
|
106
|
+
i0.ɵɵelementEnd()();
|
|
107
|
+
} if (rf & 2) {
|
|
108
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
109
|
+
i0.ɵɵadvance();
|
|
110
|
+
i0.ɵɵattribute("colspan", ctx_r1.TableColumns.length);
|
|
111
|
+
} }
|
|
112
|
+
function AnalyticsAgentRunsComponent_Conditional_2_For_61_Template(rf, ctx) { if (rf & 1) {
|
|
113
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 32);
|
|
114
|
+
i0.ɵɵtext(2);
|
|
115
|
+
i0.ɵɵelementEnd();
|
|
116
|
+
i0.ɵɵelementStart(3, "td")(4, "span", 33);
|
|
117
|
+
i0.ɵɵtext(5);
|
|
118
|
+
i0.ɵɵelementEnd()();
|
|
119
|
+
i0.ɵɵelementStart(6, "td", 34);
|
|
120
|
+
i0.ɵɵtext(7);
|
|
121
|
+
i0.ɵɵelementEnd();
|
|
122
|
+
i0.ɵɵelementStart(8, "td", 34);
|
|
123
|
+
i0.ɵɵtext(9);
|
|
124
|
+
i0.ɵɵelementEnd();
|
|
125
|
+
i0.ɵɵelementStart(10, "td", 34);
|
|
126
|
+
i0.ɵɵtext(11);
|
|
127
|
+
i0.ɵɵelementEnd();
|
|
128
|
+
i0.ɵɵelementStart(12, "td", 35);
|
|
129
|
+
i0.ɵɵtext(13);
|
|
130
|
+
i0.ɵɵelementEnd()();
|
|
131
|
+
} if (rf & 2) {
|
|
132
|
+
const run_r7 = ctx.$implicit;
|
|
133
|
+
i0.ɵɵadvance(2);
|
|
134
|
+
i0.ɵɵtextInterpolate(run_r7.Agent);
|
|
135
|
+
i0.ɵɵadvance(2);
|
|
136
|
+
i0.ɵɵclassMap(run_r7.StatusClass);
|
|
137
|
+
i0.ɵɵadvance();
|
|
138
|
+
i0.ɵɵtextInterpolate(run_r7.Status);
|
|
139
|
+
i0.ɵɵadvance(2);
|
|
140
|
+
i0.ɵɵtextInterpolate(run_r7.StepCount);
|
|
141
|
+
i0.ɵɵadvance(2);
|
|
142
|
+
i0.ɵɵtextInterpolate(run_r7.Duration);
|
|
143
|
+
i0.ɵɵadvance(2);
|
|
144
|
+
i0.ɵɵtextInterpolate(run_r7.Cost);
|
|
145
|
+
i0.ɵɵadvance(2);
|
|
146
|
+
i0.ɵɵtextInterpolate(run_r7.Time);
|
|
147
|
+
} }
|
|
148
|
+
function AnalyticsAgentRunsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
149
|
+
i0.ɵɵelementStart(0, "div", 3)(1, "div", 4)(2, "div", 5);
|
|
150
|
+
i0.ɵɵtext(3, "Total Runs");
|
|
151
|
+
i0.ɵɵelementEnd();
|
|
152
|
+
i0.ɵɵelementStart(4, "div", 6);
|
|
153
|
+
i0.ɵɵtext(5);
|
|
154
|
+
i0.ɵɵpipe(6, "number");
|
|
155
|
+
i0.ɵɵelementEnd()();
|
|
156
|
+
i0.ɵɵelementStart(7, "div", 4)(8, "div", 5);
|
|
157
|
+
i0.ɵɵtext(9, "Total Cost");
|
|
158
|
+
i0.ɵɵelementEnd();
|
|
159
|
+
i0.ɵɵelementStart(10, "div", 6);
|
|
160
|
+
i0.ɵɵtext(11);
|
|
161
|
+
i0.ɵɵelementEnd()();
|
|
162
|
+
i0.ɵɵelementStart(12, "div", 7)(13, "div", 5);
|
|
163
|
+
i0.ɵɵtext(14, "Prompt Runs");
|
|
164
|
+
i0.ɵɵelementEnd();
|
|
165
|
+
i0.ɵɵelementStart(15, "div", 6);
|
|
166
|
+
i0.ɵɵtext(16);
|
|
167
|
+
i0.ɵɵpipe(17, "number");
|
|
168
|
+
i0.ɵɵelementEnd()();
|
|
169
|
+
i0.ɵɵelementStart(18, "div", 7)(19, "div", 5);
|
|
170
|
+
i0.ɵɵtext(20, "Avg Cost/Run");
|
|
171
|
+
i0.ɵɵelementEnd();
|
|
172
|
+
i0.ɵɵelementStart(21, "div", 6);
|
|
173
|
+
i0.ɵɵtext(22);
|
|
174
|
+
i0.ɵɵelementEnd()();
|
|
175
|
+
i0.ɵɵelementStart(23, "div", 8)(24, "div", 5);
|
|
176
|
+
i0.ɵɵtext(25, "Success Rate");
|
|
177
|
+
i0.ɵɵelementEnd();
|
|
178
|
+
i0.ɵɵelementStart(26, "div", 6);
|
|
179
|
+
i0.ɵɵtext(27);
|
|
180
|
+
i0.ɵɵpipe(28, "number");
|
|
181
|
+
i0.ɵɵelementEnd()();
|
|
182
|
+
i0.ɵɵelementStart(29, "div", 7)(30, "div", 5);
|
|
183
|
+
i0.ɵɵtext(31, "Avg Duration");
|
|
184
|
+
i0.ɵɵelementEnd();
|
|
185
|
+
i0.ɵɵelementStart(32, "div", 6);
|
|
186
|
+
i0.ɵɵtext(33);
|
|
187
|
+
i0.ɵɵpipe(34, "number");
|
|
188
|
+
i0.ɵɵelementEnd()()();
|
|
189
|
+
i0.ɵɵelementStart(35, "div", 9)(36, "div", 10)(37, "div", 11);
|
|
190
|
+
i0.ɵɵelement(38, "i", 12);
|
|
191
|
+
i0.ɵɵtext(39, " Cost Attribution by Agent ");
|
|
192
|
+
i0.ɵɵelementEnd()();
|
|
193
|
+
i0.ɵɵelementStart(40, "div", 13);
|
|
194
|
+
i0.ɵɵconditionalCreate(41, AnalyticsAgentRunsComponent_Conditional_2_Conditional_41_Template, 2, 0, "div", 14);
|
|
195
|
+
i0.ɵɵrepeaterCreate(42, AnalyticsAgentRunsComponent_Conditional_2_For_43_Template, 8, 3, "div", 15, _forTrack0);
|
|
196
|
+
i0.ɵɵconditionalCreate(44, AnalyticsAgentRunsComponent_Conditional_2_Conditional_44_Template, 3, 0, "div", 16);
|
|
197
|
+
i0.ɵɵelementEnd()();
|
|
198
|
+
i0.ɵɵelementStart(45, "div", 9)(46, "div", 10)(47, "div", 11);
|
|
199
|
+
i0.ɵɵelement(48, "i", 17);
|
|
200
|
+
i0.ɵɵtext(49, " Recent Agent Runs ");
|
|
201
|
+
i0.ɵɵelementEnd();
|
|
202
|
+
i0.ɵɵelementStart(50, "span", 18);
|
|
203
|
+
i0.ɵɵtext(51);
|
|
204
|
+
i0.ɵɵelementEnd()();
|
|
205
|
+
i0.ɵɵelementStart(52, "div", 19)(53, "table", 20)(54, "thead")(55, "tr");
|
|
206
|
+
i0.ɵɵrepeaterCreate(56, AnalyticsAgentRunsComponent_Conditional_2_For_57_Template, 3, 4, "th", 21, _forTrack1);
|
|
207
|
+
i0.ɵɵelementEnd()();
|
|
208
|
+
i0.ɵɵelementStart(58, "tbody");
|
|
209
|
+
i0.ɵɵconditionalCreate(59, AnalyticsAgentRunsComponent_Conditional_2_Conditional_59_Template, 3, 1, "tr");
|
|
210
|
+
i0.ɵɵrepeaterCreate(60, AnalyticsAgentRunsComponent_Conditional_2_For_61_Template, 14, 8, "tr", null, _forTrack2);
|
|
211
|
+
i0.ɵɵelementEnd()()()();
|
|
212
|
+
} if (rf & 2) {
|
|
213
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
214
|
+
i0.ɵɵadvance(5);
|
|
215
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(6, 10, ctx_r1.Stats.TotalRuns));
|
|
216
|
+
i0.ɵɵadvance(6);
|
|
217
|
+
i0.ɵɵtextInterpolate(ctx_r1.FormatCurrency(ctx_r1.Stats.TotalCost));
|
|
218
|
+
i0.ɵɵadvance(5);
|
|
219
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(17, 12, ctx_r1.Stats.PromptRuns));
|
|
220
|
+
i0.ɵɵadvance(6);
|
|
221
|
+
i0.ɵɵtextInterpolate(ctx_r1.FormatCurrency(ctx_r1.Stats.AvgCostPerRun, 4));
|
|
222
|
+
i0.ɵɵadvance(5);
|
|
223
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(28, 14, ctx_r1.Stats.SuccessRate, "1.1-1"), "%");
|
|
224
|
+
i0.ɵɵadvance(6);
|
|
225
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(34, 17, ctx_r1.Stats.AvgDurationSeconds, "1.1-1"), "s");
|
|
226
|
+
i0.ɵɵadvance(8);
|
|
227
|
+
i0.ɵɵconditional(ctx_r1.CostAttributionRows.length === 0 ? 41 : -1);
|
|
228
|
+
i0.ɵɵadvance();
|
|
229
|
+
i0.ɵɵrepeater(ctx_r1.CostAttributionRows);
|
|
230
|
+
i0.ɵɵadvance(2);
|
|
231
|
+
i0.ɵɵconditional(ctx_r1.CostAttributionRows.length > 0 ? 44 : -1);
|
|
232
|
+
i0.ɵɵadvance(7);
|
|
233
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.RecentRuns.length, " runs");
|
|
234
|
+
i0.ɵɵadvance(5);
|
|
235
|
+
i0.ɵɵrepeater(ctx_r1.TableColumns);
|
|
236
|
+
i0.ɵɵadvance(3);
|
|
237
|
+
i0.ɵɵconditional(ctx_r1.RecentRuns.length === 0 ? 59 : -1);
|
|
238
|
+
i0.ɵɵadvance();
|
|
239
|
+
i0.ɵɵrepeater(ctx_r1.RecentRuns);
|
|
240
|
+
} }
|
|
241
|
+
const AGENT_RUN_FIELDS = [
|
|
242
|
+
'ID', 'StartedAt', 'CompletedAt', 'Status', 'Success',
|
|
243
|
+
'TotalCost', 'TotalTokensUsed', 'AgentID', 'Agent', 'ErrorMessage'
|
|
244
|
+
];
|
|
245
|
+
const PROMPT_RUN_FIELDS = [
|
|
246
|
+
'ID', 'AgentRunID', 'Cost', 'TotalCost', 'Model', 'Vendor'
|
|
247
|
+
];
|
|
248
|
+
const COST_COLORS = [
|
|
249
|
+
'var(--mj-brand-primary)',
|
|
250
|
+
'var(--mj-brand-accent, var(--mj-brand-primary-hover))',
|
|
251
|
+
'var(--mj-status-info)',
|
|
252
|
+
'var(--mj-text-disabled)'
|
|
253
|
+
];
|
|
254
|
+
export class AnalyticsAgentRunsComponent {
|
|
255
|
+
TimeRange = '7d';
|
|
256
|
+
Filters = { Agents: [], Statuses: [] };
|
|
257
|
+
TimeRangeChange = new EventEmitter();
|
|
258
|
+
FiltersChange = new EventEmitter();
|
|
259
|
+
cdr = inject(ChangeDetectorRef);
|
|
260
|
+
destroy$ = new Subject();
|
|
261
|
+
IsLoading = false;
|
|
262
|
+
Stats = {
|
|
263
|
+
TotalRuns: 0,
|
|
264
|
+
TotalCost: 0,
|
|
265
|
+
PromptRuns: 0,
|
|
266
|
+
AvgCostPerRun: 0,
|
|
267
|
+
SuccessRate: 0,
|
|
268
|
+
AvgDurationSeconds: 0
|
|
269
|
+
};
|
|
270
|
+
CostAttributionRows = [];
|
|
271
|
+
LegendItems = [];
|
|
272
|
+
RecentRuns = [];
|
|
273
|
+
SortField = 'Time';
|
|
274
|
+
SortDir = 'desc';
|
|
275
|
+
TableColumns = [
|
|
276
|
+
{ field: 'Agent', label: 'Agent' },
|
|
277
|
+
{ field: 'Status', label: 'Status' },
|
|
278
|
+
{ field: 'StepCount', label: 'Steps' },
|
|
279
|
+
{ field: 'Duration', label: 'Duration' },
|
|
280
|
+
{ field: 'Cost', label: 'Cost' },
|
|
281
|
+
{ field: 'Time', label: 'Time' }
|
|
282
|
+
];
|
|
283
|
+
/** Bridge the local filter shape to the global shape the filter bar expects */
|
|
284
|
+
get globalFilters() {
|
|
285
|
+
return {
|
|
286
|
+
Models: [],
|
|
287
|
+
Agents: this.Filters.Agents,
|
|
288
|
+
Prompts: [],
|
|
289
|
+
Statuses: this.Filters.Statuses
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
agentRuns = [];
|
|
293
|
+
promptRuns = [];
|
|
294
|
+
ngOnInit() {
|
|
295
|
+
this.LoadData();
|
|
296
|
+
}
|
|
297
|
+
ngOnDestroy() {
|
|
298
|
+
this.destroy$.next();
|
|
299
|
+
this.destroy$.complete();
|
|
300
|
+
}
|
|
301
|
+
// ── Public Event Handlers ──
|
|
302
|
+
OnTimeRangeChange(range) {
|
|
303
|
+
this.TimeRange = range;
|
|
304
|
+
this.TimeRangeChange.emit(range);
|
|
305
|
+
this.LoadData();
|
|
306
|
+
}
|
|
307
|
+
OnFiltersChange(filters) {
|
|
308
|
+
this.Filters = { Agents: filters.Agents, Statuses: filters.Statuses };
|
|
309
|
+
this.FiltersChange.emit(this.Filters);
|
|
310
|
+
this.LoadData();
|
|
311
|
+
}
|
|
312
|
+
OnSort(field) {
|
|
313
|
+
if (this.SortField === field) {
|
|
314
|
+
this.SortDir = this.SortDir === 'asc' ? 'desc' : 'asc';
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
this.SortField = field;
|
|
318
|
+
this.SortDir = field === 'Time' ? 'desc' : 'asc';
|
|
319
|
+
}
|
|
320
|
+
this.sortRecentRuns();
|
|
321
|
+
this.cdr.detectChanges();
|
|
322
|
+
}
|
|
323
|
+
FormatCurrency(value, decimals = 2) {
|
|
324
|
+
if (value === 0)
|
|
325
|
+
return '$0.00';
|
|
326
|
+
if (value < 0.01 && decimals < 4)
|
|
327
|
+
decimals = 4;
|
|
328
|
+
return '$' + value.toFixed(decimals);
|
|
329
|
+
}
|
|
330
|
+
// ── Data Loading ──
|
|
331
|
+
async LoadData() {
|
|
332
|
+
this.IsLoading = true;
|
|
333
|
+
this.cdr.detectChanges();
|
|
334
|
+
try {
|
|
335
|
+
const rv = new RunView();
|
|
336
|
+
const dateFilter = this.buildDateFilter('StartedAt');
|
|
337
|
+
const agentFilter = this.buildAgentFilter();
|
|
338
|
+
const statusFilter = this.buildStatusFilter();
|
|
339
|
+
const extraFilter = [dateFilter, agentFilter, statusFilter].filter(Boolean).join(' AND ');
|
|
340
|
+
const promptDateFilter = this.buildDateFilter('RunAt');
|
|
341
|
+
const [agentResult, promptResult] = await rv.RunViews([
|
|
342
|
+
{
|
|
343
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
344
|
+
ExtraFilter: extraFilter,
|
|
345
|
+
Fields: AGENT_RUN_FIELDS,
|
|
346
|
+
OrderBy: 'StartedAt DESC',
|
|
347
|
+
ResultType: 'simple'
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
EntityName: 'MJ: AI Prompt Runs',
|
|
351
|
+
ExtraFilter: promptDateFilter,
|
|
352
|
+
Fields: PROMPT_RUN_FIELDS,
|
|
353
|
+
OrderBy: 'RunAt DESC',
|
|
354
|
+
ResultType: 'simple'
|
|
355
|
+
}
|
|
356
|
+
]);
|
|
357
|
+
this.agentRuns = (agentResult?.Results ?? []);
|
|
358
|
+
this.promptRuns = (promptResult?.Results ?? []);
|
|
359
|
+
this.computeStats();
|
|
360
|
+
this.computeCostAttribution();
|
|
361
|
+
this.buildRecentRuns();
|
|
362
|
+
this.sortRecentRuns();
|
|
363
|
+
}
|
|
364
|
+
catch (e) {
|
|
365
|
+
console.error('Agent Run Analysis load error:', e);
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
this.IsLoading = false;
|
|
369
|
+
this.cdr.detectChanges();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// ── Computations ──
|
|
373
|
+
computeStats() {
|
|
374
|
+
const runs = this.agentRuns;
|
|
375
|
+
const total = runs.length;
|
|
376
|
+
const totalCost = runs.reduce((s, r) => s + (r.TotalCost ?? 0), 0);
|
|
377
|
+
const completed = runs.filter(r => r.Status === 'Completed');
|
|
378
|
+
const successCount = runs.filter(r => r.Success === true).length;
|
|
379
|
+
const durations = completed
|
|
380
|
+
.filter(r => r.CompletedAt)
|
|
381
|
+
.map(r => {
|
|
382
|
+
const start = new Date(r.StartedAt).getTime();
|
|
383
|
+
const end = new Date(r.CompletedAt).getTime();
|
|
384
|
+
return (end - start) / 1000;
|
|
385
|
+
})
|
|
386
|
+
.filter(d => d > 0);
|
|
387
|
+
const avgDuration = durations.length > 0
|
|
388
|
+
? durations.reduce((s, d) => s + d, 0) / durations.length
|
|
389
|
+
: 0;
|
|
390
|
+
const linkedPromptRuns = this.promptRuns.filter(p => p.AgentRunID != null && this.agentRunIdSet.has(p.AgentRunID));
|
|
391
|
+
this.Stats = {
|
|
392
|
+
TotalRuns: total,
|
|
393
|
+
TotalCost: totalCost,
|
|
394
|
+
PromptRuns: linkedPromptRuns.length,
|
|
395
|
+
AvgCostPerRun: total > 0 ? totalCost / total : 0,
|
|
396
|
+
SuccessRate: total > 0 ? (successCount / total) * 100 : 0,
|
|
397
|
+
AvgDurationSeconds: avgDuration
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
get agentRunIdSet() {
|
|
401
|
+
return new Set(this.agentRuns.map(r => r.ID));
|
|
402
|
+
}
|
|
403
|
+
computeCostAttribution() {
|
|
404
|
+
const agentCostMap = new Map();
|
|
405
|
+
// Group prompt runs by agent run, then by vendor
|
|
406
|
+
for (const pr of this.promptRuns) {
|
|
407
|
+
if (!pr.AgentRunID)
|
|
408
|
+
continue;
|
|
409
|
+
const agentRun = this.agentRuns.find(ar => UUIDsEqual(ar.ID, pr.AgentRunID));
|
|
410
|
+
if (!agentRun)
|
|
411
|
+
continue;
|
|
412
|
+
const agentKey = agentRun.AgentID;
|
|
413
|
+
if (!agentCostMap.has(agentKey)) {
|
|
414
|
+
agentCostMap.set(agentKey, {
|
|
415
|
+
name: agentRun.Agent ?? 'Unknown',
|
|
416
|
+
vendorCosts: new Map(),
|
|
417
|
+
totalCost: 0
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
const entry = agentCostMap.get(agentKey);
|
|
421
|
+
const vendor = pr.Vendor ?? 'Other';
|
|
422
|
+
const cost = pr.Cost ?? pr.TotalCost ?? 0;
|
|
423
|
+
entry.vendorCosts.set(vendor, (entry.vendorCosts.get(vendor) ?? 0) + cost);
|
|
424
|
+
entry.totalCost += cost;
|
|
425
|
+
}
|
|
426
|
+
// Collect all vendors for consistent coloring
|
|
427
|
+
const allVendors = new Set();
|
|
428
|
+
for (const entry of agentCostMap.values()) {
|
|
429
|
+
for (const v of entry.vendorCosts.keys()) {
|
|
430
|
+
allVendors.add(v);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const vendorList = Array.from(allVendors);
|
|
434
|
+
// Build legend
|
|
435
|
+
this.LegendItems = vendorList.map((v, i) => ({
|
|
436
|
+
Label: v,
|
|
437
|
+
Color: COST_COLORS[i % COST_COLORS.length]
|
|
438
|
+
}));
|
|
439
|
+
// Sort by total cost descending
|
|
440
|
+
const sorted = Array.from(agentCostMap.entries())
|
|
441
|
+
.sort((a, b) => b[1].totalCost - a[1].totalCost);
|
|
442
|
+
this.CostAttributionRows = sorted.map(([agentId, entry]) => {
|
|
443
|
+
const segments = vendorList.map((vendor, i) => {
|
|
444
|
+
const val = entry.vendorCosts.get(vendor) ?? 0;
|
|
445
|
+
return {
|
|
446
|
+
Label: vendor,
|
|
447
|
+
Value: val,
|
|
448
|
+
Percent: entry.totalCost > 0 ? (val / entry.totalCost) * 100 : 0,
|
|
449
|
+
Color: COST_COLORS[i % COST_COLORS.length]
|
|
450
|
+
};
|
|
451
|
+
}).filter(s => s.Value > 0);
|
|
452
|
+
return {
|
|
453
|
+
AgentName: entry.name,
|
|
454
|
+
AgentID: agentId,
|
|
455
|
+
TotalCost: entry.totalCost,
|
|
456
|
+
Segments: segments
|
|
457
|
+
};
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
buildRecentRuns() {
|
|
461
|
+
// Count prompt runs per agent run
|
|
462
|
+
const promptCountMap = new Map();
|
|
463
|
+
for (const pr of this.promptRuns) {
|
|
464
|
+
if (pr.AgentRunID) {
|
|
465
|
+
promptCountMap.set(pr.AgentRunID, (promptCountMap.get(pr.AgentRunID) ?? 0) + 1);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
this.RecentRuns = this.agentRuns.slice(0, 100).map(r => ({
|
|
469
|
+
ID: r.ID,
|
|
470
|
+
Agent: r.Agent ?? 'Unknown',
|
|
471
|
+
Status: r.Status,
|
|
472
|
+
StatusClass: this.getStatusClass(r.Status),
|
|
473
|
+
StepCount: promptCountMap.get(r.ID) ?? 0,
|
|
474
|
+
Duration: this.formatDuration(r.StartedAt, r.CompletedAt),
|
|
475
|
+
Cost: this.FormatCurrency(r.TotalCost ?? 0),
|
|
476
|
+
Time: this.formatRelativeTime(r.StartedAt)
|
|
477
|
+
}));
|
|
478
|
+
}
|
|
479
|
+
sortRecentRuns() {
|
|
480
|
+
const dir = this.SortDir === 'asc' ? 1 : -1;
|
|
481
|
+
this.RecentRuns.sort((a, b) => {
|
|
482
|
+
switch (this.SortField) {
|
|
483
|
+
case 'Agent': return dir * a.Agent.localeCompare(b.Agent);
|
|
484
|
+
case 'Status': return dir * a.Status.localeCompare(b.Status);
|
|
485
|
+
case 'StepCount': return dir * (a.StepCount - b.StepCount);
|
|
486
|
+
case 'Duration': return dir * a.Duration.localeCompare(b.Duration);
|
|
487
|
+
case 'Cost': return dir * a.Cost.localeCompare(b.Cost);
|
|
488
|
+
case 'Time': return dir * a.Time.localeCompare(b.Time);
|
|
489
|
+
default: return 0;
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
// ── Helpers ──
|
|
494
|
+
buildDateFilter(field) {
|
|
495
|
+
const now = new Date();
|
|
496
|
+
const ms = this.timeRangeToMs(this.TimeRange);
|
|
497
|
+
const start = new Date(now.getTime() - ms);
|
|
498
|
+
return `${field} >= '${start.toISOString()}'`;
|
|
499
|
+
}
|
|
500
|
+
buildAgentFilter() {
|
|
501
|
+
if (this.Filters.Agents.length === 0)
|
|
502
|
+
return '';
|
|
503
|
+
const ids = this.Filters.Agents.map(id => `'${id}'`).join(',');
|
|
504
|
+
return `AgentID IN (${ids})`;
|
|
505
|
+
}
|
|
506
|
+
buildStatusFilter() {
|
|
507
|
+
if (this.Filters.Statuses.length === 0)
|
|
508
|
+
return '';
|
|
509
|
+
const values = this.Filters.Statuses.map(s => `'${s}'`).join(',');
|
|
510
|
+
return `Status IN (${values})`;
|
|
511
|
+
}
|
|
512
|
+
timeRangeToMs(range) {
|
|
513
|
+
const map = {
|
|
514
|
+
'1h': 3600000,
|
|
515
|
+
'6h': 21600000,
|
|
516
|
+
'24h': 86400000,
|
|
517
|
+
'7d': 604800000,
|
|
518
|
+
'30d': 2592000000
|
|
519
|
+
};
|
|
520
|
+
return map[range] ?? 604800000;
|
|
521
|
+
}
|
|
522
|
+
getStatusClass(status) {
|
|
523
|
+
return 'status-pill status-' + status.toLowerCase().replace(/\s+/g, '');
|
|
524
|
+
}
|
|
525
|
+
formatDuration(startStr, endStr) {
|
|
526
|
+
if (!endStr)
|
|
527
|
+
return '--';
|
|
528
|
+
const ms = new Date(endStr).getTime() - new Date(startStr).getTime();
|
|
529
|
+
if (ms < 1000)
|
|
530
|
+
return ms + 'ms';
|
|
531
|
+
if (ms < 60000)
|
|
532
|
+
return (ms / 1000).toFixed(1) + 's';
|
|
533
|
+
return (ms / 60000).toFixed(1) + 'm';
|
|
534
|
+
}
|
|
535
|
+
formatRelativeTime(dateStr) {
|
|
536
|
+
const now = Date.now();
|
|
537
|
+
const then = new Date(dateStr).getTime();
|
|
538
|
+
const diffMs = now - then;
|
|
539
|
+
const diffMin = Math.floor(diffMs / 60000);
|
|
540
|
+
if (diffMin < 1)
|
|
541
|
+
return 'just now';
|
|
542
|
+
if (diffMin < 60)
|
|
543
|
+
return diffMin + 'm ago';
|
|
544
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
545
|
+
if (diffHr < 24)
|
|
546
|
+
return diffHr + 'h ago';
|
|
547
|
+
const diffDay = Math.floor(diffHr / 24);
|
|
548
|
+
return diffDay + 'd ago';
|
|
549
|
+
}
|
|
550
|
+
static ɵfac = function AnalyticsAgentRunsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnalyticsAgentRunsComponent)(); };
|
|
551
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsAgentRunsComponent, selectors: [["app-analytics-agent-runs"]], inputs: { TimeRange: "TimeRange", Filters: "Filters" }, outputs: { TimeRangeChange: "TimeRangeChange", FiltersChange: "FiltersChange" }, standalone: false, decls: 3, vars: 9, consts: [[3, "TimeRangeChange", "FiltersChange", "TimeRange", "Filters", "ShowModelFilter", "ShowPromptFilter", "ShowAgentFilter", "ShowStatusFilter", "ShowCompareToggle", "ShowExportButton"], [1, "loading-container"], ["text", "Loading agent runs..."], [1, "stats-grid"], [1, "stat-card", "accent-brand"], [1, "stat-label"], [1, "stat-value"], [1, "stat-card"], [1, "stat-card", "accent-success"], [1, "panel"], [1, "panel-header"], [1, "panel-header__title"], [1, "fa-solid", "fa-chart-bar", "panel-header__icon"], [1, "panel-body"], [1, "panel-empty"], [1, "attribution-row"], [1, "legend-row"], [1, "fa-solid", "fa-list", "panel-header__icon"], [1, "panel-header__subtitle"], [1, "table-wrapper"], [1, "data-table"], [1, "sortable-header", 3, "sorted"], [1, "attribution-name", 3, "title"], [1, "attribution-bar-container"], [1, "attribution-segment", 3, "width", "background", "title"], [1, "attribution-total"], [1, "attribution-segment", 3, "title"], [1, "legend-item"], [1, "legend-swatch"], [1, "sortable-header", 3, "click"], [3, "class"], [1, "empty-row"], [1, "cell-agent"], [1, "status-pill"], [1, "cell-numeric"], [1, "cell-time"]], template: function AnalyticsAgentRunsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
552
|
+
i0.ɵɵelementStart(0, "app-analytics-filter-bar", 0);
|
|
553
|
+
i0.ɵɵlistener("TimeRangeChange", function AnalyticsAgentRunsComponent_Template_app_analytics_filter_bar_TimeRangeChange_0_listener($event) { return ctx.OnTimeRangeChange($event); })("FiltersChange", function AnalyticsAgentRunsComponent_Template_app_analytics_filter_bar_FiltersChange_0_listener($event) { return ctx.OnFiltersChange($event); });
|
|
554
|
+
i0.ɵɵelementEnd();
|
|
555
|
+
i0.ɵɵconditionalCreate(1, AnalyticsAgentRunsComponent_Conditional_1_Template, 2, 0, "div", 1)(2, AnalyticsAgentRunsComponent_Conditional_2_Template, 62, 20);
|
|
556
|
+
} if (rf & 2) {
|
|
557
|
+
i0.ɵɵproperty("TimeRange", ctx.TimeRange)("Filters", ctx.globalFilters)("ShowModelFilter", false)("ShowPromptFilter", false)("ShowAgentFilter", true)("ShowStatusFilter", true)("ShowCompareToggle", false)("ShowExportButton", false);
|
|
558
|
+
i0.ɵɵadvance();
|
|
559
|
+
i0.ɵɵconditional(ctx.IsLoading ? 1 : 2);
|
|
560
|
+
} }, dependencies: [i1.LoadingComponent, i2.AnalyticsFilterBarComponent, i3.DecimalPipe], styles: ["[_nghost-%COMP%] { display: block; }\n\n .loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n \n\n .stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .stat-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 16px;\n text-align: center;\n border-top: 3px solid var(--mj-border-subtle);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n\n .stat-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .stat-card.accent-brand[_ngcontent-%COMP%] { border-top-color: var(--mj-brand-primary); }\n .stat-card.accent-success[_ngcontent-%COMP%] { border-top-color: var(--mj-status-success); }\n .stat-card.accent-warning[_ngcontent-%COMP%] { border-top-color: var(--mj-status-warning); }\n\n .stat-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em;\n }\n\n \n\n .panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n margin-bottom: 16px;\n overflow: hidden;\n }\n\n .panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .panel-header__title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .panel-header__icon[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-brand-primary);\n }\n\n .panel-header__subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n\n .panel-body[_ngcontent-%COMP%] {\n padding: 16px 18px;\n }\n\n .panel-empty[_ngcontent-%COMP%] {\n text-align: center;\n padding: 24px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n \n\n .attribution-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .attribution-row[_ngcontent-%COMP%]:last-of-type {\n border-bottom: none;\n }\n\n .attribution-name[_ngcontent-%COMP%] {\n width: 140px;\n min-width: 140px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .attribution-bar-container[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n }\n\n .attribution-segment[_ngcontent-%COMP%] {\n height: 100%;\n min-width: 2px;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .attribution-total[_ngcontent-%COMP%] {\n width: 80px;\n min-width: 80px;\n text-align: right;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n }\n\n .legend-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n padding: 12px 0 4px;\n flex-wrap: wrap;\n }\n\n .legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n }\n\n .legend-swatch[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n flex-shrink: 0;\n }\n\n \n\n .table-wrapper[_ngcontent-%COMP%] {\n overflow-x: auto;\n }\n\n .data-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n }\n\n .data-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%], \n .data-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 10px 14px;\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .data-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n background: var(--mj-bg-surface-card);\n position: sticky;\n top: 0;\n }\n\n .sortable-header[_ngcontent-%COMP%] {\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n transition: color 0.15s;\n }\n\n .sortable-header[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n }\n\n .sortable-header.sorted[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n }\n\n .sortable-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-left: 4px;\n font-size: 10px;\n }\n\n .data-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n transition: background 0.15s;\n }\n\n .data-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .cell-agent[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n max-width: 200px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .cell-numeric[_ngcontent-%COMP%] {\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .cell-time[_ngcontent-%COMP%] {\n white-space: nowrap;\n color: var(--mj-text-muted);\n font-size: 12px;\n }\n\n .empty-row[_ngcontent-%COMP%] {\n text-align: center;\n color: var(--mj-text-disabled);\n padding: 24px;\n }\n\n \n\n .status-pill[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.3px;\n }\n\n .status-completed[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .status-running[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .status-failed[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .status-cancelled[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .status-paused[_ngcontent-%COMP%], .status-awaitingfeedback[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-text-disabled) 12%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n }\n\n \n\n @media (max-width: 1200px) {\n .stats-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n }\n }\n\n @media (max-width: 768px) {\n .stats-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .attribution-name[_ngcontent-%COMP%] {\n width: 100px;\n min-width: 100px;\n }\n\n .attribution-total[_ngcontent-%COMP%] {\n width: 60px;\n min-width: 60px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n }"] });
|
|
561
|
+
}
|
|
562
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AnalyticsAgentRunsComponent, [{
|
|
563
|
+
type: Component,
|
|
564
|
+
args: [{ standalone: false, selector: 'app-analytics-agent-runs', template: `
|
|
565
|
+
<!-- Filter Bar -->
|
|
566
|
+
<app-analytics-filter-bar
|
|
567
|
+
[TimeRange]="TimeRange"
|
|
568
|
+
[Filters]="globalFilters"
|
|
569
|
+
[ShowModelFilter]="false"
|
|
570
|
+
[ShowPromptFilter]="false"
|
|
571
|
+
[ShowAgentFilter]="true"
|
|
572
|
+
[ShowStatusFilter]="true"
|
|
573
|
+
[ShowCompareToggle]="false"
|
|
574
|
+
[ShowExportButton]="false"
|
|
575
|
+
(TimeRangeChange)="OnTimeRangeChange($event)"
|
|
576
|
+
(FiltersChange)="OnFiltersChange($event)"
|
|
577
|
+
></app-analytics-filter-bar>
|
|
578
|
+
|
|
579
|
+
@if (IsLoading) {
|
|
580
|
+
<div class="loading-container">
|
|
581
|
+
<mj-loading text="Loading agent runs..."></mj-loading>
|
|
582
|
+
</div>
|
|
583
|
+
} @else {
|
|
584
|
+
<!-- Stats Bar -->
|
|
585
|
+
<div class="stats-grid">
|
|
586
|
+
<div class="stat-card accent-brand">
|
|
587
|
+
<div class="stat-label">Total Runs</div>
|
|
588
|
+
<div class="stat-value">{{ Stats.TotalRuns | number }}</div>
|
|
589
|
+
</div>
|
|
590
|
+
<div class="stat-card accent-brand">
|
|
591
|
+
<div class="stat-label">Total Cost</div>
|
|
592
|
+
<div class="stat-value">{{ FormatCurrency(Stats.TotalCost) }}</div>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="stat-card">
|
|
595
|
+
<div class="stat-label">Prompt Runs</div>
|
|
596
|
+
<div class="stat-value">{{ Stats.PromptRuns | number }}</div>
|
|
597
|
+
</div>
|
|
598
|
+
<div class="stat-card">
|
|
599
|
+
<div class="stat-label">Avg Cost/Run</div>
|
|
600
|
+
<div class="stat-value">{{ FormatCurrency(Stats.AvgCostPerRun, 4) }}</div>
|
|
601
|
+
</div>
|
|
602
|
+
<div class="stat-card accent-success">
|
|
603
|
+
<div class="stat-label">Success Rate</div>
|
|
604
|
+
<div class="stat-value">{{ Stats.SuccessRate | number:'1.1-1' }}%</div>
|
|
605
|
+
</div>
|
|
606
|
+
<div class="stat-card">
|
|
607
|
+
<div class="stat-label">Avg Duration</div>
|
|
608
|
+
<div class="stat-value">{{ Stats.AvgDurationSeconds | number:'1.1-1' }}s</div>
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
611
|
+
|
|
612
|
+
<!-- Cost Attribution Panel -->
|
|
613
|
+
<div class="panel">
|
|
614
|
+
<div class="panel-header">
|
|
615
|
+
<div class="panel-header__title">
|
|
616
|
+
<i class="fa-solid fa-chart-bar panel-header__icon"></i>
|
|
617
|
+
Cost Attribution by Agent
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
<div class="panel-body">
|
|
621
|
+
@if (CostAttributionRows.length === 0) {
|
|
622
|
+
<div class="panel-empty">No agent cost data for selected period</div>
|
|
623
|
+
}
|
|
624
|
+
@for (row of CostAttributionRows; track row.AgentID) {
|
|
625
|
+
<div class="attribution-row">
|
|
626
|
+
<div class="attribution-name" [title]="row.AgentName">{{ row.AgentName }}</div>
|
|
627
|
+
<div class="attribution-bar-container">
|
|
628
|
+
@for (seg of row.Segments; track seg.Label) {
|
|
629
|
+
<div
|
|
630
|
+
class="attribution-segment"
|
|
631
|
+
[style.width.%]="seg.Percent"
|
|
632
|
+
[style.background]="seg.Color"
|
|
633
|
+
[title]="seg.Label + ': ' + FormatCurrency(seg.Value, 4)"
|
|
634
|
+
></div>
|
|
635
|
+
}
|
|
636
|
+
</div>
|
|
637
|
+
<div class="attribution-total">{{ FormatCurrency(row.TotalCost) }}</div>
|
|
638
|
+
</div>
|
|
639
|
+
}
|
|
640
|
+
@if (CostAttributionRows.length > 0) {
|
|
641
|
+
<div class="legend-row">
|
|
642
|
+
@for (item of LegendItems; track item.Label) {
|
|
643
|
+
<div class="legend-item">
|
|
644
|
+
<span class="legend-swatch" [style.background]="item.Color"></span>
|
|
645
|
+
{{ item.Label }}
|
|
646
|
+
</div>
|
|
647
|
+
}
|
|
648
|
+
</div>
|
|
649
|
+
}
|
|
650
|
+
</div>
|
|
651
|
+
</div>
|
|
652
|
+
|
|
653
|
+
<!-- Recent Agent Runs Table -->
|
|
654
|
+
<div class="panel">
|
|
655
|
+
<div class="panel-header">
|
|
656
|
+
<div class="panel-header__title">
|
|
657
|
+
<i class="fa-solid fa-list panel-header__icon"></i>
|
|
658
|
+
Recent Agent Runs
|
|
659
|
+
</div>
|
|
660
|
+
<span class="panel-header__subtitle">{{ RecentRuns.length }} runs</span>
|
|
661
|
+
</div>
|
|
662
|
+
<div class="table-wrapper">
|
|
663
|
+
<table class="data-table">
|
|
664
|
+
<thead>
|
|
665
|
+
<tr>
|
|
666
|
+
@for (col of TableColumns; track col.field) {
|
|
667
|
+
<th
|
|
668
|
+
class="sortable-header"
|
|
669
|
+
[class.sorted]="SortField === col.field"
|
|
670
|
+
(click)="OnSort(col.field)">
|
|
671
|
+
{{ col.label }}
|
|
672
|
+
@if (SortField === col.field) {
|
|
673
|
+
<i [class]="SortDir === 'asc' ? 'fa-solid fa-caret-up' : 'fa-solid fa-caret-down'"></i>
|
|
674
|
+
}
|
|
675
|
+
</th>
|
|
676
|
+
}
|
|
677
|
+
</tr>
|
|
678
|
+
</thead>
|
|
679
|
+
<tbody>
|
|
680
|
+
@if (RecentRuns.length === 0) {
|
|
681
|
+
<tr><td [attr.colspan]="TableColumns.length" class="empty-row">No runs found</td></tr>
|
|
682
|
+
}
|
|
683
|
+
@for (run of RecentRuns; track run.ID) {
|
|
684
|
+
<tr>
|
|
685
|
+
<td class="cell-agent">{{ run.Agent }}</td>
|
|
686
|
+
<td><span class="status-pill" [class]="run.StatusClass">{{ run.Status }}</span></td>
|
|
687
|
+
<td class="cell-numeric">{{ run.StepCount }}</td>
|
|
688
|
+
<td class="cell-numeric">{{ run.Duration }}</td>
|
|
689
|
+
<td class="cell-numeric">{{ run.Cost }}</td>
|
|
690
|
+
<td class="cell-time">{{ run.Time }}</td>
|
|
691
|
+
</tr>
|
|
692
|
+
}
|
|
693
|
+
</tbody>
|
|
694
|
+
</table>
|
|
695
|
+
</div>
|
|
696
|
+
</div>
|
|
697
|
+
}
|
|
698
|
+
`, styles: ["\n :host { display: block; }\n\n .loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n /* \u2500\u2500 Stats Grid \u2500\u2500 */\n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .stat-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 16px;\n text-align: center;\n border-top: 3px solid var(--mj-border-subtle);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n\n .stat-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .stat-card.accent-brand { border-top-color: var(--mj-brand-primary); }\n .stat-card.accent-success { border-top-color: var(--mj-status-success); }\n .stat-card.accent-warning { border-top-color: var(--mj-status-warning); }\n\n .stat-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em;\n }\n\n /* \u2500\u2500 Panel \u2500\u2500 */\n .panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n margin-bottom: 16px;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .panel-header__title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .panel-header__icon {\n font-size: 13px;\n color: var(--mj-brand-primary);\n }\n\n .panel-header__subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n\n .panel-body {\n padding: 16px 18px;\n }\n\n .panel-empty {\n text-align: center;\n padding: 24px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n /* \u2500\u2500 Cost Attribution \u2500\u2500 */\n .attribution-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .attribution-row:last-of-type {\n border-bottom: none;\n }\n\n .attribution-name {\n width: 140px;\n min-width: 140px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .attribution-bar-container {\n flex: 1;\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n }\n\n .attribution-segment {\n height: 100%;\n min-width: 2px;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .attribution-total {\n width: 80px;\n min-width: 80px;\n text-align: right;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n }\n\n .legend-row {\n display: flex;\n gap: 16px;\n padding: 12px 0 4px;\n flex-wrap: wrap;\n }\n\n .legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n }\n\n .legend-swatch {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n flex-shrink: 0;\n }\n\n /* \u2500\u2500 Table \u2500\u2500 */\n .table-wrapper {\n overflow-x: auto;\n }\n\n .data-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n }\n\n .data-table th,\n .data-table td {\n padding: 10px 14px;\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .data-table th {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n background: var(--mj-bg-surface-card);\n position: sticky;\n top: 0;\n }\n\n .sortable-header {\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n transition: color 0.15s;\n }\n\n .sortable-header:hover {\n color: var(--mj-brand-primary);\n }\n\n .sortable-header.sorted {\n color: var(--mj-brand-primary);\n }\n\n .sortable-header i {\n margin-left: 4px;\n font-size: 10px;\n }\n\n .data-table tbody tr {\n transition: background 0.15s;\n }\n\n .data-table tbody tr:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .cell-agent {\n font-weight: 500;\n color: var(--mj-text-primary);\n max-width: 200px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .cell-numeric {\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .cell-time {\n white-space: nowrap;\n color: var(--mj-text-muted);\n font-size: 12px;\n }\n\n .empty-row {\n text-align: center;\n color: var(--mj-text-disabled);\n padding: 24px;\n }\n\n /* \u2500\u2500 Status Pills \u2500\u2500 */\n .status-pill {\n display: inline-block;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.3px;\n }\n\n .status-completed {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .status-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .status-failed {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .status-cancelled {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .status-paused, .status-awaitingfeedback {\n background: color-mix(in srgb, var(--mj-text-disabled) 12%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n }\n\n /* \u2500\u2500 Responsive \u2500\u2500 */\n @media (max-width: 1200px) {\n .stats-grid {\n grid-template-columns: repeat(3, 1fr);\n }\n }\n\n @media (max-width: 768px) {\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .attribution-name {\n width: 100px;\n min-width: 100px;\n }\n\n .attribution-total {\n width: 60px;\n min-width: 60px;\n }\n\n .stat-value {\n font-size: 18px;\n }\n }\n "] }]
|
|
699
|
+
}], null, { TimeRange: [{
|
|
700
|
+
type: Input
|
|
701
|
+
}], Filters: [{
|
|
702
|
+
type: Input
|
|
703
|
+
}], TimeRangeChange: [{
|
|
704
|
+
type: Output
|
|
705
|
+
}], FiltersChange: [{
|
|
706
|
+
type: Output
|
|
707
|
+
}] }); })();
|
|
708
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsAgentRunsComponent, { className: "AnalyticsAgentRunsComponent", filePath: "src/AI/components/analytics/agent-runs/agent-run-analysis.component.ts", lineNumber: 556 }); })();
|
|
709
|
+
export function LoadAnalyticsAgentRuns() { }
|
|
710
|
+
//# sourceMappingURL=agent-run-analysis.component.js.map
|