@memberjunction/ng-record-process-studio 6.2.0-edge.1 → 6.2.0-edge.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,70 +10,103 @@ import { CommonModule } from '@angular/common';
10
10
  import { FormsModule } from '@angular/forms';
11
11
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
12
12
  import { LogError, RunView } from '@memberjunction/core';
13
- import { renderConstraintBlock, validateSpec, } from '@memberjunction/feature-pipelines';
14
- import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
15
- import { MJButtonDirective } from '@memberjunction/ng-ui-components';
13
+ import { KnowledgeHubMetadataEngine, } from '@memberjunction/core-entities';
14
+ import { renderConstraintBlock, validateSpec, GetFeaturePipelineCapabilities, ValidateOutputsAgainstCapabilities, FindEscalationTargetRowProblem, FindEscalationTargetSpecProblem, } from '@memberjunction/feature-pipelines';
15
+ import { EscapeSQLString, SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
16
+ import { MJButtonDirective, MJConfirmDialogComponent } from '@memberjunction/ng-ui-components';
16
17
  import * as i0 from "@angular/core";
17
18
  import * as i1 from "@angular/forms";
18
- const _forTrack0 = ($index, $item) => $item.ID;
19
- const _forTrack1 = ($index, $item) => $item.Name;
20
- function FeaturePipelineBuilderComponent_Conditional_20_For_7_Template(rf, ctx) { if (rf & 1) {
21
- i0.ɵɵelementStart(0, "option", 14);
19
+ const _forTrack0 = ($index, $item) => $item.Name;
20
+ const _forTrack1 = ($index, $item) => $item.ID;
21
+ const _forTrack2 = ($index, $item) => $item.Value;
22
+ function FeaturePipelineBuilderComponent_For_8_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelementStart(0, "option", 5);
22
24
  i0.ɵɵtext(1);
23
25
  i0.ɵɵelementEnd();
24
26
  } if (rf & 2) {
25
- const doc_r3 = ctx.$implicit;
26
- i0.ɵɵproperty("value", doc_r3.ID);
27
+ const t_r1 = ctx.$implicit;
28
+ const ctx_r1 = i0.ɵɵnextContext();
29
+ i0.ɵɵproperty("value", t_r1.Name)("selected", ctx_r1.IsCurrentPipelineType(t_r1.Name));
30
+ i0.ɵɵadvance();
31
+ i0.ɵɵtextInterpolate(t_r1.DisplayName || t_r1.Name);
32
+ } }
33
+ function FeaturePipelineBuilderComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
34
+ const _r3 = i0.ɵɵgetCurrentView();
35
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
36
+ i0.ɵɵtext(3, "Capture Reasoning");
37
+ i0.ɵɵelementEnd();
38
+ i0.ɵɵelementStart(4, "select", 36);
39
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_14_Template_select_change_4_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.UpdateCaptureReasoning($event)); });
40
+ i0.ɵɵelementStart(5, "option", 30);
41
+ i0.ɵɵtext(6, "Yes \u2014 Keep the model's rationale with each Feature Value");
42
+ i0.ɵɵelementEnd();
43
+ i0.ɵɵelementStart(7, "option", 31);
44
+ i0.ɵɵtext(8, "No");
45
+ i0.ɵɵelementEnd()()()();
46
+ } if (rf & 2) {
47
+ const ctx_r1 = i0.ɵɵnextContext();
48
+ i0.ɵɵadvance(4);
49
+ i0.ɵɵproperty("value", ctx_r1.spec.CaptureReasoning ? "true" : "false");
50
+ } }
51
+ function FeaturePipelineBuilderComponent_Conditional_34_For_7_Template(rf, ctx) { if (rf & 1) {
52
+ i0.ɵɵelementStart(0, "option", 5);
53
+ i0.ɵɵtext(1);
54
+ i0.ɵɵelementEnd();
55
+ } if (rf & 2) {
56
+ const doc_r5 = ctx.$implicit;
57
+ const ctx_r1 = i0.ɵɵnextContext(2);
58
+ i0.ɵɵproperty("value", doc_r5.ID)("selected", ctx_r1.IsSavedEntityDoc(doc_r5));
27
59
  i0.ɵɵadvance();
28
- i0.ɵɵtextInterpolate(doc_r3.Name);
60
+ i0.ɵɵtextInterpolate(doc_r5.Name);
29
61
  } }
30
- function FeaturePipelineBuilderComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
31
- const _r1 = i0.ɵɵgetCurrentView();
32
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
62
+ function FeaturePipelineBuilderComponent_Conditional_34_Template(rf, ctx) { if (rf & 1) {
63
+ const _r4 = i0.ɵɵgetCurrentView();
64
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
33
65
  i0.ɵɵtext(2, "Entity Document");
34
66
  i0.ɵɵelementEnd();
35
- i0.ɵɵelementStart(3, "select", 7);
36
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_20_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityDocChange($event)); });
37
- i0.ɵɵelementStart(4, "option", 13);
67
+ i0.ɵɵelementStart(3, "select", 4);
68
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_34_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityDocChange($event)); });
69
+ i0.ɵɵelementStart(4, "option", 18);
38
70
  i0.ɵɵtext(5, "\u2014 Select Entity Document \u2014");
39
71
  i0.ɵɵelementEnd();
40
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_20_For_7_Template, 2, 2, "option", 14, _forTrack0);
72
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_34_For_7_Template, 2, 3, "option", 5, _forTrack1);
41
73
  i0.ɵɵelementEnd()();
42
74
  } if (rf & 2) {
43
75
  const ctx_r1 = i0.ɵɵnextContext();
44
- i0.ɵɵadvance(3);
45
- i0.ɵɵproperty("value", ctx_r1.spec.Context.EntityDocumentID || "");
46
- i0.ɵɵadvance(3);
76
+ i0.ɵɵadvance(4);
77
+ i0.ɵɵproperty("selected", !ctx_r1.SavedEntityDocListed);
78
+ i0.ɵɵadvance(2);
47
79
  i0.ɵɵrepeater(ctx_r1.availableDocs);
48
80
  } }
49
- function FeaturePipelineBuilderComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
50
- const _r4 = i0.ɵɵgetCurrentView();
51
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
81
+ function FeaturePipelineBuilderComponent_Conditional_35_Template(rf, ctx) { if (rf & 1) {
82
+ const _r6 = i0.ɵɵgetCurrentView();
83
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
52
84
  i0.ɵɵtext(2, "Query ID");
53
85
  i0.ɵɵelementEnd();
54
- i0.ɵɵelementStart(3, "input", 29);
55
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_21_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQueryIDChange($event)); });
86
+ i0.ɵɵelementStart(3, "input", 37);
87
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_35_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQueryIDChange($event)); });
56
88
  i0.ɵɵelementEnd()();
57
89
  } if (rf & 2) {
58
90
  const ctx_r1 = i0.ɵɵnextContext();
59
91
  i0.ɵɵadvance(3);
60
92
  i0.ɵɵproperty("value", ctx_r1.spec.Context.QueryID || "");
61
93
  } }
62
- function FeaturePipelineBuilderComponent_For_40_Template(rf, ctx) { if (rf & 1) {
63
- i0.ɵɵelementStart(0, "option", 14);
94
+ function FeaturePipelineBuilderComponent_For_54_Template(rf, ctx) { if (rf & 1) {
95
+ i0.ɵɵelementStart(0, "option", 5);
64
96
  i0.ɵɵtext(1);
65
97
  i0.ɵɵelementEnd();
66
98
  } if (rf & 2) {
67
- const p_r5 = ctx.$implicit;
68
- i0.ɵɵproperty("value", p_r5.ID);
99
+ const p_r7 = ctx.$implicit;
100
+ const ctx_r1 = i0.ɵɵnextContext();
101
+ i0.ɵɵproperty("value", p_r7.ID)("selected", ctx_r1.IsSavedPrompt(p_r7));
69
102
  i0.ɵɵadvance();
70
- i0.ɵɵtextInterpolate(p_r5.Name);
103
+ i0.ɵɵtextInterpolate(p_r7.Name);
71
104
  } }
72
- function FeaturePipelineBuilderComponent_Conditional_41_Template(rf, ctx) { if (rf & 1) {
73
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
105
+ function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (rf & 1) {
106
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
74
107
  i0.ɵɵtext(2, "Prompt Description");
75
108
  i0.ɵɵelementEnd();
76
- i0.ɵɵelementStart(3, "div", 30);
109
+ i0.ɵɵelementStart(3, "div", 6);
77
110
  i0.ɵɵtext(4);
78
111
  i0.ɵɵelementEnd()();
79
112
  } if (rf & 2) {
@@ -81,13 +114,13 @@ function FeaturePipelineBuilderComponent_Conditional_41_Template(rf, ctx) { if (
81
114
  i0.ɵɵadvance(4);
82
115
  i0.ɵɵtextInterpolate(ctx_r1.selectedPrompt.Description || "No description provided");
83
116
  } }
84
- function FeaturePipelineBuilderComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
85
- i0.ɵɵelementStart(0, "div", 15)(1, "label");
117
+ function FeaturePipelineBuilderComponent_Conditional_56_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
86
119
  i0.ɵɵtext(2, "Injected Constraint Block ");
87
- i0.ɵɵelementStart(3, "span", 31);
120
+ i0.ɵɵelementStart(3, "span", 38);
88
121
  i0.ɵɵtext(4, "\u2014 automatically appended to prompt instructions");
89
122
  i0.ɵɵelementEnd()();
90
- i0.ɵɵelementStart(5, "pre", 32);
123
+ i0.ɵɵelementStart(5, "pre", 39);
91
124
  i0.ɵɵtext(6);
92
125
  i0.ɵɵelementEnd()();
93
126
  } if (rf & 2) {
@@ -95,9 +128,9 @@ function FeaturePipelineBuilderComponent_Conditional_42_Template(rf, ctx) { if (
95
128
  i0.ɵɵadvance(6);
96
129
  i0.ɵɵtextInterpolate(ctx_r1.renderedConstraintPreview);
97
130
  } }
98
- function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (rf & 1) {
99
- i0.ɵɵelementStart(0, "div", 20);
100
- i0.ɵɵelement(1, "i", 33);
131
+ function FeaturePipelineBuilderComponent_Conditional_69_Template(rf, ctx) { if (rf & 1) {
132
+ i0.ɵɵelementStart(0, "div", 24);
133
+ i0.ɵɵelement(1, "i", 40);
101
134
  i0.ɵɵelementStart(2, "span");
102
135
  i0.ɵɵtext(3, "No outputs defined. Click ");
103
136
  i0.ɵɵelementStart(4, "strong");
@@ -106,243 +139,454 @@ function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (
106
139
  i0.ɵɵtext(6, " to configure at least one output attribute.");
107
140
  i0.ɵɵelementEnd()();
108
141
  } }
109
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_For_7_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵelementStart(0, "option", 14);
142
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
143
+ i0.ɵɵelementStart(0, "option", 18);
144
+ i0.ɵɵtext(1, "\u2014 Select Target Mode \u2014");
145
+ i0.ɵɵelementEnd();
146
+ } if (rf & 2) {
147
+ i0.ɵɵproperty("selected", true);
148
+ } }
149
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_For_22_Template(rf, ctx) { if (rf & 1) {
150
+ i0.ɵɵelementStart(0, "option", 5);
111
151
  i0.ɵɵtext(1);
112
152
  i0.ɵɵelementEnd();
113
153
  } if (rf & 2) {
114
- const f_r9 = ctx.$implicit;
115
- i0.ɵɵproperty("value", f_r9.Name);
154
+ const m_r10 = ctx.$implicit;
155
+ const output_r11 = i0.ɵɵnextContext().$implicit;
156
+ i0.ɵɵproperty("value", m_r10.Value)("selected", m_r10.Value === output_r11.Target.Mode);
116
157
  i0.ɵɵadvance();
117
- i0.ɵɵtextInterpolate2("", f_r9.DisplayName || f_r9.Name, " (", f_r9.TSType, ")");
158
+ i0.ɵɵtextInterpolate(m_r10.Label);
118
159
  } }
119
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template(rf, ctx) { if (rf & 1) {
120
- const _r8 = i0.ɵɵgetCurrentView();
121
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
160
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_For_7_Template(rf, ctx) { if (rf & 1) {
161
+ i0.ɵɵelementStart(0, "option", 5);
162
+ i0.ɵɵtext(1);
163
+ i0.ɵɵelementEnd();
164
+ } if (rf & 2) {
165
+ const f_r13 = ctx.$implicit;
166
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
167
+ i0.ɵɵproperty("value", f_r13.Name)("selected", f_r13.Name === output_r11.Target.EntityFieldName);
168
+ i0.ɵɵadvance();
169
+ i0.ɵɵtextInterpolate2("", f_r13.DisplayName || f_r13.Name, " (", f_r13.TSType, ")");
170
+ } }
171
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template(rf, ctx) { if (rf & 1) {
172
+ const _r12 = i0.ɵɵgetCurrentView();
173
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
122
174
  i0.ɵɵtext(2, "Target Field");
123
175
  i0.ɵɵelementEnd();
124
- i0.ɵɵelementStart(3, "select", 7);
125
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r8); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateFieldTarget($index_r7, $event)); });
126
- i0.ɵɵelementStart(4, "option", 13);
176
+ i0.ɵɵelementStart(3, "select", 4);
177
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r12); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateFieldTarget(ɵ$index_185_r9, $event)); });
178
+ i0.ɵɵelementStart(4, "option", 18);
127
179
  i0.ɵɵtext(5, "\u2014 Select Column \u2014");
128
180
  i0.ɵɵelementEnd();
129
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_For_7_Template, 2, 3, "option", 14, _forTrack1);
181
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_For_7_Template, 2, 4, "option", 5, _forTrack0);
130
182
  i0.ɵɵelementEnd()();
131
183
  } if (rf & 2) {
132
- const output_r10 = i0.ɵɵnextContext().$implicit;
184
+ const output_r11 = i0.ɵɵnextContext().$implicit;
133
185
  const ctx_r1 = i0.ɵɵnextContext(2);
134
- i0.ɵɵadvance(3);
135
- i0.ɵɵproperty("value", output_r10.Target.EntityFieldName);
136
- i0.ɵɵadvance(3);
186
+ i0.ɵɵadvance(4);
187
+ i0.ɵɵproperty("selected", !ctx_r1.IsEntityFieldListed(output_r11.Target.EntityFieldName));
188
+ i0.ɵɵadvance(2);
137
189
  i0.ɵɵrepeater(ctx_r1.entityFields);
138
190
  } }
139
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_For_7_Template(rf, ctx) { if (rf & 1) {
140
- i0.ɵɵelementStart(0, "option", 14);
191
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_For_7_Template(rf, ctx) { if (rf & 1) {
192
+ i0.ɵɵelementStart(0, "option", 5);
141
193
  i0.ɵɵtext(1);
142
194
  i0.ɵɵelementEnd();
143
195
  } if (rf & 2) {
144
- const e_r12 = ctx.$implicit;
145
- i0.ɵɵproperty("value", e_r12.Name);
196
+ const e_r15 = ctx.$implicit;
197
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
198
+ i0.ɵɵproperty("value", e_r15.Name)("selected", e_r15.Name === output_r11.Target.EntityName);
146
199
  i0.ɵɵadvance();
147
- i0.ɵɵtextInterpolate(e_r12.DisplayName || e_r12.Name);
200
+ i0.ɵɵtextInterpolate(e_r15.DisplayName || e_r15.Name);
148
201
  } }
149
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template(rf, ctx) { if (rf & 1) {
150
- const _r11 = i0.ɵɵgetCurrentView();
151
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
202
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template(rf, ctx) { if (rf & 1) {
203
+ const _r14 = i0.ɵɵgetCurrentView();
204
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
152
205
  i0.ɵɵtext(2, "Child Entity");
153
206
  i0.ɵɵelementEnd();
154
- i0.ɵɵelementStart(3, "select", 7);
155
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r11); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateChildTargetEntity($index_r7, $event)); });
156
- i0.ɵɵelementStart(4, "option", 13);
207
+ i0.ɵɵelementStart(3, "select", 4);
208
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r14); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateChildTargetEntity(ɵ$index_185_r9, $event)); });
209
+ i0.ɵɵelementStart(4, "option", 18);
157
210
  i0.ɵɵtext(5, "\u2014 Select Entity \u2014");
158
211
  i0.ɵɵelementEnd();
159
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_For_7_Template, 2, 2, "option", 14, _forTrack0);
212
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_For_7_Template, 2, 3, "option", 5, _forTrack1);
160
213
  i0.ɵɵelementEnd()();
161
214
  } if (rf & 2) {
162
- const output_r10 = i0.ɵɵnextContext().$implicit;
215
+ const output_r11 = i0.ɵɵnextContext().$implicit;
163
216
  const ctx_r1 = i0.ɵɵnextContext(2);
164
- i0.ɵɵadvance(3);
165
- i0.ɵɵproperty("value", output_r10.Target.EntityName);
166
- i0.ɵɵadvance(3);
217
+ i0.ɵɵadvance(4);
218
+ i0.ɵɵproperty("selected", !ctx_r1.IsEntityListed(output_r11.Target.EntityName));
219
+ i0.ɵɵadvance(2);
167
220
  i0.ɵɵrepeater(ctx_r1.availableEntities);
168
221
  } }
169
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template(rf, ctx) { if (rf & 1) {
170
- const _r13 = i0.ɵɵgetCurrentView();
171
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
222
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_30_Template(rf, ctx) { if (rf & 1) {
223
+ i0.ɵɵelementStart(0, "option", 47);
224
+ i0.ɵɵtext(1, "\u2014 Select Constraint \u2014");
225
+ i0.ɵɵelementEnd();
226
+ } if (rf & 2) {
227
+ i0.ɵɵproperty("selected", true);
228
+ } }
229
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_For_32_Template(rf, ctx) { if (rf & 1) {
230
+ i0.ɵɵelementStart(0, "option", 5);
231
+ i0.ɵɵtext(1);
232
+ i0.ɵɵelementEnd();
233
+ } if (rf & 2) {
234
+ const t_r16 = ctx.$implicit;
235
+ const output_r11 = i0.ɵɵnextContext().$implicit;
236
+ const ctx_r1 = i0.ɵɵnextContext(2);
237
+ i0.ɵɵproperty("value", t_r16.Value)("selected", t_r16.Value === ctx_r1.SavedConstraintType(output_r11));
238
+ i0.ɵɵadvance();
239
+ i0.ɵɵtextInterpolate(t_r16.Label);
240
+ } }
241
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template(rf, ctx) { if (rf & 1) {
242
+ const _r17 = i0.ɵɵgetCurrentView();
243
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
172
244
  i0.ɵɵtext(2, "Violation Policy");
173
245
  i0.ɵɵelementEnd();
174
- i0.ɵɵelementStart(3, "select", 7);
175
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r13); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateViolationPolicy($index_r7, $event)); });
176
- i0.ɵɵelementStart(4, "option", 49);
246
+ i0.ɵɵelementStart(3, "select", 13);
247
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r17); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateViolationPolicy(ɵ$index_185_r9, $event)); });
248
+ i0.ɵɵelementStart(4, "option", 48);
177
249
  i0.ɵɵtext(5, "Fail Row");
178
250
  i0.ɵɵelementEnd();
179
- i0.ɵɵelementStart(6, "option", 50);
251
+ i0.ɵɵelementStart(6, "option", 49);
180
252
  i0.ɵɵtext(7, "Set Output to Null");
181
253
  i0.ɵɵelementEnd();
182
- i0.ɵɵelementStart(8, "option", 51);
254
+ i0.ɵɵelementStart(8, "option", 50);
183
255
  i0.ɵɵtext(9, "Coerce / Fallback");
184
256
  i0.ɵɵelementEnd()()();
185
257
  } if (rf & 2) {
186
- const output_r10 = i0.ɵɵnextContext().$implicit;
258
+ const output_r11 = i0.ɵɵnextContext().$implicit;
187
259
  i0.ɵɵadvance(3);
188
- i0.ɵɵproperty("value", output_r10.Constraint.OnViolation || "fail");
260
+ i0.ɵɵproperty("value", output_r11.Constraint.OnViolation || "fail");
189
261
  } }
190
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template(rf, ctx) { if (rf & 1) {
191
- const _r14 = i0.ɵɵgetCurrentView();
192
- i0.ɵɵelementStart(0, "div", 15)(1, "label");
262
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template(rf, ctx) { if (rf & 1) {
263
+ const _r19 = i0.ɵɵgetCurrentView();
264
+ i0.ɵɵelementStart(0, "div", 53)(1, "span", 54);
265
+ i0.ɵɵtext(2);
266
+ i0.ɵɵelementEnd();
267
+ i0.ɵɵelementStart(3, "input", 55);
268
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template_input_input_3_listener($event) { const val_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateEnumValueDescription(ɵ$index_185_r9, val_r20, $event)); });
269
+ i0.ɵɵelementEnd()();
270
+ } if (rf & 2) {
271
+ const val_r20 = ctx.$implicit;
272
+ const output_r11 = i0.ɵɵnextContext(3).$implicit;
273
+ const ctx_r1 = i0.ɵɵnextContext(2);
274
+ i0.ɵɵadvance(2);
275
+ i0.ɵɵtextInterpolate(val_r20);
276
+ i0.ɵɵadvance();
277
+ i0.ɵɵproperty("value", ctx_r1.GetEnumValueDescription(output_r11, val_r20))("placeholder", "Description for " + val_r20);
278
+ } }
279
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_Template(rf, ctx) { if (rf & 1) {
280
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
281
+ i0.ɵɵtext(2, "Value Descriptions ");
282
+ i0.ɵɵelementStart(3, "span", 38);
283
+ i0.ɵɵtext(4, "\u2014 Decision models require a description for every choice option");
284
+ i0.ɵɵelementEnd()();
285
+ i0.ɵɵelementStart(5, "div", 52);
286
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template, 4, 3, "div", 53, i0.ɵɵrepeaterTrackByIdentity);
287
+ i0.ɵɵelementEnd()();
288
+ } if (rf & 2) {
289
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
290
+ const ctx_r1 = i0.ɵɵnextContext(2);
291
+ i0.ɵɵadvance(6);
292
+ i0.ɵɵrepeater(ctx_r1.GetEnumValues(output_r11));
293
+ } }
294
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template(rf, ctx) { if (rf & 1) {
295
+ const _r18 = i0.ɵɵgetCurrentView();
296
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
193
297
  i0.ɵɵtext(2, "Allowed Values (comma separated)");
194
298
  i0.ɵɵelementEnd();
195
- i0.ɵɵelementStart(3, "input", 52);
196
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r14); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateEnumValues($index_r7, $event)); });
299
+ i0.ɵɵelementStart(3, "input", 51);
300
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r18); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateEnumValues(ɵ$index_185_r9, $event)); });
197
301
  i0.ɵɵelementEnd()();
302
+ i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_Template, 8, 0, "div", 19);
198
303
  } if (rf & 2) {
199
- const output_r10 = i0.ɵɵnextContext().$implicit;
304
+ const output_r11 = i0.ɵɵnextContext().$implicit;
200
305
  const ctx_r1 = i0.ɵɵnextContext(2);
201
306
  i0.ɵɵadvance(3);
202
- i0.ɵɵproperty("value", ctx_r1.getEnumValuesCsv(output_r10.Constraint));
307
+ i0.ɵɵproperty("value", ctx_r1.getEnumValuesCsv(output_r11.Constraint));
308
+ i0.ɵɵadvance();
309
+ i0.ɵɵconditional(ctx_r1.IsDecisionPipeline && ctx_r1.GetEnumValues(output_r11).length > 0 ? 4 : -1);
310
+ } }
311
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template(rf, ctx) { if (rf & 1) {
312
+ const _r22 = i0.ɵɵgetCurrentView();
313
+ i0.ɵɵelementStart(0, "div", 59)(1, "span", 60);
314
+ i0.ɵɵtext(2);
315
+ i0.ɵɵelementEnd();
316
+ i0.ɵɵelementStart(3, "input", 61);
317
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_input_input_3_listener($event) { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, $event)); });
318
+ i0.ɵɵelementEnd();
319
+ i0.ɵɵelementStart(4, "button", 62);
320
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_4_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, "up")); });
321
+ i0.ɵɵelement(5, "i", 63);
322
+ i0.ɵɵelementEnd();
323
+ i0.ɵɵelementStart(6, "button", 64);
324
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_6_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, "down")); });
325
+ i0.ɵɵelement(7, "i", 65);
326
+ i0.ɵɵelementEnd();
327
+ i0.ɵɵelementStart(8, "button", 66);
328
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_8_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RemoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23)); });
329
+ i0.ɵɵelement(9, "i", 44);
330
+ i0.ɵɵelementEnd()();
331
+ } if (rf & 2) {
332
+ const lvl_r24 = ctx.$implicit;
333
+ const ɵ$index_339_r23 = ctx.$index;
334
+ const ɵ$count_339_r25 = ctx.$count;
335
+ const output_r11 = i0.ɵɵnextContext(3).$implicit;
336
+ const ctx_r1 = i0.ɵɵnextContext(2);
337
+ i0.ɵɵadvance(2);
338
+ i0.ɵɵtextInterpolate(ɵ$index_339_r23 + 1);
339
+ i0.ɵɵadvance();
340
+ i0.ɵɵproperty("value", lvl_r24);
341
+ i0.ɵɵadvance();
342
+ i0.ɵɵproperty("disabled", ɵ$index_339_r23 === 0);
343
+ i0.ɵɵadvance(2);
344
+ i0.ɵɵproperty("disabled", ɵ$index_339_r23 === ɵ$count_339_r25 - 1);
345
+ i0.ɵɵadvance(2);
346
+ i0.ɵɵproperty("disabled", ctx_r1.GetNumericLevels(output_r11).length <= 2);
347
+ } }
348
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template(rf, ctx) { if (rf & 1) {
349
+ const _r21 = i0.ɵɵgetCurrentView();
350
+ i0.ɵɵelementStart(0, "div", 19)(1, "div", 56)(2, "label");
351
+ i0.ɵɵtext(3, "Numeric Levels ");
352
+ i0.ɵɵelementStart(4, "span", 38);
353
+ i0.ɵɵtext(5, "(Ordered: lowest to highest, 2 to 10 levels)");
354
+ i0.ɵɵelementEnd()();
355
+ i0.ɵɵelementStart(6, "button", 57);
356
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r21); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.AddNumericLevel(ɵ$index_185_r9)); });
357
+ i0.ɵɵelement(7, "i", 23);
358
+ i0.ɵɵtext(8, " Add Level ");
359
+ i0.ɵɵelementEnd()();
360
+ i0.ɵɵelementStart(9, "div", 58);
361
+ i0.ɵɵrepeaterCreate(10, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template, 10, 5, "div", 59, i0.ɵɵrepeaterTrackByIndex);
362
+ i0.ɵɵelementEnd()();
363
+ } if (rf & 2) {
364
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
365
+ const ctx_r1 = i0.ɵɵnextContext(2);
366
+ i0.ɵɵadvance(6);
367
+ i0.ɵɵproperty("disabled", ctx_r1.GetNumericLevels(output_r11).length >= 10);
368
+ i0.ɵɵadvance(4);
369
+ i0.ɵɵrepeater(ctx_r1.GetNumericLevels(output_r11));
203
370
  } }
204
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template(rf, ctx) { if (rf & 1) {
205
- const _r15 = i0.ɵɵgetCurrentView();
206
- i0.ɵɵelementStart(0, "div", 48)(1, "div", 6)(2, "label");
371
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template(rf, ctx) { if (rf & 1) {
372
+ const _r26 = i0.ɵɵgetCurrentView();
373
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
207
374
  i0.ɵɵtext(3, "Min Value");
208
375
  i0.ɵɵelementEnd();
209
- i0.ɵɵelementStart(4, "input", 53);
210
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r15); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMin($index_r7, $event)); });
376
+ i0.ɵɵelementStart(4, "input", 67);
377
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r26); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMin(ɵ$index_185_r9, $event)); });
211
378
  i0.ɵɵelementEnd()();
212
- i0.ɵɵelementStart(5, "div", 6)(6, "label");
379
+ i0.ɵɵelementStart(5, "div", 3)(6, "label");
213
380
  i0.ɵɵtext(7, "Max Value");
214
381
  i0.ɵɵelementEnd();
215
- i0.ɵɵelementStart(8, "input", 53);
216
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r15); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMax($index_r7, $event)); });
382
+ i0.ɵɵelementStart(8, "input", 67);
383
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r26); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMax(ɵ$index_185_r9, $event)); });
217
384
  i0.ɵɵelementEnd()()();
218
385
  } if (rf & 2) {
219
- const output_r10 = i0.ɵɵnextContext().$implicit;
386
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
220
387
  const ctx_r1 = i0.ɵɵnextContext(2);
221
388
  i0.ɵɵadvance(4);
222
- i0.ɵɵproperty("value", ctx_r1.getNumericMin(output_r10.Constraint));
389
+ i0.ɵɵproperty("value", ctx_r1.getNumericMin(output_r11.Constraint));
223
390
  i0.ɵɵadvance(4);
224
- i0.ɵɵproperty("value", ctx_r1.getNumericMax(output_r10.Constraint));
391
+ i0.ɵɵproperty("value", ctx_r1.getNumericMax(output_r11.Constraint));
225
392
  } }
226
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template(rf, ctx) { if (rf & 1) {
227
- const _r6 = i0.ɵɵgetCurrentView();
228
- i0.ɵɵelementStart(0, "div", 34)(1, "div", 35)(2, "h4");
393
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Template(rf, ctx) { if (rf & 1) {
394
+ i0.ɵɵconditionalCreate(0, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template, 12, 1, "div", 19)(1, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template, 9, 2, "div", 7);
395
+ } if (rf & 2) {
396
+ const ctx_r1 = i0.ɵɵnextContext(3);
397
+ i0.ɵɵconditional(ctx_r1.IsDecisionPipeline ? 0 : 1);
398
+ } }
399
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template(rf, ctx) { if (rf & 1) {
400
+ const _r27 = i0.ɵɵgetCurrentView();
401
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
402
+ i0.ɵɵtext(2, "Decision Threshold (0.0 to 1.0) ");
403
+ i0.ɵɵelementStart(3, "span", 38);
404
+ i0.ɵɵtext(4, "\u2014 calibrated probability threshold for true");
405
+ i0.ɵɵelementEnd()();
406
+ i0.ɵɵelementStart(5, "input", 68);
407
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template_input_input_5_listener($event) { i0.ɵɵrestoreView(_r27); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateBooleanThreshold(ɵ$index_185_r9, $event)); });
408
+ i0.ɵɵelementEnd()();
409
+ } if (rf & 2) {
410
+ const output_r11 = i0.ɵɵnextContext().$implicit;
411
+ const ctx_r1 = i0.ɵɵnextContext(2);
412
+ i0.ɵɵadvance(5);
413
+ i0.ɵɵproperty("value", ctx_r1.GetBooleanThreshold(output_r11) ?? "");
414
+ } }
415
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template(rf, ctx) { if (rf & 1) {
416
+ const _r8 = i0.ɵɵgetCurrentView();
417
+ i0.ɵɵelementStart(0, "div", 41)(1, "div", 42)(2, "h4");
229
418
  i0.ɵɵtext(3);
230
419
  i0.ɵɵelementEnd();
231
- i0.ɵɵelementStart(4, "button", 36);
232
- i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_button_click_4_listener() { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.removeOutput($index_r7)); });
233
- i0.ɵɵelement(5, "i", 37);
420
+ i0.ɵɵelementStart(4, "button", 43);
421
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_button_click_4_listener() { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.removeOutput(ɵ$index_185_r9)); });
422
+ i0.ɵɵelement(5, "i", 44);
234
423
  i0.ɵɵtext(6, " Remove ");
235
424
  i0.ɵɵelementEnd()();
236
- i0.ɵɵelementStart(7, "div", 5)(8, "div", 6)(9, "label");
425
+ i0.ɵɵelementStart(7, "div", 12)(8, "div", 3)(9, "label");
237
426
  i0.ɵɵtext(10, "Output Name");
238
427
  i0.ɵɵelementEnd();
239
- i0.ɵɵelementStart(11, "input", 38);
240
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_input_input_11_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp($index_r7, "Name", $event)); });
428
+ i0.ɵɵelementStart(11, "input", 45);
429
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_input_input_11_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp(ɵ$index_185_r9, "Name", $event)); });
241
430
  i0.ɵɵelementEnd()();
242
- i0.ɵɵelementStart(12, "div", 6)(13, "label");
431
+ i0.ɵɵelementStart(12, "div", 3)(13, "label");
243
432
  i0.ɵɵtext(14, "JSON Path / Ref");
244
433
  i0.ɵɵelementEnd();
245
- i0.ɵɵelementStart(15, "input", 39);
246
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_input_input_15_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp($index_r7, "Ref", $event)); });
434
+ i0.ɵɵelementStart(15, "input", 46);
435
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_input_input_15_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp(ɵ$index_185_r9, "Ref", $event)); });
247
436
  i0.ɵɵelementEnd()();
248
- i0.ɵɵelementStart(16, "div", 6)(17, "label");
437
+ i0.ɵɵelementStart(16, "div", 3)(17, "label");
249
438
  i0.ɵɵtext(18, "Target Mode");
250
439
  i0.ɵɵelementEnd();
251
- i0.ɵɵelementStart(19, "select", 7);
252
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_select_change_19_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateTargetMode($index_r7, $event)); });
253
- i0.ɵɵelementStart(20, "option", 40);
254
- i0.ɵɵtext(21, "Entity Column (field)");
255
- i0.ɵɵelementEnd();
256
- i0.ɵɵelementStart(22, "option", 41);
257
- i0.ɵɵtext(23, "Child Rows (child)");
258
- i0.ɵɵelementEnd();
259
- i0.ɵɵelementStart(24, "option", 42);
260
- i0.ɵɵtext(25, "Taxonomy Tags (tags)");
261
- i0.ɵɵelementEnd()()()();
262
- i0.ɵɵelementStart(26, "div", 27);
263
- i0.ɵɵconditionalCreate(27, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template, 8, 1, "div", 6);
264
- i0.ɵɵconditionalCreate(28, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template, 8, 1, "div", 6);
265
- i0.ɵɵelementStart(29, "div", 6)(30, "label");
266
- i0.ɵɵtext(31, "Constraint Type");
267
- i0.ɵɵelementEnd();
268
- i0.ɵɵelementStart(32, "select", 7);
269
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_select_change_32_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateConstraintType($index_r7, $event)); });
270
- i0.ɵɵelementStart(33, "option", 43);
271
- i0.ɵɵtext(34, "None / Unconstrained");
272
- i0.ɵɵelementEnd();
273
- i0.ɵɵelementStart(35, "option", 44);
274
- i0.ɵɵtext(36, "Enum (Allowed Values)");
275
- i0.ɵɵelementEnd();
276
- i0.ɵɵelementStart(37, "option", 45);
277
- i0.ɵɵtext(38, "Numeric (Min/Max)");
278
- i0.ɵɵelementEnd();
279
- i0.ɵɵelementStart(39, "option", 46);
280
- i0.ɵɵtext(40, "Boolean");
281
- i0.ɵɵelementEnd();
282
- i0.ɵɵelementStart(41, "option", 47);
283
- i0.ɵɵtext(42, "Free Text");
440
+ i0.ɵɵelementStart(19, "select", 4);
441
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_select_change_19_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateTargetMode(ɵ$index_185_r9, $event)); });
442
+ i0.ɵɵconditionalCreate(20, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_20_Template, 2, 1, "option", 18);
443
+ i0.ɵɵrepeaterCreate(21, FeaturePipelineBuilderComponent_Conditional_70_For_2_For_22_Template, 2, 3, "option", 5, _forTrack2);
284
444
  i0.ɵɵelementEnd()()();
285
- i0.ɵɵconditionalCreate(43, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template, 10, 1, "div", 6);
445
+ i0.ɵɵelementStart(23, "div", 32);
446
+ i0.ɵɵconditionalCreate(24, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template, 8, 1, "div", 3);
447
+ i0.ɵɵconditionalCreate(25, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template, 8, 1, "div", 3);
448
+ i0.ɵɵelementStart(26, "div", 3)(27, "label");
449
+ i0.ɵɵtext(28, "Constraint Type");
286
450
  i0.ɵɵelementEnd();
287
- i0.ɵɵconditionalCreate(44, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template, 4, 1, "div", 15);
288
- i0.ɵɵconditionalCreate(45, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template, 9, 2, "div", 48);
451
+ i0.ɵɵelementStart(29, "select", 4);
452
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_select_change_29_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateConstraintType(ɵ$index_185_r9, $event)); });
453
+ i0.ɵɵconditionalCreate(30, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_30_Template, 2, 1, "option", 47);
454
+ i0.ɵɵrepeaterCreate(31, FeaturePipelineBuilderComponent_Conditional_70_For_2_For_32_Template, 2, 3, "option", 5, _forTrack2);
455
+ i0.ɵɵelementEnd()();
456
+ i0.ɵɵconditionalCreate(33, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template, 10, 1, "div", 3);
457
+ i0.ɵɵelementEnd();
458
+ i0.ɵɵconditionalCreate(34, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template, 5, 2);
459
+ i0.ɵɵconditionalCreate(35, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Template, 2, 1);
460
+ i0.ɵɵconditionalCreate(36, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template, 6, 1, "div", 19);
289
461
  i0.ɵɵelementEnd();
290
462
  } if (rf & 2) {
291
- const output_r10 = ctx.$implicit;
292
- const $index_r7 = ctx.$index;
463
+ const output_r11 = ctx.$implicit;
464
+ const ɵ$index_185_r9 = ctx.$index;
465
+ const ctx_r1 = i0.ɵɵnextContext(2);
293
466
  i0.ɵɵadvance(3);
294
- i0.ɵɵtextInterpolate2("Output #", $index_r7 + 1, ": ", output_r10.Name || "(unnamed)");
467
+ i0.ɵɵtextInterpolate2("Output #", ɵ$index_185_r9 + 1, ": ", output_r11.Name || "(unnamed)");
295
468
  i0.ɵɵadvance(8);
296
- i0.ɵɵproperty("value", output_r10.Name);
469
+ i0.ɵɵproperty("value", output_r11.Name);
297
470
  i0.ɵɵadvance(4);
298
- i0.ɵɵproperty("value", output_r10.Ref);
299
- i0.ɵɵadvance(4);
300
- i0.ɵɵproperty("value", output_r10.Target.Mode);
301
- i0.ɵɵadvance(8);
302
- i0.ɵɵconditional(output_r10.Target.Mode === "field" ? 27 : -1);
471
+ i0.ɵɵproperty("value", output_r11.Ref);
472
+ i0.ɵɵadvance(5);
473
+ i0.ɵɵconditional(!ctx_r1.IsTargetModeOffered(output_r11) ? 20 : -1);
303
474
  i0.ɵɵadvance();
304
- i0.ɵɵconditional(output_r10.Target.Mode === "child" ? 28 : -1);
305
- i0.ɵɵadvance(4);
306
- i0.ɵɵproperty("value", (output_r10.Constraint == null ? null : output_r10.Constraint.Type) || "none");
307
- i0.ɵɵadvance(11);
308
- i0.ɵɵconditional(output_r10.Constraint ? 43 : -1);
475
+ i0.ɵɵrepeater(ctx_r1.AvailableTargetModes);
476
+ i0.ɵɵadvance(3);
477
+ i0.ɵɵconditional(output_r11.Target.Mode === "field" ? 24 : -1);
478
+ i0.ɵɵadvance();
479
+ i0.ɵɵconditional(output_r11.Target.Mode === "child" ? 25 : -1);
480
+ i0.ɵɵadvance(5);
481
+ i0.ɵɵconditional(!ctx_r1.IsConstraintTypeOffered(output_r11) ? 30 : -1);
482
+ i0.ɵɵadvance();
483
+ i0.ɵɵrepeater(ctx_r1.AvailableConstraintTypes);
484
+ i0.ɵɵadvance(2);
485
+ i0.ɵɵconditional(output_r11.Constraint ? 33 : -1);
309
486
  i0.ɵɵadvance();
310
- i0.ɵɵconditional((output_r10.Constraint == null ? null : output_r10.Constraint.Type) === "enum" ? 44 : -1);
487
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "enum" ? 34 : -1);
311
488
  i0.ɵɵadvance();
312
- i0.ɵɵconditional((output_r10.Constraint == null ? null : output_r10.Constraint.Type) === "numeric" ? 45 : -1);
489
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "numeric" ? 35 : -1);
490
+ i0.ɵɵadvance();
491
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "boolean" && ctx_r1.IsDecisionPipeline ? 36 : -1);
313
492
  } }
314
- function FeaturePipelineBuilderComponent_Conditional_56_Template(rf, ctx) { if (rf & 1) {
315
- i0.ɵɵelementStart(0, "div", 21);
316
- i0.ɵɵrepeaterCreate(1, FeaturePipelineBuilderComponent_Conditional_56_For_2_Template, 46, 11, "div", 34, i0.ɵɵrepeaterTrackByIndex);
493
+ function FeaturePipelineBuilderComponent_Conditional_70_Template(rf, ctx) { if (rf & 1) {
494
+ i0.ɵɵelementStart(0, "div", 25);
495
+ i0.ɵɵrepeaterCreate(1, FeaturePipelineBuilderComponent_Conditional_70_For_2_Template, 37, 12, "div", 41, i0.ɵɵrepeaterTrackByIndex);
317
496
  i0.ɵɵelementEnd();
318
497
  } if (rf & 2) {
319
498
  const ctx_r1 = i0.ɵɵnextContext();
320
499
  i0.ɵɵadvance();
321
500
  i0.ɵɵrepeater(ctx_r1.spec.Outputs);
322
501
  } }
323
- function FeaturePipelineBuilderComponent_Conditional_90_Template(rf, ctx) { if (rf & 1) {
324
- const _r16 = i0.ɵɵgetCurrentView();
325
- i0.ɵɵelementStart(0, "div", 27)(1, "div", 6)(2, "label");
502
+ function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_For_8_Template(rf, ctx) { if (rf & 1) {
503
+ i0.ɵɵelementStart(0, "option", 73);
504
+ i0.ɵɵtext(1);
505
+ i0.ɵɵelementEnd();
506
+ } if (rf & 2) {
507
+ const target_r30 = ctx.$implicit;
508
+ const ctx_r1 = i0.ɵɵnextContext(3);
509
+ i0.ɵɵproperty("value", target_r30.ID)("disabled", !!ctx_r1.GetTargetProblem(target_r30))("selected", ctx_r1.IsSavedEscalationTarget(target_r30));
510
+ i0.ɵɵadvance();
511
+ i0.ɵɵtextInterpolate2(" ", target_r30.Name, "", ctx_r1.GetTargetProblem(target_r30) ? " (" + ctx_r1.GetTargetProblem(target_r30) + ")" : "", " ");
512
+ } }
513
+ function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template(rf, ctx) { if (rf & 1) {
514
+ const _r29 = i0.ɵɵgetCurrentView();
515
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
516
+ i0.ɵɵtext(3, "Target LLM Pipeline");
517
+ i0.ɵɵelementEnd();
518
+ i0.ɵɵelementStart(4, "select", 4);
519
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template_select_change_4_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnEscalationTargetChange($event)); });
520
+ i0.ɵɵelementStart(5, "option", 18);
521
+ i0.ɵɵtext(6);
522
+ i0.ɵɵelementEnd();
523
+ i0.ɵɵrepeaterCreate(7, FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_For_8_Template, 2, 5, "option", 73, _forTrack1);
524
+ i0.ɵɵelementEnd()();
525
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
526
+ i0.ɵɵtext(11, "Confidence Floor (0.0 to 1.0)");
527
+ i0.ɵɵelementEnd();
528
+ i0.ɵɵelementStart(12, "input", 74);
529
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template_input_input_12_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnEscalationFloorChange($event)); });
530
+ i0.ɵɵelementEnd()()();
531
+ } if (rf & 2) {
532
+ const ctx_r1 = i0.ɵɵnextContext(2);
533
+ i0.ɵɵadvance(5);
534
+ i0.ɵɵproperty("selected", !ctx_r1.SavedEscalationTargetListed);
535
+ i0.ɵɵadvance();
536
+ i0.ɵɵtextInterpolate(ctx_r1.EscalationTargetsPlaceholder);
537
+ i0.ɵɵadvance();
538
+ i0.ɵɵrepeater(ctx_r1.AvailableEscalationTargets);
539
+ i0.ɵɵadvance(5);
540
+ i0.ɵɵproperty("value", (ctx_r1.spec.Escalation == null ? null : ctx_r1.spec.Escalation.BelowConfidence) ?? "");
541
+ } }
542
+ function FeaturePipelineBuilderComponent_Conditional_71_Template(rf, ctx) { if (rf & 1) {
543
+ const _r28 = i0.ɵɵgetCurrentView();
544
+ i0.ɵɵelementStart(0, "section", 26)(1, "div", 9);
545
+ i0.ɵɵelement(2, "i", 69);
546
+ i0.ɵɵelementStart(3, "h3");
547
+ i0.ɵɵtext(4, "Borderline Escalation");
548
+ i0.ɵɵelementEnd()();
549
+ i0.ɵɵelementStart(5, "p", 11);
550
+ i0.ɵɵtext(6, "Records any output of which the decision model answers below this confidence are re-run through the chosen LLM pipeline. Only those records are re-run.");
551
+ i0.ɵɵelementEnd();
552
+ i0.ɵɵelementStart(7, "div", 70)(8, "label", 71)(9, "input", 72);
553
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_71_Template_input_change_9_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnEscalationToggle($event)); });
554
+ i0.ɵɵelementEnd();
555
+ i0.ɵɵelementStart(10, "span");
556
+ i0.ɵɵtext(11, "Escalate borderline records to an LLM pipeline");
557
+ i0.ɵɵelementEnd()()();
558
+ i0.ɵɵconditionalCreate(12, FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template, 13, 3, "div", 7);
559
+ i0.ɵɵelementEnd();
560
+ } if (rf & 2) {
561
+ const ctx_r1 = i0.ɵɵnextContext();
562
+ i0.ɵɵadvance(9);
563
+ i0.ɵɵproperty("checked", ctx_r1.IsEscalationEnabled);
564
+ i0.ɵɵadvance(3);
565
+ i0.ɵɵconditional(ctx_r1.IsEscalationEnabled ? 12 : -1);
566
+ } }
567
+ function FeaturePipelineBuilderComponent_Conditional_105_Template(rf, ctx) { if (rf & 1) {
568
+ const _r31 = i0.ɵɵgetCurrentView();
569
+ i0.ɵɵelementStart(0, "div", 32)(1, "div", 3)(2, "label");
326
570
  i0.ɵɵtext(3, "Cache Key Fields (comma separated)");
327
571
  i0.ɵɵelementEnd();
328
- i0.ɵɵelementStart(4, "input", 54);
329
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_90_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheKeyFields($event)); });
572
+ i0.ɵɵelementStart(4, "input", 75);
573
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_105_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheKeyFields($event)); });
330
574
  i0.ɵɵelementEnd()();
331
- i0.ɵɵelementStart(5, "div", 6)(6, "label");
575
+ i0.ɵɵelementStart(5, "div", 3)(6, "label");
332
576
  i0.ɵɵtext(7, "Cache TTL (Seconds)");
333
577
  i0.ɵɵelementEnd();
334
- i0.ɵɵelementStart(8, "input", 53);
335
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_90_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheTTL($event)); });
578
+ i0.ɵɵelementStart(8, "input", 67);
579
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_105_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheTTL($event)); });
336
580
  i0.ɵɵelementEnd()();
337
- i0.ɵɵelementStart(9, "div", 6)(10, "label");
581
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
338
582
  i0.ɵɵtext(11, "Cache Scope");
339
583
  i0.ɵɵelementEnd();
340
- i0.ɵɵelementStart(12, "select", 7);
341
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_90_Template_select_change_12_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheScope($event)); });
342
- i0.ɵɵelementStart(13, "option", 55);
584
+ i0.ɵɵelementStart(12, "select", 13);
585
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_105_Template_select_change_12_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheScope($event)); });
586
+ i0.ɵɵelementStart(13, "option", 76);
343
587
  i0.ɵɵtext(14, "Pipeline (Isolated to this process)");
344
588
  i0.ɵɵelementEnd();
345
- i0.ɵɵelementStart(15, "option", 56);
589
+ i0.ɵɵelementStart(15, "option", 77);
346
590
  i0.ɵɵtext(16, "Prompt (Shared across processes with same prompt)");
347
591
  i0.ɵɵelementEnd()()()();
348
592
  } if (rf & 2) {
@@ -354,44 +598,62 @@ function FeaturePipelineBuilderComponent_Conditional_90_Template(rf, ctx) { if (
354
598
  i0.ɵɵadvance(4);
355
599
  i0.ɵɵproperty("value", ctx_r1.spec.Caching.Scope || "pipeline");
356
600
  } }
357
- function FeaturePipelineBuilderComponent_Conditional_91_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
358
- i0.ɵɵelementStart(0, "span", 31);
601
+ function FeaturePipelineBuilderComponent_Conditional_106_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
602
+ i0.ɵɵelementStart(0, "span", 38);
359
603
  i0.ɵɵtext(1);
360
604
  i0.ɵɵelementEnd();
361
605
  } if (rf & 2) {
362
- const issue_r17 = i0.ɵɵnextContext().$implicit;
606
+ const issue_r32 = i0.ɵɵnextContext().$implicit;
363
607
  i0.ɵɵadvance();
364
- i0.ɵɵtextInterpolate1("(Fix: ", issue_r17.FixRecommendation, ")");
608
+ i0.ɵɵtextInterpolate1("(Fix: ", issue_r32.FixRecommendation, ")");
365
609
  } }
366
- function FeaturePipelineBuilderComponent_Conditional_91_For_6_Template(rf, ctx) { if (rf & 1) {
610
+ function FeaturePipelineBuilderComponent_Conditional_106_For_6_Template(rf, ctx) { if (rf & 1) {
367
611
  i0.ɵɵelementStart(0, "li")(1, "strong");
368
612
  i0.ɵɵtext(2);
369
613
  i0.ɵɵelementEnd();
370
614
  i0.ɵɵtext(3);
371
- i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_91_For_6_Conditional_4_Template, 2, 1, "span", 31);
615
+ i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_106_For_6_Conditional_4_Template, 2, 1, "span", 38);
372
616
  i0.ɵɵelementEnd();
373
617
  } if (rf & 2) {
374
- const issue_r17 = ctx.$implicit;
618
+ const issue_r32 = ctx.$implicit;
375
619
  i0.ɵɵadvance(2);
376
- i0.ɵɵtextInterpolate(issue_r17.Field ? issue_r17.Field + ": " : "");
620
+ i0.ɵɵtextInterpolate(issue_r32.Field ? issue_r32.Field + ": " : "");
377
621
  i0.ɵɵadvance();
378
- i0.ɵɵtextInterpolate1("", issue_r17.Message, " ");
622
+ i0.ɵɵtextInterpolate1("", issue_r32.Message, " ");
379
623
  i0.ɵɵadvance();
380
- i0.ɵɵconditional(issue_r17.FixRecommendation ? 4 : -1);
624
+ i0.ɵɵconditional(issue_r32.FixRecommendation ? 4 : -1);
381
625
  } }
382
- function FeaturePipelineBuilderComponent_Conditional_91_Template(rf, ctx) { if (rf & 1) {
383
- i0.ɵɵelementStart(0, "div", 28)(1, "h4");
384
- i0.ɵɵelement(2, "i", 57);
626
+ function FeaturePipelineBuilderComponent_Conditional_106_Template(rf, ctx) { if (rf & 1) {
627
+ i0.ɵɵelementStart(0, "div", 33)(1, "h4");
628
+ i0.ɵɵelement(2, "i", 78);
385
629
  i0.ɵɵtext(3, " Specification Issues");
386
630
  i0.ɵɵelementEnd();
387
631
  i0.ɵɵelementStart(4, "ul");
388
- i0.ɵɵrepeaterCreate(5, FeaturePipelineBuilderComponent_Conditional_91_For_6_Template, 5, 3, "li", null, i0.ɵɵrepeaterTrackByIndex);
632
+ i0.ɵɵrepeaterCreate(5, FeaturePipelineBuilderComponent_Conditional_106_For_6_Template, 5, 3, "li", null, i0.ɵɵrepeaterTrackByIndex);
389
633
  i0.ɵɵelementEnd()();
390
634
  } if (rf & 2) {
391
635
  const ctx_r1 = i0.ɵɵnextContext();
392
636
  i0.ɵɵadvance(5);
393
637
  i0.ɵɵrepeater(ctx_r1.validationErrors);
394
638
  } }
639
+ function FeaturePipelineBuilderComponent_For_110_Template(rf, ctx) { if (rf & 1) {
640
+ i0.ɵɵelementStart(0, "li");
641
+ i0.ɵɵtext(1);
642
+ i0.ɵɵelementEnd();
643
+ } if (rf & 2) {
644
+ const issue_r33 = ctx.$implicit;
645
+ i0.ɵɵadvance();
646
+ i0.ɵɵtextInterpolate(issue_r33);
647
+ } }
648
+ /**
649
+ * The confidence floor typed into the builder, as a number. A blank or non-numeric entry is NaN, so the spec
650
+ * check reports it ("must be a number greater than 0 and less than 1, but is NaN") instead of the builder
651
+ * guessing a value; an out-of-range number is kept as typed, for the same check to report.
652
+ */
653
+ export function ParseConfidenceFloor(raw) {
654
+ const text = raw.trim();
655
+ return text.length === 0 ? Number.NaN : Number(text);
656
+ }
395
657
  export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
396
658
  cdr = inject(ChangeDetectorRef);
397
659
  Record = null;
@@ -406,6 +668,132 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
406
668
  Outputs: [],
407
669
  Caching: { Cacheable: false },
408
670
  };
671
+ AvailablePipelineTypes = [
672
+ { Name: 'LLM', Description: null },
673
+ ];
674
+ ShowTypeSwitchConfirm = false;
675
+ PendingPipelineType = null;
676
+ TypeSwitchIssues = [];
677
+ get CurrentPipelineTypeName() {
678
+ return this.spec.PipelineType?.trim() || 'LLM';
679
+ }
680
+ get CurrentCapabilities() {
681
+ return GetFeaturePipelineCapabilities(this.CurrentPipelineTypeName);
682
+ }
683
+ get IsDecisionPipeline() {
684
+ return this.CurrentPipelineTypeName.toLowerCase() === 'decision';
685
+ }
686
+ AvailableEscalationTargets = [];
687
+ /** Whether the escalation targets were loaded. False until a load succeeds, and after one fails. */
688
+ EscalationTargetsLoaded = false;
689
+ /** Why the last load of escalation targets failed, or null when it did not. */
690
+ EscalationTargetsLoadError = null;
691
+ /** Numbers each target load, so a slower earlier load cannot overwrite a later one. */
692
+ escalationTargetsLoadSeq = 0;
693
+ get IsEscalationEnabled() {
694
+ return this.spec.Escalation !== undefined && this.spec.Escalation !== null;
695
+ }
696
+ /** The target picker's empty option: what to pick, or why there is nothing to pick. */
697
+ get EscalationTargetsPlaceholder() {
698
+ if (this.EscalationTargetsLoadError) {
699
+ return '— Pipelines could not be loaded —';
700
+ }
701
+ return this.AvailableEscalationTargets.length > 0 ? '— Select LLM Pipeline —' : '— No other Infer pipelines on this entity —';
702
+ }
703
+ /** Whether `target` is the spec's escalation target. IDs compare through UUIDsEqual, as the target check does. */
704
+ IsSavedEscalationTarget(target) {
705
+ return UUIDsEqual(target.ID, this.spec.Escalation?.PipelineID);
706
+ }
707
+ /** Whether the target picker lists the spec's escalation target. Until the targets load, or when it is not among them, the placeholder shows. */
708
+ get SavedEscalationTargetListed() {
709
+ return this.AvailableEscalationTargets.some((t) => this.IsSavedEscalationTarget(t));
710
+ }
711
+ /**
712
+ * Whether to offer the Capture Reasoning setting: for a type that produces reasoning, and for any spec
713
+ * that already asks for it, so a pipeline switched to a type without reasoning can turn it off.
714
+ */
715
+ get ShowCaptureReasoning() {
716
+ return this.CurrentCapabilities.ProducesReasoning || this.spec.CaptureReasoning === true;
717
+ }
718
+ get SelectedPipelineTypeDescription() {
719
+ const cur = this.CurrentPipelineTypeName.toLowerCase();
720
+ const opt = this.AvailablePipelineTypes.find((t) => t.Name.toLowerCase() === cur);
721
+ return opt?.Description ?? '';
722
+ }
723
+ get AvailableTargetModes() {
724
+ const all = [
725
+ { Value: 'field', Label: 'Entity Column (field)' },
726
+ { Value: 'child', Label: 'Child Rows (child)' },
727
+ { Value: 'tags', Label: 'Taxonomy Tags (tags)' },
728
+ ];
729
+ const supported = this.CurrentCapabilities.TargetModes;
730
+ return all.filter((m) => supported.includes(m.Value));
731
+ }
732
+ get AvailableConstraintTypes() {
733
+ const options = [];
734
+ if (!this.IsDecisionPipeline) {
735
+ options.push({ Value: 'none', Label: 'None / Unconstrained' });
736
+ }
737
+ if (this.CurrentCapabilities.ConstraintTypes.includes('boolean')) {
738
+ options.push({ Value: 'boolean', Label: 'Boolean' });
739
+ }
740
+ if (this.CurrentCapabilities.ConstraintTypes.includes('enum')) {
741
+ options.push({ Value: 'enum', Label: 'Enum (Allowed Values)' });
742
+ }
743
+ if (this.CurrentCapabilities.ConstraintTypes.includes('numeric')) {
744
+ options.push({ Value: 'numeric', Label: this.IsDecisionPipeline ? 'Numeric (Levels)' : 'Numeric (Min/Max)' });
745
+ }
746
+ if (this.CurrentCapabilities.ConstraintTypes.includes('freetext')) {
747
+ options.push({ Value: 'freetext', Label: 'Free Text' });
748
+ }
749
+ return options;
750
+ }
751
+ // The pickers mark the saved option with [selected] on each <option>, not [value] on the <select>. A [value]
752
+ // binding runs before @for creates the options, matches nothing, and does not run again, so the browser shows
753
+ // the first option. When the saved value is not listed, the placeholder is selected. A placeholder inside @if
754
+ // binds [selected] instead of carrying the attribute, because on a live type switch the attribute loses to the
755
+ // option still selected, which is then removed.
756
+ /** Whether `name` is the spec's pipeline type. Names compare case-insensitively, as {@link IsDecisionPipeline} does. */
757
+ IsCurrentPipelineType(name) {
758
+ return name.toLowerCase() === this.CurrentPipelineTypeName.toLowerCase();
759
+ }
760
+ /** The output's saved constraint type as the constraint picker names it: `'none'` when it has none. */
761
+ SavedConstraintType(output) {
762
+ return output.Constraint?.Type || 'none';
763
+ }
764
+ /** Whether the constraint picker lists the output's saved type. A Decision output with no constraint, or one this type cannot produce, is not listed. */
765
+ IsConstraintTypeOffered(output) {
766
+ const saved = this.SavedConstraintType(output);
767
+ return this.AvailableConstraintTypes.some((t) => t.Value === saved);
768
+ }
769
+ /** Whether the target mode picker lists the output's saved mode. */
770
+ IsTargetModeOffered(output) {
771
+ return this.AvailableTargetModes.some((m) => m.Value === output.Target.Mode);
772
+ }
773
+ /** Whether the target field picker lists a field named `name`. */
774
+ IsEntityFieldListed(name) {
775
+ return !!name && this.EntityFields.some((f) => f.Name === name);
776
+ }
777
+ /** Whether the child entity picker lists an entity named `name`. */
778
+ IsEntityListed(name) {
779
+ return !!name && this.AvailableEntities.some((e) => e.Name === name);
780
+ }
781
+ /** Whether `prompt` is the pipeline's saved prompt. */
782
+ IsSavedPrompt(prompt) {
783
+ return UUIDsEqual(prompt.ID, this.Record ? this.Record.PromptID : this.spec.PromptID);
784
+ }
785
+ /** Whether the prompt picker lists the pipeline's saved prompt. */
786
+ get SavedPromptListed() {
787
+ return this.AvailablePrompts.some((p) => this.IsSavedPrompt(p));
788
+ }
789
+ /** Whether `doc` is the spec's saved entity document. */
790
+ IsSavedEntityDoc(doc) {
791
+ return UUIDsEqual(doc.ID, this.spec.Context.EntityDocumentID);
792
+ }
793
+ /** Whether the entity document picker lists the spec's saved document. */
794
+ get SavedEntityDocListed() {
795
+ return this.AvailableDocs.some((d) => this.IsSavedEntityDoc(d));
796
+ }
409
797
  AvailablePrompts = [];
410
798
  /** @deprecated Use {@link AvailablePrompts}. */
411
799
  get availablePrompts() {
@@ -498,13 +886,20 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
498
886
  }
499
887
  async ngOnInit() {
500
888
  this.AvailableEntities = [...this.ProviderToUse.Entities].sort((a, b) => (a.DisplayName || a.Name).localeCompare(b.DisplayName || b.Name));
889
+ await this.loadPipelineTypes();
501
890
  await this.loadPrompts();
502
891
  await this.loadEntityDocs();
892
+ await this.LoadEscalationTargets();
503
893
  this.SyncFromRecord();
504
894
  }
505
895
  ngOnChanges(changes) {
506
896
  if (changes['Record'] || changes['EntityID']) {
507
897
  this.SyncFromRecord();
898
+ // ngOnInit loads the targets for the first binding; reload only when the pipeline or entity changes after it
899
+ const firstBinding = Object.values(changes).every((change) => change.firstChange);
900
+ if (!firstBinding) {
901
+ void this.LoadEscalationTargets();
902
+ }
508
903
  }
509
904
  }
510
905
  SyncFromRecord() {
@@ -519,6 +914,16 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
519
914
  this.spec.Context = parsed.Context ?? {};
520
915
  this.spec.Caching = parsed.Caching ?? { Cacheable: false };
521
916
  this.spec.ProcessorExtensionKey = parsed.ProcessorExtensionKey;
917
+ this.spec.PipelineType = parsed.PipelineType;
918
+ if (parsed.Escalation) {
919
+ this.spec.Escalation = { ...parsed.Escalation };
920
+ }
921
+ else {
922
+ delete this.spec.Escalation;
923
+ }
924
+ // Carried so the capability check sees what the runtime sees, and the next edit keeps them
925
+ this.spec.CaptureReasoning = parsed.CaptureReasoning;
926
+ this.spec.Watermark = parsed.Watermark;
522
927
  }
523
928
  }
524
929
  }
@@ -550,6 +955,7 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
550
955
  if (this.Record?.PromptID) {
551
956
  this.SelectedPrompt = this.AvailablePrompts.find((p) => UUIDsEqual(p.ID, this.Record?.PromptID)) ?? null;
552
957
  }
958
+ this.ensureLoadedTypeIncluded();
553
959
  this.recomputeValidation();
554
960
  this.cdr.detectChanges();
555
961
  }
@@ -557,6 +963,71 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
557
963
  syncFromRecord() {
558
964
  return this.SyncFromRecord();
559
965
  }
966
+ async loadPipelineTypes() {
967
+ let activeRows = [];
968
+ try {
969
+ await KnowledgeHubMetadataEngine.Instance.Config(false, this.ProviderToUse.CurrentUser, this.ProviderToUse);
970
+ const engineTypes = KnowledgeHubMetadataEngine.Instance.FeaturePipelineTypes;
971
+ if (Array.isArray(engineTypes)) {
972
+ activeRows = engineTypes.filter((t) => t.Status === 'Active');
973
+ }
974
+ }
975
+ catch (error) {
976
+ LogError('Error loading Feature Pipeline Types from KnowledgeHubMetadataEngine', undefined, error);
977
+ }
978
+ if (activeRows.length > 0) {
979
+ this.AvailablePipelineTypes = activeRows.map((t) => ({
980
+ Name: t.Name,
981
+ Description: t.Description || null,
982
+ }));
983
+ if (!this.AvailablePipelineTypes.some((t) => t.Name.toLowerCase() === 'llm')) {
984
+ this.AvailablePipelineTypes.unshift({
985
+ Name: 'LLM',
986
+ Description: null,
987
+ });
988
+ }
989
+ }
990
+ else {
991
+ this.AvailablePipelineTypes = [
992
+ {
993
+ Name: 'LLM',
994
+ Description: null,
995
+ },
996
+ ];
997
+ }
998
+ this.ensureLoadedTypeIncluded();
999
+ }
1000
+ ensureLoadedTypeIncluded() {
1001
+ const typeName = this.spec.PipelineType?.trim();
1002
+ if (!typeName || typeName.toLowerCase() === 'llm') {
1003
+ return;
1004
+ }
1005
+ const exists = this.AvailablePipelineTypes.some((t) => t.Name.toLowerCase() === typeName.toLowerCase());
1006
+ if (exists) {
1007
+ return;
1008
+ }
1009
+ let isInactive = false;
1010
+ let desc = null;
1011
+ try {
1012
+ const engineTypes = KnowledgeHubMetadataEngine.Instance.FeaturePipelineTypes;
1013
+ if (Array.isArray(engineTypes)) {
1014
+ const match = engineTypes.find((t) => t.Name?.trim().toLowerCase() === typeName.toLowerCase());
1015
+ if (match) {
1016
+ isInactive = match.Status !== 'Active';
1017
+ desc = match.Description || null;
1018
+ }
1019
+ }
1020
+ }
1021
+ catch {
1022
+ // Ignore
1023
+ }
1024
+ const label = isInactive ? `${typeName} (inactive)` : `${typeName} (unrecognized)`;
1025
+ this.AvailablePipelineTypes.push({
1026
+ Name: typeName,
1027
+ DisplayName: label,
1028
+ Description: desc,
1029
+ });
1030
+ }
560
1031
  async loadPrompts() {
561
1032
  try {
562
1033
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
@@ -599,6 +1070,106 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
599
1070
  LogError('Error loading Entity Documents', undefined, error);
600
1071
  }
601
1072
  }
1073
+ /**
1074
+ * Loads the Infer pipelines on this pipeline's entity that it could escalate to. With no entity there is
1075
+ * nothing to offer, so nothing is loaded. A failed load is recorded in {@link EscalationTargetsLoadError},
1076
+ * not taken to mean there are no targets. Only the latest load's result is kept.
1077
+ */
1078
+ async LoadEscalationTargets() {
1079
+ const seq = ++this.escalationTargetsLoadSeq;
1080
+ const targetEntityID = this.Record?.EntityID || this.EntityID;
1081
+ const outcome = targetEntityID
1082
+ ? await this.fetchEscalationTargets(targetEntityID)
1083
+ : { Targets: [], Error: null };
1084
+ if (seq !== this.escalationTargetsLoadSeq) {
1085
+ return; // a later load, for a later Record or entity, has superseded this one
1086
+ }
1087
+ this.AvailableEscalationTargets = outcome.Targets;
1088
+ this.EscalationTargetsLoadError = outcome.Error;
1089
+ this.EscalationTargetsLoaded = outcome.Error === null;
1090
+ this.recomputeValidation();
1091
+ this.cdr.detectChanges();
1092
+ }
1093
+ /** The Infer pipelines on the entity, other than this one, each with its parsed spec; or why they could not be read. */
1094
+ async fetchEscalationTargets(entityID) {
1095
+ try {
1096
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1097
+ const res = await rv.RunView({
1098
+ EntityName: 'MJ: Record Processes',
1099
+ Fields: ['ID', 'Name', 'Description', 'Entity', 'EntityID', 'WorkType', 'Status', 'PromptID', 'Configuration'],
1100
+ ExtraFilter: `WorkType='Infer' AND EntityID='${EscapeSQLString(entityID)}'`,
1101
+ OrderBy: 'Name',
1102
+ ResultType: 'simple',
1103
+ });
1104
+ if (!res.Success) {
1105
+ const reason = res.ErrorMessage || 'unknown error';
1106
+ LogError(`Failed to load Escalation Targets: ${reason}`);
1107
+ return { Targets: [], Error: reason };
1108
+ }
1109
+ const currentID = this.Record?.ID;
1110
+ const targets = (res.Results ?? [])
1111
+ .filter((r) => !currentID || !UUIDsEqual(r.ID, currentID))
1112
+ .map((r) => ({ ...r, ParsedSpec: this.parseTargetSpec(r.Configuration) }));
1113
+ return { Targets: targets, Error: null };
1114
+ }
1115
+ catch (error) {
1116
+ LogError('Error loading Escalation Targets', undefined, error);
1117
+ return { Targets: [], Error: error instanceof Error ? error.message : String(error) };
1118
+ }
1119
+ }
1120
+ /** A target's Configuration as a spec, or undefined when it is empty or not a JSON object. */
1121
+ parseTargetSpec(configuration) {
1122
+ const parsed = configuration ? SafeJSONParse(configuration) : null;
1123
+ return parsed && typeof parsed === 'object' ? parsed : undefined;
1124
+ }
1125
+ /**
1126
+ * Why a pipeline cannot be this pipeline's escalation target, or null when it can. Beyond the shared row and
1127
+ * output checks, its own spec must pass `ValidateSpec`, as the engine requires before it builds the target.
1128
+ */
1129
+ GetTargetProblem(target) {
1130
+ const targetEntityID = this.Record?.EntityID || this.EntityID || '';
1131
+ const rowProblem = FindEscalationTargetRowProblem(target, targetEntityID);
1132
+ if (rowProblem) {
1133
+ return rowProblem;
1134
+ }
1135
+ const specError = target.ParsedSpec ? validateSpec(target.ParsedSpec).find((issue) => issue.Severity === 'error') : undefined;
1136
+ if (specError) {
1137
+ return `has an invalid spec: ${specError.Message}`;
1138
+ }
1139
+ return FindEscalationTargetSpecProblem(target.ParsedSpec, this.spec.Outputs ?? []);
1140
+ }
1141
+ OnEscalationToggle(event) {
1142
+ const checked = event.target.checked;
1143
+ if (checked) {
1144
+ this.spec.Escalation = {
1145
+ PipelineID: this.spec.Escalation?.PipelineID || '',
1146
+ BelowConfidence: this.spec.Escalation?.BelowConfidence ?? 0.7,
1147
+ };
1148
+ }
1149
+ else {
1150
+ delete this.spec.Escalation;
1151
+ }
1152
+ this.emitChanges();
1153
+ }
1154
+ OnEscalationTargetChange(event) {
1155
+ const val = event.target.value;
1156
+ if (!this.spec.Escalation) {
1157
+ this.spec.Escalation = {
1158
+ PipelineID: val,
1159
+ BelowConfidence: 0.7,
1160
+ };
1161
+ }
1162
+ else {
1163
+ this.spec.Escalation.PipelineID = val;
1164
+ }
1165
+ this.emitChanges();
1166
+ }
1167
+ /** Sets the confidence floor from its input, as a number; a blank or invalid entry is NaN, which the spec check reports. */
1168
+ OnEscalationFloorChange(event) {
1169
+ const floor = ParseConfidenceFloor(event.target.value);
1170
+ this.spec.Escalation = { PipelineID: this.spec.Escalation?.PipelineID ?? '', BelowConfidence: floor };
1171
+ this.emitChanges();
1172
+ }
602
1173
  OnContextModeChange(event) {
603
1174
  this.ContextMode = event.target.value;
604
1175
  if (!this.spec.Context)
@@ -676,6 +1247,12 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
676
1247
  EntityFieldName: this.EntityFields.length > 0 ? this.EntityFields[0].Name : '',
677
1248
  },
678
1249
  };
1250
+ if (this.IsDecisionPipeline) {
1251
+ newOutput.Constraint = {
1252
+ Type: 'boolean',
1253
+ OnViolation: 'fail',
1254
+ };
1255
+ }
679
1256
  this.spec.Outputs.push(newOutput);
680
1257
  this.emitChanges();
681
1258
  }
@@ -730,6 +1307,9 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
730
1307
  const target = this.spec.Outputs[index].Target;
731
1308
  if (target.Mode === 'field') {
732
1309
  target.EntityFieldName = fieldName;
1310
+ if (this.spec.Outputs[index].Constraint?.Type === 'enum') {
1311
+ this.prefillEnumValuesFromField(this.spec.Outputs[index]);
1312
+ }
733
1313
  }
734
1314
  this.emitChanges();
735
1315
  }
@@ -757,9 +1337,15 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
757
1337
  }
758
1338
  else if (type === 'enum') {
759
1339
  output.Constraint = { Type: 'enum', Values: [], OnViolation: 'fail' };
1340
+ this.prefillEnumValuesFromField(output);
760
1341
  }
761
1342
  else if (type === 'numeric') {
762
- output.Constraint = { Type: 'numeric', Min: 0, Max: 100, OnViolation: 'fail' };
1343
+ if (this.IsDecisionPipeline) {
1344
+ output.Constraint = { Type: 'numeric', Levels: ['Low', 'Medium', 'High'], OnViolation: 'fail' };
1345
+ }
1346
+ else {
1347
+ output.Constraint = { Type: 'numeric', Min: 0, Max: 100, OnViolation: 'fail' };
1348
+ }
763
1349
  }
764
1350
  else if (type === 'boolean') {
765
1351
  output.Constraint = { Type: 'boolean', OnViolation: 'fail' };
@@ -913,7 +1499,213 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
913
1499
  updateCacheScope(event) {
914
1500
  return this.UpdateCacheScope(event);
915
1501
  }
1502
+ /** Turns capture of the model's rationale on or off. Off removes the flag, so a spec that never set it keeps its hash. */
1503
+ UpdateCaptureReasoning(event) {
1504
+ if (event.target.value === 'true') {
1505
+ this.spec.CaptureReasoning = true;
1506
+ }
1507
+ else {
1508
+ delete this.spec.CaptureReasoning;
1509
+ }
1510
+ this.emitChanges();
1511
+ }
1512
+ OnPipelineTypeSelect(event) {
1513
+ const target = event.target;
1514
+ const newType = target.value;
1515
+ const currentType = this.CurrentPipelineTypeName;
1516
+ if (newType.toLowerCase() === currentType.toLowerCase()) {
1517
+ return;
1518
+ }
1519
+ const isNewTypeLLM = newType.trim().toLowerCase() === 'llm';
1520
+ const candidateSpec = {
1521
+ ...this.spec,
1522
+ PipelineType: isNewTypeLLM ? undefined : newType.trim(),
1523
+ };
1524
+ if (newType.trim().toLowerCase() !== 'decision') {
1525
+ delete candidateSpec.Escalation;
1526
+ }
1527
+ const newCapabilities = GetFeaturePipelineCapabilities(newType);
1528
+ const lookup = this.buildFieldValuesLookup();
1529
+ const capIssues = ValidateOutputsAgainstCapabilities(candidateSpec, newCapabilities, lookup);
1530
+ let specIssues = [];
1531
+ const entity = this.Record?.EntityID ? this.ProviderToUse.EntityByID(this.Record.EntityID) : null;
1532
+ if (entity) {
1533
+ const stub = {
1534
+ Name: entity.Name,
1535
+ Fields: (entity.Fields ?? []).map((f) => ({
1536
+ Name: f.Name,
1537
+ TSType: f.TSType,
1538
+ IsVirtual: f.IsVirtual,
1539
+ AllowsNull: f.AllowsNull,
1540
+ RelatedEntity: f.RelatedEntity,
1541
+ RelatedEntityID: f.RelatedEntityID,
1542
+ EntityFieldValues: f.EntityFieldValues ? f.EntityFieldValues.map((v) => ({ Value: v.Value, Code: v.Code })) : undefined,
1543
+ })),
1544
+ };
1545
+ specIssues = validateSpec(candidateSpec, stub).filter((i) => i.Severity === 'error').map((i) => i.Message);
1546
+ }
1547
+ const allIssues = Array.from(new Set([...capIssues, ...specIssues]));
1548
+ if (allIssues.length > 0) {
1549
+ target.value = currentType;
1550
+ this.PendingPipelineType = newType;
1551
+ this.TypeSwitchIssues = allIssues;
1552
+ this.ShowTypeSwitchConfirm = true;
1553
+ this.cdr.detectChanges();
1554
+ }
1555
+ else {
1556
+ this.ApplyPipelineTypeChange(newType);
1557
+ }
1558
+ }
1559
+ OnTypeSwitchConfirmed() {
1560
+ this.ShowTypeSwitchConfirm = false;
1561
+ if (this.PendingPipelineType) {
1562
+ this.ApplyPipelineTypeChange(this.PendingPipelineType);
1563
+ this.PendingPipelineType = null;
1564
+ }
1565
+ this.TypeSwitchIssues = [];
1566
+ this.cdr.detectChanges();
1567
+ }
1568
+ OnTypeSwitchCancelled() {
1569
+ this.ShowTypeSwitchConfirm = false;
1570
+ this.PendingPipelineType = null;
1571
+ this.TypeSwitchIssues = [];
1572
+ this.cdr.detectChanges();
1573
+ }
1574
+ ApplyPipelineTypeChange(newType) {
1575
+ if (newType.trim().toLowerCase() === 'llm') {
1576
+ delete this.spec.PipelineType;
1577
+ }
1578
+ else {
1579
+ this.spec.PipelineType = newType.trim();
1580
+ }
1581
+ if (!this.IsDecisionPipeline) {
1582
+ delete this.spec.Escalation;
1583
+ }
1584
+ this.emitChanges();
1585
+ }
1586
+ GetNumericLevels(output) {
1587
+ if (!output.Constraint || output.Constraint.Type !== 'numeric' || !Array.isArray(output.Constraint.Levels)) {
1588
+ return [];
1589
+ }
1590
+ return output.Constraint.Levels;
1591
+ }
1592
+ AddNumericLevel(index) {
1593
+ const output = this.spec.Outputs[index];
1594
+ if (output?.Constraint?.Type === 'numeric') {
1595
+ if (!Array.isArray(output.Constraint.Levels) || output.Constraint.Levels.length === 0) {
1596
+ output.Constraint.Levels = ['Low', 'Medium', 'High'];
1597
+ this.emitChanges();
1598
+ return;
1599
+ }
1600
+ if (output.Constraint.Levels.length < 10) {
1601
+ output.Constraint.Levels.push(`Level ${output.Constraint.Levels.length + 1}`);
1602
+ this.emitChanges();
1603
+ }
1604
+ }
1605
+ }
1606
+ RemoveNumericLevel(outputIndex, levelIndex) {
1607
+ const output = this.spec.Outputs[outputIndex];
1608
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1609
+ if (output.Constraint.Levels.length > 2) {
1610
+ output.Constraint.Levels.splice(levelIndex, 1);
1611
+ this.emitChanges();
1612
+ }
1613
+ }
1614
+ }
1615
+ UpdateNumericLevel(outputIndex, levelIndex, event) {
1616
+ const val = event.target.value;
1617
+ const output = this.spec.Outputs[outputIndex];
1618
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1619
+ output.Constraint.Levels[levelIndex] = val;
1620
+ this.emitChanges();
1621
+ }
1622
+ }
1623
+ MoveNumericLevel(outputIndex, levelIndex, direction) {
1624
+ const output = this.spec.Outputs[outputIndex];
1625
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1626
+ const targetIndex = direction === 'up' ? levelIndex - 1 : levelIndex + 1;
1627
+ if (targetIndex >= 0 && targetIndex < output.Constraint.Levels.length) {
1628
+ const item = output.Constraint.Levels.splice(levelIndex, 1)[0];
1629
+ output.Constraint.Levels.splice(targetIndex, 0, item);
1630
+ this.emitChanges();
1631
+ }
1632
+ }
1633
+ }
1634
+ GetEnumValues(output) {
1635
+ if (output.Constraint && output.Constraint.Type === 'enum' && Array.isArray(output.Constraint.Values)) {
1636
+ return output.Constraint.Values;
1637
+ }
1638
+ return [];
1639
+ }
1640
+ GetEnumValueDescription(output, val) {
1641
+ if (output.Constraint && output.Constraint.Type === 'enum') {
1642
+ return output.Constraint.ValueDescriptions?.[val] ?? '';
1643
+ }
1644
+ return '';
1645
+ }
1646
+ UpdateEnumValueDescription(outputIndex, val, event) {
1647
+ const desc = event.target.value;
1648
+ const output = this.spec.Outputs[outputIndex];
1649
+ if (output?.Constraint && output.Constraint.Type === 'enum') {
1650
+ if (!output.Constraint.ValueDescriptions) {
1651
+ output.Constraint.ValueDescriptions = {};
1652
+ }
1653
+ output.Constraint.ValueDescriptions[val] = desc;
1654
+ this.emitChanges();
1655
+ }
1656
+ }
1657
+ GetBooleanThreshold(output) {
1658
+ if (output.Constraint && output.Constraint.Type === 'boolean' && output.Constraint.Threshold !== undefined) {
1659
+ return output.Constraint.Threshold;
1660
+ }
1661
+ return null;
1662
+ }
1663
+ UpdateBooleanThreshold(outputIndex, event) {
1664
+ const raw = event.target.value.trim();
1665
+ const output = this.spec.Outputs[outputIndex];
1666
+ if (output?.Constraint && output.Constraint.Type === 'boolean') {
1667
+ if (raw === '') {
1668
+ delete output.Constraint.Threshold;
1669
+ }
1670
+ else {
1671
+ const val = parseFloat(raw);
1672
+ output.Constraint.Threshold = isNaN(val) ? undefined : val;
1673
+ }
1674
+ this.emitChanges();
1675
+ }
1676
+ }
1677
+ prefillEnumValuesFromField(output) {
1678
+ if (output.Target.Mode !== 'field' || output.Constraint?.Type !== 'enum') {
1679
+ return;
1680
+ }
1681
+ const fieldName = output.Target.EntityFieldName;
1682
+ if (!fieldName) {
1683
+ return;
1684
+ }
1685
+ const field = this.EntityFields.find((f) => f.Name === fieldName);
1686
+ if (field && Array.isArray(field.EntityFieldValues) && field.EntityFieldValues.length > 0) {
1687
+ if (!output.Constraint.Values || output.Constraint.Values.length === 0) {
1688
+ output.Constraint.Values = field.EntityFieldValues.map((v) => v.Value);
1689
+ }
1690
+ if (this.IsDecisionPipeline) {
1691
+ if (!output.Constraint.ValueDescriptions) {
1692
+ output.Constraint.ValueDescriptions = {};
1693
+ }
1694
+ for (const v of field.EntityFieldValues) {
1695
+ if (!output.Constraint.ValueDescriptions[v.Value] && v.Description) {
1696
+ output.Constraint.ValueDescriptions[v.Value] = v.Description;
1697
+ }
1698
+ }
1699
+ }
1700
+ }
1701
+ }
916
1702
  emitChanges() {
1703
+ if (this.spec.PipelineType && this.spec.PipelineType.trim().toLowerCase() === 'llm') {
1704
+ delete this.spec.PipelineType;
1705
+ }
1706
+ if (!this.IsDecisionPipeline) {
1707
+ delete this.spec.Escalation;
1708
+ }
917
1709
  if (this.Record) {
918
1710
  this.spec.Name = this.Record.Name || '';
919
1711
  this.spec.Description = this.Record.Description || '';
@@ -940,6 +1732,12 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
940
1732
  }
941
1733
  this.Record.OutputMapping = JSON.stringify({ fields });
942
1734
  }
1735
+ buildFieldValuesLookup() {
1736
+ return (fieldName) => {
1737
+ const field = this.EntityFields.find((f) => f.Name.toLowerCase() === fieldName.toLowerCase());
1738
+ return field?.EntityFieldValues ? field.EntityFieldValues.map((v) => ({ Value: v.Value, Description: v.Description })) : undefined;
1739
+ };
1740
+ }
943
1741
  recomputeValidation() {
944
1742
  this.RenderedConstraintPreview = renderConstraintBlock(this.spec.Outputs);
945
1743
  const entity = this.Record?.EntityID ? this.ProviderToUse.EntityByID(this.Record.EntityID) : null;
@@ -959,168 +1757,268 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
959
1757
  this.ValidationErrors = validateSpec(this.spec, stub);
960
1758
  }
961
1759
  else {
962
- this.ValidationErrors = this.spec.Outputs.length === 0
963
- ? [{
964
- Path: 'Outputs',
1760
+ this.ValidationErrors = validateSpec(this.spec);
1761
+ }
1762
+ const lookup = this.buildFieldValuesLookup();
1763
+ const capIssues = ValidateOutputsAgainstCapabilities(this.spec, this.CurrentCapabilities, lookup);
1764
+ for (const capIssue of capIssues) {
1765
+ this.ValidationErrors.push({
1766
+ Path: 'Outputs',
1767
+ Severity: 'error',
1768
+ Message: capIssue,
1769
+ FixRecommendation: 'Adjust output configuration to match the selected pipeline capabilities.',
1770
+ });
1771
+ }
1772
+ if (this.IsDecisionPipeline && this.spec.Escalation && this.spec.Escalation.PipelineID && this.EscalationTargetsLoadError) {
1773
+ // The targets are unknown, not absent: say so, and leave the target to be checked at run time
1774
+ this.ValidationErrors.push({
1775
+ Path: 'Escalation.PipelineID',
1776
+ Severity: 'warning',
1777
+ Message: `The escalation target could not be checked: the pipelines on this entity could not be loaded (${this.EscalationTargetsLoadError}).`,
1778
+ FixRecommendation: 'Reopen the pipeline to retry. The target is still checked when the pipeline runs.',
1779
+ });
1780
+ }
1781
+ else if (this.IsDecisionPipeline && this.spec.Escalation) {
1782
+ const targetID = this.spec.Escalation.PipelineID;
1783
+ if (targetID && this.EscalationTargetsLoaded) {
1784
+ const match = this.AvailableEscalationTargets.find((t) => UUIDsEqual(t.ID, targetID));
1785
+ if (!match) {
1786
+ this.ValidationErrors.push({
1787
+ Path: 'Escalation.PipelineID',
965
1788
  Severity: 'error',
966
- Message: 'At least one output attribute must be configured',
967
- FixRecommendation: 'Click Add Output to configure an output attribute',
968
- }]
969
- : [];
1789
+ Message: `Escalation target pipeline '${targetID}' was not found on this entity.`,
1790
+ FixRecommendation: 'Select a valid Active LLM Feature Pipeline on this entity.',
1791
+ });
1792
+ }
1793
+ else {
1794
+ const problem = this.GetTargetProblem(match);
1795
+ if (problem) {
1796
+ this.ValidationErrors.push({
1797
+ Path: 'Escalation.PipelineID',
1798
+ Severity: 'error',
1799
+ Message: `Escalation target pipeline '${match.Name}' ${problem}.`,
1800
+ FixRecommendation: 'Select an Active LLM Feature Pipeline that produces every output of this Decision pipeline.',
1801
+ });
1802
+ }
1803
+ }
1804
+ }
970
1805
  }
971
1806
  const hasErrors = this.ValidationErrors.some((i) => i.Severity === 'error');
972
1807
  this.ValidChange.emit(!hasErrors);
973
1808
  }
974
1809
  static ɵfac = /*@__PURE__*/ (() => { let ɵFeaturePipelineBuilderComponent_BaseFactory; return function FeaturePipelineBuilderComponent_Factory(__ngFactoryType__) { return (ɵFeaturePipelineBuilderComponent_BaseFactory || (ɵFeaturePipelineBuilderComponent_BaseFactory = i0.ɵɵgetInheritedFactory(FeaturePipelineBuilderComponent)))(__ngFactoryType__ || FeaturePipelineBuilderComponent); }; })();
975
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelineBuilderComponent, selectors: [["mj-feature-pipeline-builder"]], inputs: { Record: "Record", EntityID: "EntityID" }, outputs: { SpecChange: "SpecChange", ValidChange: "ValidChange" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 92, vars: 13, consts: [[1, "fpb"], [1, "rpe-sec"], [1, "rpe-sec-h"], [1, "num"], [1, "rpe-desc"], [1, "rpe-grid3"], [1, "field"], [1, "mj-input", 3, "change", "value"], ["value", "fields"], ["value", "document"], ["value", "query"], ["placeholder", "e.g. FirstName, LastName, Title", 1, "mj-input", 3, "input", "value"], [1, "rpe-grid2"], ["value", "", "disabled", ""], [3, "value"], [1, "field", "rpe-mt"], [1, "rpe-sec-h", "fpb-split-h"], [1, "fpb-title-group"], ["mjButton", "", "size", "sm", "variant", "secondary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fpb-empty-outputs"], [1, "fpb-outputs-list"], ["value", "Checksum"], ["value", "UpdatedAt"], ["value", "None"], ["value", "true"], ["value", "false"], [1, "rpe-grid3", "rpe-mt"], [1, "fpb-issues-card", "fpb-issues-card--error"], ["placeholder", "UUID of approved Query", 1, "mj-input", "mono", 3, "input", "value"], [1, "rpe-static-text"], [1, "muted"], [1, "fpb-code-preview"], [1, "fa-solid", "fa-arrow-turn-up"], [1, "fpb-output-card"], [1, "fpb-output-head"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "fa-solid", "fa-trash"], ["placeholder", "e.g. SentimentScore", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. $.sentiment or $", 1, "mj-input", "mono", 3, "input", "value"], ["value", "field"], ["value", "child"], ["value", "tags"], ["value", "none"], ["value", "enum"], ["value", "numeric"], ["value", "boolean"], ["value", "freetext"], [1, "rpe-grid2", "rpe-mt"], ["value", "fail"], ["value", "null"], ["value", "coerce-to-other"], ["placeholder", "e.g. Positive, Neutral, Negative", 1, "mj-input", 3, "input", "value"], ["type", "number", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. CurrentJobTitle", 1, "mj-input", 3, "input", "value"], ["value", "pipeline"], ["value", "prompt"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function FeaturePipelineBuilderComponent_Template(rf, ctx) { if (rf & 1) {
976
- i0.ɵɵelementStart(0, "div", 0)(1, "section", 1)(2, "div", 2)(3, "span", 3);
977
- i0.ɵɵtext(4, "1");
1810
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelineBuilderComponent, selectors: [["mj-feature-pipeline-builder"]], inputs: { Record: "Record", EntityID: "EntityID" }, outputs: { SpecChange: "SpecChange", ValidChange: "ValidChange" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 111, vars: 18, consts: [[1, "fpb"], [1, "rpe-sec", "fpb-type-sec"], [1, "rpe-grid2"], [1, "field"], [1, "mj-input", 3, "change"], [3, "value", "selected"], [1, "rpe-static-text"], [1, "rpe-grid2", "rpe-mt"], [1, "rpe-sec"], [1, "rpe-sec-h"], [1, "num"], [1, "rpe-desc"], [1, "rpe-grid3"], [1, "mj-input", 3, "change", "value"], ["value", "fields"], ["value", "document"], ["value", "query"], ["placeholder", "e.g. FirstName, LastName, Title", 1, "mj-input", 3, "input", "value"], ["value", "", "disabled", "", 3, "selected"], [1, "field", "rpe-mt"], [1, "rpe-sec-h", "fpb-split-h"], [1, "fpb-title-group"], ["mjButton", "", "size", "sm", "variant", "secondary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fpb-empty-outputs"], [1, "fpb-outputs-list"], [1, "rpe-sec", "fpb-escalation-sec"], ["value", "Checksum"], ["value", "UpdatedAt"], ["value", "None"], ["value", "true"], ["value", "false"], [1, "rpe-grid3", "rpe-mt"], [1, "fpb-issues-card", "fpb-issues-card--error"], ["Type", "warning", "Title", "Switch Pipeline Type", "ConfirmText", "Switch Anyway", "CancelText", "Cancel", 3, "VisibleChange", "Confirmed", "Cancelled", "Visible", "Message"], [1, "fpb-confirm-issues"], [1, "mj-input", "fpb-reasoning-select", 3, "change", "value"], ["placeholder", "UUID of approved Query", 1, "mj-input", "mono", 3, "input", "value"], [1, "muted"], [1, "fpb-code-preview"], [1, "fa-solid", "fa-arrow-turn-up"], [1, "fpb-output-card"], [1, "fpb-output-head"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "fa-solid", "fa-trash"], ["placeholder", "e.g. SentimentScore", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. $.sentiment or $", 1, "mj-input", "mono", 3, "input", "value"], ["value", "none", "disabled", "", 3, "selected"], ["value", "fail"], ["value", "null"], ["value", "coerce-to-other"], ["placeholder", "e.g. Positive, Neutral, Negative", 1, "mj-input", 3, "input", "value"], [1, "fpb-enum-descriptions"], [1, "fpb-enum-desc-row"], [1, "fpb-enum-val-badge"], [1, "mj-input", 3, "input", "value", "placeholder"], [1, "fpb-levels-header"], ["mjButton", "", "size", "sm", "variant", "secondary", "type", "button", 3, "click", "disabled"], [1, "fpb-levels-list"], [1, "fpb-level-row"], [1, "fpb-level-num"], ["placeholder", "Level label (e.g. Low, Medium, High)", 1, "mj-input", 3, "input", "value"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Move Up", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-up"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Move Down", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-down"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Remove Level", 3, "click", "disabled"], ["type", "number", 1, "mj-input", 3, "input", "value"], ["type", "number", "min", "0", "max", "1", "step", "0.05", "placeholder", "0.5", 1, "mj-input", 3, "input", "value"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "fpb-escalation-toggle-row"], [1, "fpb-checkbox-label"], ["type", "checkbox", 3, "change", "checked"], [3, "value", "disabled", "selected"], ["type", "number", "min", "0", "max", "1", "step", "0.05", "placeholder", "0.7", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. CurrentJobTitle", 1, "mj-input", 3, "input", "value"], ["value", "pipeline"], ["value", "prompt"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function FeaturePipelineBuilderComponent_Template(rf, ctx) { if (rf & 1) {
1811
+ i0.ɵɵelementStart(0, "div", 0)(1, "section", 1)(2, "div", 2)(3, "div", 3)(4, "label");
1812
+ i0.ɵɵtext(5, "Pipeline Type");
1813
+ i0.ɵɵelementEnd();
1814
+ i0.ɵɵelementStart(6, "select", 4);
1815
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_6_listener($event) { return ctx.OnPipelineTypeSelect($event); });
1816
+ i0.ɵɵrepeaterCreate(7, FeaturePipelineBuilderComponent_For_8_Template, 2, 3, "option", 5, _forTrack0);
1817
+ i0.ɵɵelementEnd()();
1818
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
1819
+ i0.ɵɵtext(11, "Type Description");
978
1820
  i0.ɵɵelementEnd();
979
- i0.ɵɵelementStart(5, "h3");
980
- i0.ɵɵtext(6, "Context Source");
1821
+ i0.ɵɵelementStart(12, "div", 6);
1822
+ i0.ɵɵtext(13);
1823
+ i0.ɵɵelementEnd()()();
1824
+ i0.ɵɵconditionalCreate(14, FeaturePipelineBuilderComponent_Conditional_14_Template, 9, 1, "div", 7);
1825
+ i0.ɵɵelementEnd();
1826
+ i0.ɵɵelementStart(15, "section", 8)(16, "div", 9)(17, "span", 10);
1827
+ i0.ɵɵtext(18, "1");
1828
+ i0.ɵɵelementEnd();
1829
+ i0.ɵɵelementStart(19, "h3");
1830
+ i0.ɵɵtext(20, "Context Source");
981
1831
  i0.ɵɵelementEnd()();
982
- i0.ɵɵelementStart(7, "p", 4);
983
- i0.ɵɵtext(8, "Choose how data from each record is extracted and formatted before being sent to the LLM prompt.");
1832
+ i0.ɵɵelementStart(21, "p", 11);
1833
+ i0.ɵɵtext(22, "Choose how data from each record is extracted and formatted before being sent to the LLM prompt.");
984
1834
  i0.ɵɵelementEnd();
985
- i0.ɵɵelementStart(9, "div", 5)(10, "div", 6)(11, "label");
986
- i0.ɵɵtext(12, "Context Mode");
1835
+ i0.ɵɵelementStart(23, "div", 12)(24, "div", 3)(25, "label");
1836
+ i0.ɵɵtext(26, "Context Mode");
987
1837
  i0.ɵɵelementEnd();
988
- i0.ɵɵelementStart(13, "select", 7);
989
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_13_listener($event) { return ctx.onContextModeChange($event); });
990
- i0.ɵɵelementStart(14, "option", 8);
991
- i0.ɵɵtext(15, "Record Fields");
1838
+ i0.ɵɵelementStart(27, "select", 13);
1839
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_27_listener($event) { return ctx.onContextModeChange($event); });
1840
+ i0.ɵɵelementStart(28, "option", 14);
1841
+ i0.ɵɵtext(29, "Record Fields");
992
1842
  i0.ɵɵelementEnd();
993
- i0.ɵɵelementStart(16, "option", 9);
994
- i0.ɵɵtext(17, "Entity Document (Template)");
1843
+ i0.ɵɵelementStart(30, "option", 15);
1844
+ i0.ɵɵtext(31, "Entity Document (Template)");
995
1845
  i0.ɵɵelementEnd();
996
- i0.ɵɵelementStart(18, "option", 10);
997
- i0.ɵɵtext(19, "Query (Graph Traversal)");
1846
+ i0.ɵɵelementStart(32, "option", 16);
1847
+ i0.ɵɵtext(33, "Query (Graph Traversal)");
998
1848
  i0.ɵɵelementEnd()()();
999
- i0.ɵɵconditionalCreate(20, FeaturePipelineBuilderComponent_Conditional_20_Template, 8, 1, "div", 6);
1000
- i0.ɵɵconditionalCreate(21, FeaturePipelineBuilderComponent_Conditional_21_Template, 4, 1, "div", 6);
1001
- i0.ɵɵelementStart(22, "div", 6)(23, "label");
1002
- i0.ɵɵtext(24, "Field Filter (optional)");
1849
+ i0.ɵɵconditionalCreate(34, FeaturePipelineBuilderComponent_Conditional_34_Template, 8, 1, "div", 3);
1850
+ i0.ɵɵconditionalCreate(35, FeaturePipelineBuilderComponent_Conditional_35_Template, 4, 1, "div", 3);
1851
+ i0.ɵɵelementStart(36, "div", 3)(37, "label");
1852
+ i0.ɵɵtext(38, "Field Filter (optional)");
1003
1853
  i0.ɵɵelementEnd();
1004
- i0.ɵɵelementStart(25, "input", 11);
1005
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Template_input_input_25_listener($event) { return ctx.onFieldsCsvChange($event); });
1854
+ i0.ɵɵelementStart(39, "input", 17);
1855
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Template_input_input_39_listener($event) { return ctx.onFieldsCsvChange($event); });
1006
1856
  i0.ɵɵelementEnd()()()();
1007
- i0.ɵɵelementStart(26, "section", 1)(27, "div", 2)(28, "span", 3);
1008
- i0.ɵɵtext(29, "2");
1857
+ i0.ɵɵelementStart(40, "section", 8)(41, "div", 9)(42, "span", 10);
1858
+ i0.ɵɵtext(43, "2");
1009
1859
  i0.ɵɵelementEnd();
1010
- i0.ɵɵelementStart(30, "h3");
1011
- i0.ɵɵtext(31, "AI Prompt");
1860
+ i0.ɵɵelementStart(44, "h3");
1861
+ i0.ɵɵtext(45, "AI Prompt");
1012
1862
  i0.ɵɵelementEnd()();
1013
- i0.ɵɵelementStart(32, "div", 12)(33, "div", 6)(34, "label");
1014
- i0.ɵɵtext(35, "Prompt");
1863
+ i0.ɵɵelementStart(46, "div", 2)(47, "div", 3)(48, "label");
1864
+ i0.ɵɵtext(49, "Prompt");
1015
1865
  i0.ɵɵelementEnd();
1016
- i0.ɵɵelementStart(36, "select", 7);
1017
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_36_listener($event) { return ctx.onPromptChange($event); });
1018
- i0.ɵɵelementStart(37, "option", 13);
1019
- i0.ɵɵtext(38, "\u2014 Select AI Prompt \u2014");
1866
+ i0.ɵɵelementStart(50, "select", 4);
1867
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_50_listener($event) { return ctx.onPromptChange($event); });
1868
+ i0.ɵɵelementStart(51, "option", 18);
1869
+ i0.ɵɵtext(52, "\u2014 Select AI Prompt \u2014");
1020
1870
  i0.ɵɵelementEnd();
1021
- i0.ɵɵrepeaterCreate(39, FeaturePipelineBuilderComponent_For_40_Template, 2, 2, "option", 14, _forTrack0);
1871
+ i0.ɵɵrepeaterCreate(53, FeaturePipelineBuilderComponent_For_54_Template, 2, 3, "option", 5, _forTrack1);
1022
1872
  i0.ɵɵelementEnd()();
1023
- i0.ɵɵconditionalCreate(41, FeaturePipelineBuilderComponent_Conditional_41_Template, 5, 1, "div", 6);
1873
+ i0.ɵɵconditionalCreate(55, FeaturePipelineBuilderComponent_Conditional_55_Template, 5, 1, "div", 3);
1024
1874
  i0.ɵɵelementEnd();
1025
- i0.ɵɵconditionalCreate(42, FeaturePipelineBuilderComponent_Conditional_42_Template, 7, 1, "div", 15);
1875
+ i0.ɵɵconditionalCreate(56, FeaturePipelineBuilderComponent_Conditional_56_Template, 7, 1, "div", 19);
1026
1876
  i0.ɵɵelementEnd();
1027
- i0.ɵɵelementStart(43, "section", 1)(44, "div", 16)(45, "div", 17)(46, "span", 3);
1028
- i0.ɵɵtext(47, "3");
1877
+ i0.ɵɵelementStart(57, "section", 8)(58, "div", 20)(59, "div", 21)(60, "span", 10);
1878
+ i0.ɵɵtext(61, "3");
1029
1879
  i0.ɵɵelementEnd();
1030
- i0.ɵɵelementStart(48, "h3");
1031
- i0.ɵɵtext(49, "Outputs & Constraints");
1880
+ i0.ɵɵelementStart(62, "h3");
1881
+ i0.ɵɵtext(63, "Outputs & Constraints");
1032
1882
  i0.ɵɵelementEnd()();
1033
- i0.ɵɵelementStart(50, "button", 18);
1034
- i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Template_button_click_50_listener() { return ctx.addOutput(); });
1035
- i0.ɵɵelement(51, "i", 19);
1036
- i0.ɵɵtext(52, " Add Output ");
1883
+ i0.ɵɵelementStart(64, "button", 22);
1884
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Template_button_click_64_listener() { return ctx.addOutput(); });
1885
+ i0.ɵɵelement(65, "i", 23);
1886
+ i0.ɵɵtext(66, " Add Output ");
1037
1887
  i0.ɵɵelementEnd()();
1038
- i0.ɵɵelementStart(53, "p", 4);
1039
- i0.ɵɵtext(54, "Define the structured outputs produced by the LLM, their type constraints, and target write-back destinations.");
1888
+ i0.ɵɵelementStart(67, "p", 11);
1889
+ i0.ɵɵtext(68, "Define the structured outputs produced by the pipeline, their type constraints, and target write-back destinations.");
1040
1890
  i0.ɵɵelementEnd();
1041
- i0.ɵɵconditionalCreate(55, FeaturePipelineBuilderComponent_Conditional_55_Template, 7, 0, "div", 20)(56, FeaturePipelineBuilderComponent_Conditional_56_Template, 3, 0, "div", 21);
1891
+ i0.ɵɵconditionalCreate(69, FeaturePipelineBuilderComponent_Conditional_69_Template, 7, 0, "div", 24)(70, FeaturePipelineBuilderComponent_Conditional_70_Template, 3, 0, "div", 25);
1042
1892
  i0.ɵɵelementEnd();
1043
- i0.ɵɵelementStart(57, "section", 1)(58, "div", 2)(59, "span", 3);
1044
- i0.ɵɵtext(60, "4");
1893
+ i0.ɵɵconditionalCreate(71, FeaturePipelineBuilderComponent_Conditional_71_Template, 13, 2, "section", 26);
1894
+ i0.ɵɵelementStart(72, "section", 8)(73, "div", 9)(74, "span", 10);
1895
+ i0.ɵɵtext(75, "4");
1045
1896
  i0.ɵɵelementEnd();
1046
- i0.ɵɵelementStart(61, "h3");
1047
- i0.ɵɵtext(62, "Caching & Watermarks");
1897
+ i0.ɵɵelementStart(76, "h3");
1898
+ i0.ɵɵtext(77, "Caching & Watermarks");
1048
1899
  i0.ɵɵelementEnd()();
1049
- i0.ɵɵelementStart(63, "div", 5)(64, "div", 6)(65, "label");
1050
- i0.ɵɵtext(66, "Watermark Strategy");
1900
+ i0.ɵɵelementStart(78, "div", 12)(79, "div", 3)(80, "label");
1901
+ i0.ɵɵtext(81, "Watermark Strategy");
1051
1902
  i0.ɵɵelementEnd();
1052
- i0.ɵɵelementStart(67, "select", 7);
1053
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_67_listener($event) { return ctx.updateWatermarkStrategy($event); });
1054
- i0.ɵɵelementStart(68, "option", 22);
1055
- i0.ɵɵtext(69, "Checksum (Content Hash + Prompt Hash)");
1903
+ i0.ɵɵelementStart(82, "select", 13);
1904
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_82_listener($event) { return ctx.updateWatermarkStrategy($event); });
1905
+ i0.ɵɵelementStart(83, "option", 27);
1906
+ i0.ɵɵtext(84, "Checksum (Content Hash + Prompt Hash)");
1056
1907
  i0.ɵɵelementEnd();
1057
- i0.ɵɵelementStart(70, "option", 23);
1058
- i0.ɵɵtext(71, "UpdatedAt (Compare modified timestamp)");
1908
+ i0.ɵɵelementStart(85, "option", 28);
1909
+ i0.ɵɵtext(86, "UpdatedAt (Compare modified timestamp)");
1059
1910
  i0.ɵɵelementEnd();
1060
- i0.ɵɵelementStart(72, "option", 24);
1061
- i0.ɵɵtext(73, "None (Always process all records)");
1911
+ i0.ɵɵelementStart(87, "option", 29);
1912
+ i0.ɵɵtext(88, "None (Always process all records)");
1062
1913
  i0.ɵɵelementEnd()()();
1063
- i0.ɵɵelementStart(74, "div", 6)(75, "label");
1064
- i0.ɵɵtext(76, "Skip Unchanged Records");
1914
+ i0.ɵɵelementStart(89, "div", 3)(90, "label");
1915
+ i0.ɵɵtext(91, "Skip Unchanged Records");
1065
1916
  i0.ɵɵelementEnd();
1066
- i0.ɵɵelementStart(77, "select", 7);
1067
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_77_listener($event) { return ctx.updateSkipUnchanged($event); });
1068
- i0.ɵɵelementStart(78, "option", 25);
1069
- i0.ɵɵtext(79, "Yes \u2014 Skip unchanged rows");
1917
+ i0.ɵɵelementStart(92, "select", 13);
1918
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_92_listener($event) { return ctx.updateSkipUnchanged($event); });
1919
+ i0.ɵɵelementStart(93, "option", 30);
1920
+ i0.ɵɵtext(94, "Yes \u2014 Skip unchanged rows");
1070
1921
  i0.ɵɵelementEnd();
1071
- i0.ɵɵelementStart(80, "option", 26);
1072
- i0.ɵɵtext(81, "No \u2014 Recompute every time");
1922
+ i0.ɵɵelementStart(95, "option", 31);
1923
+ i0.ɵɵtext(96, "No \u2014 Recompute every time");
1073
1924
  i0.ɵɵelementEnd()()();
1074
- i0.ɵɵelementStart(82, "div", 6)(83, "label");
1075
- i0.ɵɵtext(84, "Enable Result Cache");
1925
+ i0.ɵɵelementStart(97, "div", 3)(98, "label");
1926
+ i0.ɵɵtext(99, "Enable Result Cache");
1076
1927
  i0.ɵɵelementEnd();
1077
- i0.ɵɵelementStart(85, "select", 7);
1078
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_85_listener($event) { return ctx.updateCacheable($event); });
1079
- i0.ɵɵelementStart(86, "option", 25);
1080
- i0.ɵɵtext(87, "Yes \u2014 Cache outputs by distinct key");
1928
+ i0.ɵɵelementStart(100, "select", 13);
1929
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_100_listener($event) { return ctx.updateCacheable($event); });
1930
+ i0.ɵɵelementStart(101, "option", 30);
1931
+ i0.ɵɵtext(102, "Yes \u2014 Cache outputs by distinct key");
1081
1932
  i0.ɵɵelementEnd();
1082
- i0.ɵɵelementStart(88, "option", 26);
1083
- i0.ɵɵtext(89, "No \u2014 Compute per row");
1933
+ i0.ɵɵelementStart(103, "option", 31);
1934
+ i0.ɵɵtext(104, "No \u2014 Compute per row");
1084
1935
  i0.ɵɵelementEnd()()()();
1085
- i0.ɵɵconditionalCreate(90, FeaturePipelineBuilderComponent_Conditional_90_Template, 17, 3, "div", 27);
1086
- i0.ɵɵelementEnd();
1087
- i0.ɵɵconditionalCreate(91, FeaturePipelineBuilderComponent_Conditional_91_Template, 7, 0, "div", 28);
1936
+ i0.ɵɵconditionalCreate(105, FeaturePipelineBuilderComponent_Conditional_105_Template, 17, 3, "div", 32);
1088
1937
  i0.ɵɵelementEnd();
1938
+ i0.ɵɵconditionalCreate(106, FeaturePipelineBuilderComponent_Conditional_106_Template, 7, 0, "div", 33);
1939
+ i0.ɵɵelementStart(107, "mj-confirm-dialog", 34);
1940
+ i0.ɵɵtwoWayListener("VisibleChange", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_VisibleChange_107_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.ShowTypeSwitchConfirm, $event) || (ctx.ShowTypeSwitchConfirm = $event); return $event; });
1941
+ i0.ɵɵlistener("Confirmed", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_Confirmed_107_listener() { return ctx.OnTypeSwitchConfirmed(); })("Cancelled", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_Cancelled_107_listener() { return ctx.OnTypeSwitchCancelled(); });
1942
+ i0.ɵɵelementStart(108, "ul", 35);
1943
+ i0.ɵɵrepeaterCreate(109, FeaturePipelineBuilderComponent_For_110_Template, 2, 1, "li", null, i0.ɵɵrepeaterTrackByIndex);
1944
+ i0.ɵɵelementEnd()()();
1089
1945
  } if (rf & 2) {
1946
+ i0.ɵɵadvance(7);
1947
+ i0.ɵɵrepeater(ctx.AvailablePipelineTypes);
1948
+ i0.ɵɵadvance(6);
1949
+ i0.ɵɵtextInterpolate(ctx.SelectedPipelineTypeDescription || "\u2014");
1950
+ i0.ɵɵadvance();
1951
+ i0.ɵɵconditional(ctx.ShowCaptureReasoning ? 14 : -1);
1090
1952
  i0.ɵɵadvance(13);
1091
1953
  i0.ɵɵproperty("value", ctx.contextMode);
1092
1954
  i0.ɵɵadvance(7);
1093
- i0.ɵɵconditional(ctx.contextMode === "document" ? 20 : -1);
1955
+ i0.ɵɵconditional(ctx.contextMode === "document" ? 34 : -1);
1094
1956
  i0.ɵɵadvance();
1095
- i0.ɵɵconditional(ctx.contextMode === "query" ? 21 : -1);
1957
+ i0.ɵɵconditional(ctx.contextMode === "query" ? 35 : -1);
1096
1958
  i0.ɵɵadvance(4);
1097
1959
  i0.ɵɵproperty("value", ctx.fieldsCsv);
1098
- i0.ɵɵadvance(11);
1099
- i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.PromptID) || "");
1100
- i0.ɵɵadvance(3);
1960
+ i0.ɵɵadvance(12);
1961
+ i0.ɵɵproperty("selected", !ctx.SavedPromptListed);
1962
+ i0.ɵɵadvance(2);
1101
1963
  i0.ɵɵrepeater(ctx.availablePrompts);
1102
1964
  i0.ɵɵadvance(2);
1103
- i0.ɵɵconditional(ctx.selectedPrompt ? 41 : -1);
1965
+ i0.ɵɵconditional(ctx.selectedPrompt ? 55 : -1);
1104
1966
  i0.ɵɵadvance();
1105
- i0.ɵɵconditional(ctx.renderedConstraintPreview ? 42 : -1);
1967
+ i0.ɵɵconditional(ctx.renderedConstraintPreview ? 56 : -1);
1106
1968
  i0.ɵɵadvance(13);
1107
- i0.ɵɵconditional(!ctx.spec.Outputs || ctx.spec.Outputs.length === 0 ? 55 : 56);
1108
- i0.ɵɵadvance(12);
1969
+ i0.ɵɵconditional(!ctx.spec.Outputs || ctx.spec.Outputs.length === 0 ? 69 : 70);
1970
+ i0.ɵɵadvance(2);
1971
+ i0.ɵɵconditional(ctx.IsDecisionPipeline ? 71 : -1);
1972
+ i0.ɵɵadvance(11);
1109
1973
  i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.WatermarkStrategy) || "Checksum");
1110
1974
  i0.ɵɵadvance(10);
1111
1975
  i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.SkipUnchanged) ? "true" : "false");
1112
1976
  i0.ɵɵadvance(8);
1113
1977
  i0.ɵɵproperty("value", ctx.spec.Caching.Cacheable ? "true" : "false");
1114
1978
  i0.ɵɵadvance(5);
1115
- i0.ɵɵconditional(ctx.spec.Caching.Cacheable ? 90 : -1);
1979
+ i0.ɵɵconditional(ctx.spec.Caching.Cacheable ? 105 : -1);
1980
+ i0.ɵɵadvance();
1981
+ i0.ɵɵconditional(ctx.validationErrors.length > 0 ? 106 : -1);
1116
1982
  i0.ɵɵadvance();
1117
- i0.ɵɵconditional(ctx.validationErrors.length > 0 ? 91 : -1);
1118
- } }, dependencies: [CommonModule, FormsModule, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, MJButtonDirective], styles: [".fpb[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .rpe-sec-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h[_ngcontent-%COMP%] { justify-content: space-between; }\n .fpb-title-group[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 6px; }\n .field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt[_ngcontent-%COMP%] { margin-top: 14px; }\n .mono[_ngcontent-%COMP%] { font-family: monospace; font-size: 12.5px; }\n .muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card[_ngcontent-%COMP%] { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error[_ngcontent-%COMP%] { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card[_ngcontent-%COMP%] ul[_ngcontent-%COMP%] { margin: 0; padding-left: 20px; }"], changeDetection: 0 });
1983
+ i0.ɵɵtwoWayProperty("Visible", ctx.ShowTypeSwitchConfirm);
1984
+ i0.ɵɵproperty("Message", "Switching to " + (ctx.PendingPipelineType || "selected type") + " will affect existing outputs:");
1985
+ i0.ɵɵadvance(2);
1986
+ i0.ɵɵrepeater(ctx.TypeSwitchIssues);
1987
+ } }, dependencies: [CommonModule, FormsModule, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, MJButtonDirective, MJConfirmDialogComponent], styles: [".fpb[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .fpb-type-sec[_ngcontent-%COMP%] { border-left: 3px solid var(--mj-brand-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h[_ngcontent-%COMP%] { justify-content: space-between; }\n .fpb-title-group[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 6px; }\n .field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt[_ngcontent-%COMP%] { margin-top: 14px; }\n .mono[_ngcontent-%COMP%] { font-family: monospace; font-size: 12.5px; }\n .muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card[_ngcontent-%COMP%] { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error[_ngcontent-%COMP%] { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card[_ngcontent-%COMP%] ul[_ngcontent-%COMP%] { margin: 0; padding-left: 20px; }\n .fpb-confirm-issues[_ngcontent-%COMP%] { margin: 10px 0 0 0; padding-left: 20px; color: var(--mj-status-error-text, var(--mj-text-primary)); font-size: 13px; }\n .fpb-confirm-issues[_ngcontent-%COMP%] li[_ngcontent-%COMP%] { margin-bottom: 4px; }\n .fpb-levels-header[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }\n .fpb-levels-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; }\n .fpb-level-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; }\n .fpb-level-num[_ngcontent-%COMP%] { width: 22px; height: 22px; display: grid; place-items: center; font-size: 11px; font-weight: 700; border-radius: var(--mj-radius-sm, 4px); background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); flex-shrink: 0; }\n .fpb-enum-descriptions[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }\n .fpb-enum-desc-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; }\n .fpb-enum-val-badge[_ngcontent-%COMP%] { min-width: 90px; padding: 4px 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-sm, 4px); font-size: 12px; font-weight: 600; text-align: center; flex-shrink: 0; }\n .fpb-escalation-toggle-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; margin-top: 10px; }\n .fpb-checkbox-label[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--mj-text-primary); user-select: none; }\n .fpb-checkbox-label[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--mj-brand-primary); }"], changeDetection: 0 });
1119
1988
  }
1120
1989
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FeaturePipelineBuilderComponent, [{
1121
1990
  type: Component,
1122
- args: [{ selector: 'mj-feature-pipeline-builder', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, MJButtonDirective], template: `
1991
+ args: [{ selector: 'mj-feature-pipeline-builder', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, MJButtonDirective, MJConfirmDialogComponent], template: `
1123
1992
  <div class="fpb">
1993
+ <!-- PIPELINE TYPE SELECTOR -->
1994
+ <section class="rpe-sec fpb-type-sec">
1995
+ <div class="rpe-grid2">
1996
+ <div class="field">
1997
+ <label>Pipeline Type</label>
1998
+ <select class="mj-input" (change)="OnPipelineTypeSelect($event)">
1999
+ @for (t of AvailablePipelineTypes; track t.Name) {
2000
+ <option [value]="t.Name" [selected]="IsCurrentPipelineType(t.Name)">{{ t.DisplayName || t.Name }}</option>
2001
+ }
2002
+ </select>
2003
+ </div>
2004
+ <div class="field">
2005
+ <label>Type Description</label>
2006
+ <div class="rpe-static-text">{{ SelectedPipelineTypeDescription || '—' }}</div>
2007
+ </div>
2008
+ </div>
2009
+ @if (ShowCaptureReasoning) {
2010
+ <div class="rpe-grid2 rpe-mt">
2011
+ <div class="field">
2012
+ <label>Capture Reasoning</label>
2013
+ <select class="mj-input fpb-reasoning-select" [value]="spec.CaptureReasoning ? 'true' : 'false'" (change)="UpdateCaptureReasoning($event)">
2014
+ <option value="true">Yes — Keep the model's rationale with each Feature Value</option>
2015
+ <option value="false">No</option>
2016
+ </select>
2017
+ </div>
2018
+ </div>
2019
+ }
2020
+ </section>
2021
+
1124
2022
  <!-- STAGE 1: CONTEXT SOURCE -->
1125
2023
  <section class="rpe-sec">
1126
2024
  <div class="rpe-sec-h">
@@ -1142,10 +2040,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1142
2040
  @if (contextMode === 'document') {
1143
2041
  <div class="field">
1144
2042
  <label>Entity Document</label>
1145
- <select class="mj-input" [value]="spec.Context.EntityDocumentID || ''" (change)="onEntityDocChange($event)">
1146
- <option value="" disabled>— Select Entity Document —</option>
2043
+ <select class="mj-input" (change)="onEntityDocChange($event)">
2044
+ <option value="" disabled [selected]="!SavedEntityDocListed">— Select Entity Document —</option>
1147
2045
  @for (doc of availableDocs; track doc.ID) {
1148
- <option [value]="doc.ID">{{ doc.Name }}</option>
2046
+ <option [value]="doc.ID" [selected]="IsSavedEntityDoc(doc)">{{ doc.Name }}</option>
1149
2047
  }
1150
2048
  </select>
1151
2049
  </div>
@@ -1174,10 +2072,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1174
2072
  <div class="rpe-grid2">
1175
2073
  <div class="field">
1176
2074
  <label>Prompt</label>
1177
- <select class="mj-input" [value]="Record?.PromptID || ''" (change)="onPromptChange($event)">
1178
- <option value="" disabled>— Select AI Prompt —</option>
2075
+ <select class="mj-input" (change)="onPromptChange($event)">
2076
+ <option value="" disabled [selected]="!SavedPromptListed">— Select AI Prompt —</option>
1179
2077
  @for (p of availablePrompts; track p.ID) {
1180
- <option [value]="p.ID">{{ p.Name }}</option>
2078
+ <option [value]="p.ID" [selected]="IsSavedPrompt(p)">{{ p.Name }}</option>
1181
2079
  }
1182
2080
  </select>
1183
2081
  </div>
@@ -1208,7 +2106,7 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1208
2106
  <i class="fa-solid fa-plus"></i> Add Output
1209
2107
  </button>
1210
2108
  </div>
1211
- <p class="rpe-desc">Define the structured outputs produced by the LLM, their type constraints, and target write-back destinations.</p>
2109
+ <p class="rpe-desc">Define the structured outputs produced by the pipeline, their type constraints, and target write-back destinations.</p>
1212
2110
 
1213
2111
  @if (!spec.Outputs || spec.Outputs.length === 0) {
1214
2112
  <div class="fpb-empty-outputs">
@@ -1217,11 +2115,11 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1217
2115
  </div>
1218
2116
  } @else {
1219
2117
  <div class="fpb-outputs-list">
1220
- @for (output of spec.Outputs; track $index) {
2118
+ @for (output of spec.Outputs; track $index; let outputIndex = $index) {
1221
2119
  <div class="fpb-output-card">
1222
2120
  <div class="fpb-output-head">
1223
- <h4>Output #{{ $index + 1 }}: {{ output.Name || '(unnamed)' }}</h4>
1224
- <button mjButton size="sm" variant="flat" (click)="removeOutput($index)">
2121
+ <h4>Output #{{ outputIndex + 1 }}: {{ output.Name || '(unnamed)' }}</h4>
2122
+ <button mjButton size="sm" variant="flat" (click)="removeOutput(outputIndex)">
1225
2123
  <i class="fa-solid fa-trash"></i> Remove
1226
2124
  </button>
1227
2125
  </div>
@@ -1229,18 +2127,21 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1229
2127
  <div class="rpe-grid3">
1230
2128
  <div class="field">
1231
2129
  <label>Output Name</label>
1232
- <input class="mj-input" [value]="output.Name" (input)="updateOutputProp($index, 'Name', $event)" placeholder="e.g. SentimentScore">
2130
+ <input class="mj-input" [value]="output.Name" (input)="updateOutputProp(outputIndex, 'Name', $event)" placeholder="e.g. SentimentScore">
1233
2131
  </div>
1234
2132
  <div class="field">
1235
2133
  <label>JSON Path / Ref</label>
1236
- <input class="mj-input mono" [value]="output.Ref" (input)="updateOutputProp($index, 'Ref', $event)" placeholder="e.g. $.sentiment or $">
2134
+ <input class="mj-input mono" [value]="output.Ref" (input)="updateOutputProp(outputIndex, 'Ref', $event)" placeholder="e.g. $.sentiment or $">
1237
2135
  </div>
1238
2136
  <div class="field">
1239
2137
  <label>Target Mode</label>
1240
- <select class="mj-input" [value]="output.Target.Mode" (change)="updateTargetMode($index, $event)">
1241
- <option value="field">Entity Column (field)</option>
1242
- <option value="child">Child Rows (child)</option>
1243
- <option value="tags">Taxonomy Tags (tags)</option>
2138
+ <select class="mj-input" (change)="updateTargetMode(outputIndex, $event)">
2139
+ @if (!IsTargetModeOffered(output)) {
2140
+ <option value="" disabled [selected]="true">— Select Target Mode —</option>
2141
+ }
2142
+ @for (m of AvailableTargetModes; track m.Value) {
2143
+ <option [value]="m.Value" [selected]="m.Value === output.Target.Mode">{{ m.Label }}</option>
2144
+ }
1244
2145
  </select>
1245
2146
  </div>
1246
2147
  </div>
@@ -1250,10 +2151,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1250
2151
  @if (output.Target.Mode === 'field') {
1251
2152
  <div class="field">
1252
2153
  <label>Target Field</label>
1253
- <select class="mj-input" [value]="output.Target.EntityFieldName" (change)="updateFieldTarget($index, $event)">
1254
- <option value="" disabled>— Select Column —</option>
2154
+ <select class="mj-input" (change)="updateFieldTarget(outputIndex, $event)">
2155
+ <option value="" disabled [selected]="!IsEntityFieldListed(output.Target.EntityFieldName)">— Select Column —</option>
1255
2156
  @for (f of entityFields; track f.Name) {
1256
- <option [value]="f.Name">{{ f.DisplayName || f.Name }} ({{ f.TSType }})</option>
2157
+ <option [value]="f.Name" [selected]="f.Name === output.Target.EntityFieldName">{{ f.DisplayName || f.Name }} ({{ f.TSType }})</option>
1257
2158
  }
1258
2159
  </select>
1259
2160
  </div>
@@ -1262,10 +2163,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1262
2163
  @if (output.Target.Mode === 'child') {
1263
2164
  <div class="field">
1264
2165
  <label>Child Entity</label>
1265
- <select class="mj-input" [value]="output.Target.EntityName" (change)="updateChildTargetEntity($index, $event)">
1266
- <option value="" disabled>— Select Entity —</option>
2166
+ <select class="mj-input" (change)="updateChildTargetEntity(outputIndex, $event)">
2167
+ <option value="" disabled [selected]="!IsEntityListed(output.Target.EntityName)">— Select Entity —</option>
1267
2168
  @for (e of availableEntities; track e.ID) {
1268
- <option [value]="e.Name">{{ e.DisplayName || e.Name }}</option>
2169
+ <option [value]="e.Name" [selected]="e.Name === output.Target.EntityName">{{ e.DisplayName || e.Name }}</option>
1269
2170
  }
1270
2171
  </select>
1271
2172
  </div>
@@ -1274,19 +2175,20 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1274
2175
  <!-- Constraint details -->
1275
2176
  <div class="field">
1276
2177
  <label>Constraint Type</label>
1277
- <select class="mj-input" [value]="output.Constraint?.Type || 'none'" (change)="updateConstraintType($index, $event)">
1278
- <option value="none">None / Unconstrained</option>
1279
- <option value="enum">Enum (Allowed Values)</option>
1280
- <option value="numeric">Numeric (Min/Max)</option>
1281
- <option value="boolean">Boolean</option>
1282
- <option value="freetext">Free Text</option>
2178
+ <select class="mj-input" (change)="updateConstraintType(outputIndex, $event)">
2179
+ @if (!IsConstraintTypeOffered(output)) {
2180
+ <option value="none" disabled [selected]="true">— Select Constraint —</option>
2181
+ }
2182
+ @for (t of AvailableConstraintTypes; track t.Value) {
2183
+ <option [value]="t.Value" [selected]="t.Value === SavedConstraintType(output)">{{ t.Label }}</option>
2184
+ }
1283
2185
  </select>
1284
2186
  </div>
1285
2187
 
1286
2188
  @if (output.Constraint) {
1287
2189
  <div class="field">
1288
2190
  <label>Violation Policy</label>
1289
- <select class="mj-input" [value]="output.Constraint.OnViolation || 'fail'" (change)="updateViolationPolicy($index, $event)">
2191
+ <select class="mj-input" [value]="output.Constraint.OnViolation || 'fail'" (change)="updateViolationPolicy(outputIndex, $event)">
1290
2192
  <option value="fail">Fail Row</option>
1291
2193
  <option value="null">Set Output to Null</option>
1292
2194
  <option value="coerce-to-other">Coerce / Fallback</option>
@@ -1299,19 +2201,109 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1299
2201
  @if (output.Constraint?.Type === 'enum') {
1300
2202
  <div class="field rpe-mt">
1301
2203
  <label>Allowed Values (comma separated)</label>
1302
- <input class="mj-input" [value]="getEnumValuesCsv(output.Constraint)" (input)="updateEnumValues($index, $event)" placeholder="e.g. Positive, Neutral, Negative">
2204
+ <input class="mj-input" [value]="getEnumValuesCsv(output.Constraint)" (input)="updateEnumValues(outputIndex, $event)" placeholder="e.g. Positive, Neutral, Negative">
1303
2205
  </div>
2206
+ @if (IsDecisionPipeline && GetEnumValues(output).length > 0) {
2207
+ <div class="field rpe-mt">
2208
+ <label>Value Descriptions <span class="muted">— Decision models require a description for every choice option</span></label>
2209
+ <div class="fpb-enum-descriptions">
2210
+ @for (val of GetEnumValues(output); track val) {
2211
+ <div class="fpb-enum-desc-row">
2212
+ <span class="fpb-enum-val-badge">{{ val }}</span>
2213
+ <input
2214
+ class="mj-input"
2215
+ [value]="GetEnumValueDescription(output, val)"
2216
+ (input)="UpdateEnumValueDescription(outputIndex, val, $event)"
2217
+ [placeholder]="'Description for ' + val">
2218
+ </div>
2219
+ }
2220
+ </div>
2221
+ </div>
2222
+ }
1304
2223
  }
1305
2224
  @if (output.Constraint?.Type === 'numeric') {
1306
- <div class="rpe-grid2 rpe-mt">
1307
- <div class="field">
1308
- <label>Min Value</label>
1309
- <input class="mj-input" type="number" [value]="getNumericMin(output.Constraint)" (input)="updateNumericMin($index, $event)">
2225
+ @if (IsDecisionPipeline) {
2226
+ <div class="field rpe-mt">
2227
+ <div class="fpb-levels-header">
2228
+ <label>Numeric Levels <span class="muted">(Ordered: lowest to highest, 2 to 10 levels)</span></label>
2229
+ <button
2230
+ mjButton
2231
+ size="sm"
2232
+ variant="secondary"
2233
+ type="button"
2234
+ [disabled]="GetNumericLevels(output).length >= 10"
2235
+ (click)="AddNumericLevel(outputIndex)">
2236
+ <i class="fa-solid fa-plus"></i> Add Level
2237
+ </button>
2238
+ </div>
2239
+ <div class="fpb-levels-list">
2240
+ @for (lvl of GetNumericLevels(output); track $index; let lvlIdx = $index; let first = $first; let last = $last) {
2241
+ <div class="fpb-level-row">
2242
+ <span class="fpb-level-num">{{ lvlIdx + 1 }}</span>
2243
+ <input
2244
+ class="mj-input"
2245
+ [value]="lvl"
2246
+ (input)="UpdateNumericLevel(outputIndex, lvlIdx, $event)"
2247
+ placeholder="Level label (e.g. Low, Medium, High)">
2248
+ <button
2249
+ mjButton
2250
+ size="sm"
2251
+ variant="flat"
2252
+ type="button"
2253
+ [disabled]="first"
2254
+ (click)="MoveNumericLevel(outputIndex, lvlIdx, 'up')"
2255
+ title="Move Up">
2256
+ <i class="fa-solid fa-arrow-up"></i>
2257
+ </button>
2258
+ <button
2259
+ mjButton
2260
+ size="sm"
2261
+ variant="flat"
2262
+ type="button"
2263
+ [disabled]="last"
2264
+ (click)="MoveNumericLevel(outputIndex, lvlIdx, 'down')"
2265
+ title="Move Down">
2266
+ <i class="fa-solid fa-arrow-down"></i>
2267
+ </button>
2268
+ <button
2269
+ mjButton
2270
+ size="sm"
2271
+ variant="flat"
2272
+ type="button"
2273
+ [disabled]="GetNumericLevels(output).length <= 2"
2274
+ (click)="RemoveNumericLevel(outputIndex, lvlIdx)"
2275
+ title="Remove Level">
2276
+ <i class="fa-solid fa-trash"></i>
2277
+ </button>
2278
+ </div>
2279
+ }
2280
+ </div>
1310
2281
  </div>
1311
- <div class="field">
1312
- <label>Max Value</label>
1313
- <input class="mj-input" type="number" [value]="getNumericMax(output.Constraint)" (input)="updateNumericMax($index, $event)">
2282
+ } @else {
2283
+ <div class="rpe-grid2 rpe-mt">
2284
+ <div class="field">
2285
+ <label>Min Value</label>
2286
+ <input class="mj-input" type="number" [value]="getNumericMin(output.Constraint)" (input)="updateNumericMin(outputIndex, $event)">
2287
+ </div>
2288
+ <div class="field">
2289
+ <label>Max Value</label>
2290
+ <input class="mj-input" type="number" [value]="getNumericMax(output.Constraint)" (input)="updateNumericMax(outputIndex, $event)">
2291
+ </div>
1314
2292
  </div>
2293
+ }
2294
+ }
2295
+ @if (output.Constraint?.Type === 'boolean' && IsDecisionPipeline) {
2296
+ <div class="field rpe-mt">
2297
+ <label>Decision Threshold (0.0 to 1.0) <span class="muted">— calibrated probability threshold for true</span></label>
2298
+ <input
2299
+ class="mj-input"
2300
+ type="number"
2301
+ min="0"
2302
+ max="1"
2303
+ step="0.05"
2304
+ placeholder="0.5"
2305
+ [value]="GetBooleanThreshold(output) ?? ''"
2306
+ (input)="UpdateBooleanThreshold(outputIndex, $event)">
1315
2307
  </div>
1316
2308
  }
1317
2309
  </div>
@@ -1320,6 +2312,56 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1320
2312
  }
1321
2313
  </section>
1322
2314
 
2315
+ <!-- ESCALATION (DECISION PIPELINES ONLY) -->
2316
+ @if (IsDecisionPipeline) {
2317
+ <section class="rpe-sec fpb-escalation-sec">
2318
+ <div class="rpe-sec-h">
2319
+ <i class="fa-solid fa-arrow-up-right-from-square"></i>
2320
+ <h3>Borderline Escalation</h3>
2321
+ </div>
2322
+ <p class="rpe-desc">Records any output of which the decision model answers below this confidence are re-run through the chosen LLM pipeline. Only those records are re-run.</p>
2323
+
2324
+ <div class="fpb-escalation-toggle-row">
2325
+ <label class="fpb-checkbox-label">
2326
+ <input
2327
+ type="checkbox"
2328
+ [checked]="IsEscalationEnabled"
2329
+ (change)="OnEscalationToggle($event)">
2330
+ <span>Escalate borderline records to an LLM pipeline</span>
2331
+ </label>
2332
+ </div>
2333
+
2334
+ @if (IsEscalationEnabled) {
2335
+ <div class="rpe-grid2 rpe-mt">
2336
+ <div class="field">
2337
+ <label>Target LLM Pipeline</label>
2338
+ <select class="mj-input" (change)="OnEscalationTargetChange($event)">
2339
+ <option value="" disabled [selected]="!SavedEscalationTargetListed">{{ EscalationTargetsPlaceholder }}</option>
2340
+ @for (target of AvailableEscalationTargets; track target.ID) {
2341
+ <option [value]="target.ID" [disabled]="!!GetTargetProblem(target)" [selected]="IsSavedEscalationTarget(target)">
2342
+ {{ target.Name }}{{ GetTargetProblem(target) ? ' (' + GetTargetProblem(target) + ')' : '' }}
2343
+ </option>
2344
+ }
2345
+ </select>
2346
+ </div>
2347
+
2348
+ <div class="field">
2349
+ <label>Confidence Floor (0.0 to 1.0)</label>
2350
+ <input
2351
+ class="mj-input"
2352
+ type="number"
2353
+ min="0"
2354
+ max="1"
2355
+ step="0.05"
2356
+ placeholder="0.7"
2357
+ [value]="spec.Escalation?.BelowConfidence ?? ''"
2358
+ (input)="OnEscalationFloorChange($event)">
2359
+ </div>
2360
+ </div>
2361
+ }
2362
+ </section>
2363
+ }
2364
+
1323
2365
  <!-- STAGE 4: MATERIALIZATION & WATERMARK -->
1324
2366
  <section class="rpe-sec">
1325
2367
  <div class="rpe-sec-h">
@@ -1385,8 +2427,25 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1385
2427
  </ul>
1386
2428
  </div>
1387
2429
  }
2430
+
2431
+ <!-- TYPE SWITCH CONFIRMATION DIALOG -->
2432
+ <mj-confirm-dialog
2433
+ [(Visible)]="ShowTypeSwitchConfirm"
2434
+ Type="warning"
2435
+ Title="Switch Pipeline Type"
2436
+ [Message]="'Switching to ' + (PendingPipelineType || 'selected type') + ' will affect existing outputs:'"
2437
+ ConfirmText="Switch Anyway"
2438
+ CancelText="Cancel"
2439
+ (Confirmed)="OnTypeSwitchConfirmed()"
2440
+ (Cancelled)="OnTypeSwitchCancelled()">
2441
+ <ul class="fpb-confirm-issues">
2442
+ @for (issue of TypeSwitchIssues; track $index) {
2443
+ <li>{{ issue }}</li>
2444
+ }
2445
+ </ul>
2446
+ </mj-confirm-dialog>
1388
2447
  </div>
1389
- `, styles: ["\n .fpb { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .rpe-sec-h { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h .num { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h { justify-content: space-between; }\n .fpb-title-group { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field { display: flex; flex-direction: column; gap: 6px; }\n .field label { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt { margin-top: 14px; }\n .mono { font-family: monospace; font-size: 12.5px; }\n .muted { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head h4 { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card h4 { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card ul { margin: 0; padding-left: 20px; }\n "] }]
2448
+ `, styles: ["\n .fpb { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .fpb-type-sec { border-left: 3px solid var(--mj-brand-primary); }\n .rpe-sec-h { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h .num { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h { justify-content: space-between; }\n .fpb-title-group { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field { display: flex; flex-direction: column; gap: 6px; }\n .field label { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt { margin-top: 14px; }\n .mono { font-family: monospace; font-size: 12.5px; }\n .muted { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head h4 { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card h4 { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card ul { margin: 0; padding-left: 20px; }\n .fpb-confirm-issues { margin: 10px 0 0 0; padding-left: 20px; color: var(--mj-status-error-text, var(--mj-text-primary)); font-size: 13px; }\n .fpb-confirm-issues li { margin-bottom: 4px; }\n .fpb-levels-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }\n .fpb-levels-list { display: flex; flex-direction: column; gap: 8px; }\n .fpb-level-row { display: flex; align-items: center; gap: 8px; }\n .fpb-level-num { width: 22px; height: 22px; display: grid; place-items: center; font-size: 11px; font-weight: 700; border-radius: var(--mj-radius-sm, 4px); background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); flex-shrink: 0; }\n .fpb-enum-descriptions { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }\n .fpb-enum-desc-row { display: flex; align-items: center; gap: 10px; }\n .fpb-enum-val-badge { min-width: 90px; padding: 4px 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-sm, 4px); font-size: 12px; font-weight: 600; text-align: center; flex-shrink: 0; }\n .fpb-escalation-toggle-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; }\n .fpb-checkbox-label { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--mj-text-primary); user-select: none; }\n .fpb-checkbox-label input[type=\"checkbox\"] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--mj-brand-primary); }\n "] }]
1390
2449
  }], null, { Record: [{
1391
2450
  type: Input
1392
2451
  }], EntityID: [{
@@ -1396,5 +2455,5 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1396
2455
  }], ValidChange: [{
1397
2456
  type: Output
1398
2457
  }] }); })();
1399
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FeaturePipelineBuilderComponent, { className: "FeaturePipelineBuilderComponent", filePath: "lib/feature-pipeline-builder/feature-pipeline-builder.component.ts", lineNumber: 346 }); })();
2458
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FeaturePipelineBuilderComponent, { className: "FeaturePipelineBuilderComponent", filePath: "lib/feature-pipeline-builder/feature-pipeline-builder.component.ts", lineNumber: 584 }); })();
1400
2459
  //# sourceMappingURL=feature-pipeline-builder.component.js.map