@memberjunction/ng-dashboards 5.46.0 → 5.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +15 -4
  2. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  3. package/dist/DataExplorer/data-explorer-dashboard.component.js +45 -35
  4. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  5. package/dist/DataExplorer/models/explorer-state.interface.d.ts +7 -0
  6. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  7. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  8. package/dist/Lists/components/lists-browse-resource.component.d.ts +4 -0
  9. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  10. package/dist/Lists/components/lists-browse-resource.component.js +39 -30
  11. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  12. package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
  13. package/dist/Lists/components/lists-my-lists-resource.component.js +14 -12
  14. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  15. package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
  16. package/dist/Lists/components/lists-operations-resource.component.js +6 -1
  17. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  18. package/dist/Lists/services/list-set-operations.service.d.ts +11 -0
  19. package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
  20. package/dist/Lists/services/list-set-operations.service.js +27 -2
  21. package/dist/Lists/services/list-set-operations.service.js.map +1 -1
  22. package/dist/PredictiveStudio/at-risk.view-models.d.ts +33 -0
  23. package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +1 -1
  24. package/dist/PredictiveStudio/at-risk.view-models.js +69 -2
  25. package/dist/PredictiveStudio/at-risk.view-models.js.map +1 -1
  26. package/dist/PredictiveStudio/components/ps-catalog.component.js +2 -2
  27. package/dist/PredictiveStudio/components/ps-catalog.component.js.map +1 -1
  28. package/dist/PredictiveStudio/components/ps-compare.component.js +2 -2
  29. package/dist/PredictiveStudio/components/ps-compare.component.js.map +1 -1
  30. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +2 -2
  31. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +1 -1
  32. package/dist/PredictiveStudio/components/ps-experiments.component.js +2 -2
  33. package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
  34. package/dist/PredictiveStudio/components/ps-home.component.js +2 -2
  35. package/dist/PredictiveStudio/components/ps-home.component.js.map +1 -1
  36. package/dist/PredictiveStudio/components/ps-operate-dialog.component.js +2 -2
  37. package/dist/PredictiveStudio/components/ps-operate-dialog.component.js.map +1 -1
  38. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  39. package/dist/PredictiveStudio/components/ps-pipelines.component.js +306 -297
  40. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  41. package/dist/PredictiveStudio/components/ps-production.component.js +2 -2
  42. package/dist/PredictiveStudio/components/ps-production.component.js.map +1 -1
  43. package/dist/PredictiveStudio/components/ps-registry.component.d.ts +1 -1
  44. package/dist/PredictiveStudio/components/ps-registry.component.d.ts.map +1 -1
  45. package/dist/PredictiveStudio/components/ps-registry.component.js +15 -9
  46. package/dist/PredictiveStudio/components/ps-registry.component.js.map +1 -1
  47. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +115 -0
  48. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -0
  49. package/dist/PredictiveStudio/predictive-studio-agent-context.js +119 -0
  50. package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -0
  51. package/dist/PredictiveStudio/predictive-studio-copilot.view-models.d.ts +36 -0
  52. package/dist/PredictiveStudio/predictive-studio-copilot.view-models.d.ts.map +1 -0
  53. package/dist/PredictiveStudio/predictive-studio-copilot.view-models.js +52 -0
  54. package/dist/PredictiveStudio/predictive-studio-copilot.view-models.js.map +1 -0
  55. package/dist/PredictiveStudio/resources/ps-models-resource.component.d.ts +9 -1
  56. package/dist/PredictiveStudio/resources/ps-models-resource.component.d.ts.map +1 -1
  57. package/dist/PredictiveStudio/resources/ps-models-resource.component.js +133 -56
  58. package/dist/PredictiveStudio/resources/ps-models-resource.component.js.map +1 -1
  59. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +50 -1
  60. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
  61. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +591 -165
  62. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
  63. package/dist/PredictiveStudio/resources/ps-resource-base.d.ts +17 -0
  64. package/dist/PredictiveStudio/resources/ps-resource-base.d.ts.map +1 -1
  65. package/dist/PredictiveStudio/resources/ps-resource-base.js +27 -1
  66. package/dist/PredictiveStudio/resources/ps-resource-base.js.map +1 -1
  67. package/dist/PredictiveStudio/resources/ps-studio-resource.component.d.ts +11 -1
  68. package/dist/PredictiveStudio/resources/ps-studio-resource.component.d.ts.map +1 -1
  69. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +199 -99
  70. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
  71. package/package.json +59 -59
@@ -11,7 +11,9 @@ import { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';
11
11
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
12
12
  import { BaseResourceComponent } from '@memberjunction/ng-shared';
13
13
  import { PSResourceBase } from './ps-resource-base';
14
- import { STUDIO_SECTIONS, sectionGroups, sectionsInGroup, sectionLabel, sectionIcon, hasSection, routeHomeNavigate, } from '../predictive-studio.nav';
14
+ import { STUDIO_SECTIONS, sectionGroups, sectionsInGroup, sectionLabel, hasSection, routeHomeNavigate, } from '../predictive-studio.nav';
15
+ import { buildStudioAgentContext, resolvePSRecord, buildPSNotFoundError } from '../predictive-studio-agent-context';
16
+ import { validateStringParam } from '../../shared/agent-tool-validation';
15
17
  import * as i0 from "@angular/core";
16
18
  import * as i1 from "@memberjunction/ng-ui-components";
17
19
  import * as i2 from "@memberjunction/ng-shared-generic";
@@ -23,137 +25,160 @@ import * as i7 from "../components/ps-experiments.component";
23
25
  import * as i8 from "../components/ps-compare.component";
24
26
  const _forTrack0 = ($index, $item) => $item.key;
25
27
  function PSStudioResourceComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
26
- i0.ɵɵelement(0, "mj-loading", 1);
28
+ i0.ɵɵelement(0, "mj-loading", 2);
27
29
  } }
28
- function PSStudioResourceComponent_Conditional_3_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
29
- i0.ɵɵelementStart(0, "div", 9);
30
+ function PSStudioResourceComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
31
+ const _r1 = i0.ɵɵgetCurrentView();
32
+ i0.ɵɵelementStart(0, "div", 3);
33
+ i0.ɵɵelement(1, "i", 5);
34
+ i0.ɵɵelementStart(2, "div", 6)(3, "strong");
35
+ i0.ɵɵtext(4);
36
+ i0.ɵɵelementEnd();
37
+ i0.ɵɵelementStart(5, "span", 7);
38
+ i0.ɵɵtext(6);
39
+ i0.ɵɵelementEnd()();
40
+ i0.ɵɵelementStart(7, "button", 8);
41
+ i0.ɵɵlistener("click", function PSStudioResourceComponent_Conditional_3_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.retryLoad()); });
42
+ i0.ɵɵelement(8, "i", 9);
43
+ i0.ɵɵtext(9, " Try again");
44
+ i0.ɵɵelementEnd()();
45
+ } if (rf & 2) {
46
+ const ctx_r1 = i0.ɵɵnextContext();
47
+ i0.ɵɵadvance(4);
48
+ i0.ɵɵtextInterpolate1("Couldn't load ", ctx_r1.sectionTitle);
49
+ i0.ɵɵadvance(2);
50
+ i0.ɵɵtextInterpolate(ctx_r1.loadError);
51
+ } }
52
+ function PSStudioResourceComponent_Conditional_4_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
53
+ i0.ɵɵelementStart(0, "div", 16);
30
54
  i0.ɵɵtext(1);
31
55
  i0.ɵɵelementEnd();
32
56
  } if (rf & 2) {
33
- const group_r1 = i0.ɵɵnextContext().$implicit;
57
+ const group_r3 = i0.ɵɵnextContext().$implicit;
34
58
  i0.ɵɵadvance();
35
- i0.ɵɵtextInterpolate(group_r1);
59
+ i0.ɵɵtextInterpolate(group_r3);
36
60
  } }
37
- function PSStudioResourceComponent_Conditional_3_For_3_For_2_Template(rf, ctx) { if (rf & 1) {
38
- const _r2 = i0.ɵɵgetCurrentView();
39
- i0.ɵɵelementStart(0, "button", 11);
40
- i0.ɵɵlistener("click", function PSStudioResourceComponent_Conditional_3_For_3_For_2_Template_button_click_0_listener() { const item_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r3.selectSection(item_r3.key)); });
61
+ function PSStudioResourceComponent_Conditional_4_For_3_For_2_Template(rf, ctx) { if (rf & 1) {
62
+ const _r4 = i0.ɵɵgetCurrentView();
63
+ i0.ɵɵelementStart(0, "button", 18);
64
+ i0.ɵɵlistener("click", function PSStudioResourceComponent_Conditional_4_For_3_For_2_Template_button_click_0_listener() { const item_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectSection(item_r5.key)); });
41
65
  i0.ɵɵelement(1, "i");
42
66
  i0.ɵɵelementStart(2, "span");
43
67
  i0.ɵɵtext(3);
44
68
  i0.ɵɵelementEnd()();
45
69
  } if (rf & 2) {
46
- const item_r3 = ctx.$implicit;
47
- const ctx_r3 = i0.ɵɵnextContext(3);
48
- i0.ɵɵclassProp("active", ctx_r3.activeSection === item_r3.key);
49
- i0.ɵɵattribute("data-testid", "ps-nav-" + item_r3.key);
70
+ const item_r5 = ctx.$implicit;
71
+ const ctx_r1 = i0.ɵɵnextContext(3);
72
+ i0.ɵɵclassProp("active", ctx_r1.activeSection === item_r5.key);
73
+ i0.ɵɵattribute("data-testid", "ps-nav-" + item_r5.key);
50
74
  i0.ɵɵadvance();
51
- i0.ɵɵclassMap(item_r3.icon);
75
+ i0.ɵɵclassMap(item_r5.icon);
52
76
  i0.ɵɵadvance(2);
53
- i0.ɵɵtextInterpolate(item_r3.label);
77
+ i0.ɵɵtextInterpolate(item_r5.label);
54
78
  } }
55
- function PSStudioResourceComponent_Conditional_3_For_3_Template(rf, ctx) { if (rf & 1) {
56
- i0.ɵɵconditionalCreate(0, PSStudioResourceComponent_Conditional_3_For_3_Conditional_0_Template, 2, 1, "div", 9);
57
- i0.ɵɵrepeaterCreate(1, PSStudioResourceComponent_Conditional_3_For_3_For_2_Template, 4, 6, "button", 10, _forTrack0);
79
+ function PSStudioResourceComponent_Conditional_4_For_3_Template(rf, ctx) { if (rf & 1) {
80
+ i0.ɵɵconditionalCreate(0, PSStudioResourceComponent_Conditional_4_For_3_Conditional_0_Template, 2, 1, "div", 16);
81
+ i0.ɵɵrepeaterCreate(1, PSStudioResourceComponent_Conditional_4_For_3_For_2_Template, 4, 6, "button", 17, _forTrack0);
58
82
  } if (rf & 2) {
59
- const group_r1 = ctx.$implicit;
60
- const ctx_r3 = i0.ɵɵnextContext(2);
61
- i0.ɵɵconditional(group_r1 ? 0 : -1);
83
+ const group_r3 = ctx.$implicit;
84
+ const ctx_r1 = i0.ɵɵnextContext(2);
85
+ i0.ɵɵconditional(group_r3 ? 0 : -1);
62
86
  i0.ɵɵadvance();
63
- i0.ɵɵrepeater(ctx_r3.itemsForGroup(group_r1));
87
+ i0.ɵɵrepeater(ctx_r1.itemsForGroup(group_r3));
64
88
  } }
65
- function PSStudioResourceComponent_Conditional_3_Case_5_Template(rf, ctx) { if (rf & 1) {
66
- const _r5 = i0.ɵɵgetCurrentView();
67
- i0.ɵɵelementStart(0, "ps-home", 12);
68
- i0.ɵɵlistener("navigate", function PSStudioResourceComponent_Conditional_3_Case_5_Template_ps_home_navigate_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.mapNavigate($event)); })("askAgent", function PSStudioResourceComponent_Conditional_3_Case_5_Template_ps_home_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onAskAgent($event)); });
89
+ function PSStudioResourceComponent_Conditional_4_Case_5_Template(rf, ctx) { if (rf & 1) {
90
+ const _r6 = i0.ɵɵgetCurrentView();
91
+ i0.ɵɵelementStart(0, "ps-home", 19);
92
+ i0.ɵɵlistener("navigate", function PSStudioResourceComponent_Conditional_4_Case_5_Template_ps_home_navigate_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.mapNavigate($event)); })("askAgent", function PSStudioResourceComponent_Conditional_4_Case_5_Template_ps_home_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onAskAgent($event)); });
69
93
  i0.ɵɵelementEnd();
70
94
  } if (rf & 2) {
71
- const ctx_r3 = i0.ɵɵnextContext(2);
72
- i0.ɵɵproperty("engine", ctx_r3.engine)("provider", ctx_r3.ProviderToUse)("currentUser", ctx_r3.ProviderToUse.CurrentUser);
95
+ const ctx_r1 = i0.ɵɵnextContext(2);
96
+ i0.ɵɵproperty("engine", ctx_r1.engine)("provider", ctx_r1.ProviderToUse)("currentUser", ctx_r1.ProviderToUse.CurrentUser);
73
97
  } }
74
- function PSStudioResourceComponent_Conditional_3_Case_6_Template(rf, ctx) { if (rf & 1) {
75
- const _r6 = i0.ɵɵgetCurrentView();
76
- i0.ɵɵelementStart(0, "ps-pipelines", 13);
77
- i0.ɵɵlistener("askAgent", function PSStudioResourceComponent_Conditional_3_Case_6_Template_ps_pipelines_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onAskAgent($event)); });
98
+ function PSStudioResourceComponent_Conditional_4_Case_6_Template(rf, ctx) { if (rf & 1) {
99
+ const _r7 = i0.ɵɵgetCurrentView();
100
+ i0.ɵɵelementStart(0, "ps-pipelines", 20);
101
+ i0.ɵɵlistener("askAgent", function PSStudioResourceComponent_Conditional_4_Case_6_Template_ps_pipelines_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onAskAgent($event)); });
78
102
  i0.ɵɵelementEnd();
79
103
  } if (rf & 2) {
80
- const ctx_r3 = i0.ɵɵnextContext(2);
81
- i0.ɵɵproperty("engine", ctx_r3.engine)("provider", ctx_r3.ProviderToUse)("currentUser", ctx_r3.ProviderToUse.CurrentUser);
104
+ const ctx_r1 = i0.ɵɵnextContext(2);
105
+ i0.ɵɵproperty("engine", ctx_r1.engine)("provider", ctx_r1.ProviderToUse)("currentUser", ctx_r1.ProviderToUse.CurrentUser);
82
106
  } }
83
- function PSStudioResourceComponent_Conditional_3_Case_7_Template(rf, ctx) { if (rf & 1) {
84
- const _r7 = i0.ɵɵgetCurrentView();
85
- i0.ɵɵelementStart(0, "ps-catalog", 14);
86
- i0.ɵɵlistener("askAgent", function PSStudioResourceComponent_Conditional_3_Case_7_Template_ps_catalog_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onAskAgent($event)); });
107
+ function PSStudioResourceComponent_Conditional_4_Case_7_Template(rf, ctx) { if (rf & 1) {
108
+ const _r8 = i0.ɵɵgetCurrentView();
109
+ i0.ɵɵelementStart(0, "ps-catalog", 21);
110
+ i0.ɵɵlistener("askAgent", function PSStudioResourceComponent_Conditional_4_Case_7_Template_ps_catalog_askAgent_0_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onAskAgent($event)); });
87
111
  i0.ɵɵelementEnd();
88
112
  } if (rf & 2) {
89
- const ctx_r3 = i0.ɵɵnextContext(2);
90
- i0.ɵɵproperty("engine", ctx_r3.engine);
113
+ const ctx_r1 = i0.ɵɵnextContext(2);
114
+ i0.ɵɵproperty("engine", ctx_r1.engine);
91
115
  } }
92
- function PSStudioResourceComponent_Conditional_3_Case_8_Template(rf, ctx) { if (rf & 1) {
93
- i0.ɵɵelement(0, "ps-experiments", 6);
116
+ function PSStudioResourceComponent_Conditional_4_Case_8_Template(rf, ctx) { if (rf & 1) {
117
+ i0.ɵɵelement(0, "ps-experiments", 13);
94
118
  } if (rf & 2) {
95
- const ctx_r3 = i0.ɵɵnextContext(2);
96
- i0.ɵɵproperty("engine", ctx_r3.engine)("provider", ctx_r3.ProviderToUse)("currentUser", ctx_r3.ProviderToUse.CurrentUser);
119
+ const ctx_r1 = i0.ɵɵnextContext(2);
120
+ i0.ɵɵproperty("engine", ctx_r1.engine)("provider", ctx_r1.ProviderToUse)("currentUser", ctx_r1.ProviderToUse.CurrentUser);
97
121
  } }
98
- function PSStudioResourceComponent_Conditional_3_Case_9_Template(rf, ctx) { if (rf & 1) {
99
- i0.ɵɵelement(0, "ps-compare", 7);
122
+ function PSStudioResourceComponent_Conditional_4_Case_9_Template(rf, ctx) { if (rf & 1) {
123
+ i0.ɵɵelement(0, "ps-compare", 14);
100
124
  } if (rf & 2) {
101
- const ctx_r3 = i0.ɵɵnextContext(2);
102
- i0.ɵɵproperty("engine", ctx_r3.engine);
125
+ const ctx_r1 = i0.ɵɵnextContext(2);
126
+ i0.ɵɵproperty("engine", ctx_r1.engine);
103
127
  } }
104
- function PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_8_Template(rf, ctx) { if (rf & 1) {
105
- const _r9 = i0.ɵɵgetCurrentView();
106
- i0.ɵɵelementStart(0, "mj-conversation-chat-area", 23);
107
- i0.ɵɵlistener("conversationCreated", function PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_8_Template_mj_conversation_chat_area_conversationCreated_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r3 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r3.onChatConversationCreated($event)); })("pendingMessageConsumed", function PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_8_Template_mj_conversation_chat_area_pendingMessageConsumed_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r3 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r3.onChatPendingMessageConsumed()); });
128
+ function PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_8_Template(rf, ctx) { if (rf & 1) {
129
+ const _r10 = i0.ɵɵgetCurrentView();
130
+ i0.ɵɵelementStart(0, "mj-conversation-chat-area", 30);
131
+ i0.ɵɵlistener("conversationCreated", function PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_8_Template_mj_conversation_chat_area_conversationCreated_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onChatConversationCreated($event)); })("pendingMessageConsumed", function PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_8_Template_mj_conversation_chat_area_pendingMessageConsumed_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onChatPendingMessageConsumed()); });
108
132
  i0.ɵɵelementEnd();
109
133
  } if (rf & 2) {
110
- const ctx_r3 = i0.ɵɵnextContext(3);
111
- i0.ɵɵproperty("Provider", ctx_r3.Provider)("environmentId", ctx_r3.chatEnvironmentId)("currentUser", ctx_r3.currentUser)("conversation", ctx_r3.chatConversation)("conversationId", ctx_r3.chatConversationId)("isNewConversation", ctx_r3.chatIsNewConversation)("suppressNewConversationEmptyState", true)("allowMentions", false)("overlayMode", true)("showExportButton", false)("showShareButton", false)("showArtifactIndicator", false)("showAgentPicker", false)("showAgentModePicker", false)("defaultAgentId", ctx_r3.modelDevAgentId)("pendingMessage", ctx_r3.pendingPrompt)("applicationScope", "Application")("applicationId", ctx_r3.applicationId)("appContext", ctx_r3.chatAppContext);
134
+ const ctx_r1 = i0.ɵɵnextContext(3);
135
+ i0.ɵɵproperty("Provider", ctx_r1.Provider)("environmentId", ctx_r1.chatEnvironmentId)("currentUser", ctx_r1.currentUser)("conversation", ctx_r1.chatConversation)("conversationId", ctx_r1.chatConversationId)("isNewConversation", ctx_r1.chatIsNewConversation)("suppressNewConversationEmptyState", true)("allowMentions", false)("overlayMode", true)("showExportButton", false)("showShareButton", false)("showArtifactIndicator", false)("showAgentPicker", false)("showAgentModePicker", false)("defaultAgentId", ctx_r1.modelDevAgentId)("pendingMessage", ctx_r1.pendingPrompt)("applicationScope", "Application")("applicationId", ctx_r1.applicationId)("appContext", ctx_r1.chatAppContext);
112
136
  } }
113
- function PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
114
- i0.ɵɵelementStart(0, "div", 22);
115
- i0.ɵɵelement(1, "mj-loading", 24);
137
+ function PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
138
+ i0.ɵɵelementStart(0, "div", 29);
139
+ i0.ɵɵelement(1, "mj-loading", 31);
116
140
  i0.ɵɵelementEnd();
117
141
  } }
118
- function PSStudioResourceComponent_Conditional_3_Conditional_10_Template(rf, ctx) { if (rf & 1) {
119
- const _r8 = i0.ɵɵgetCurrentView();
120
- i0.ɵɵelementStart(0, "aside", 8)(1, "div", 15)(2, "div", 16);
121
- i0.ɵɵelement(3, "i", 17);
142
+ function PSStudioResourceComponent_Conditional_4_Conditional_10_Template(rf, ctx) { if (rf & 1) {
143
+ const _r9 = i0.ɵɵgetCurrentView();
144
+ i0.ɵɵelementStart(0, "aside", 15)(1, "div", 22)(2, "div", 23);
145
+ i0.ɵɵelement(3, "i", 24);
122
146
  i0.ɵɵtext(4, " Model Dev Agent");
123
147
  i0.ɵɵelementEnd();
124
- i0.ɵɵelementStart(5, "button", 18);
125
- i0.ɵɵlistener("click", function PSStudioResourceComponent_Conditional_3_Conditional_10_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.closeChat()); });
126
- i0.ɵɵelement(6, "i", 19);
148
+ i0.ɵɵelementStart(5, "button", 25);
149
+ i0.ɵɵlistener("click", function PSStudioResourceComponent_Conditional_4_Conditional_10_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.closeChat()); });
150
+ i0.ɵɵelement(6, "i", 26);
127
151
  i0.ɵɵelementEnd()();
128
- i0.ɵɵelementStart(7, "div", 20);
129
- i0.ɵɵconditionalCreate(8, PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_8_Template, 1, 19, "mj-conversation-chat-area", 21)(9, PSStudioResourceComponent_Conditional_3_Conditional_10_Conditional_9_Template, 2, 0, "div", 22);
152
+ i0.ɵɵelementStart(7, "div", 27);
153
+ i0.ɵɵconditionalCreate(8, PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_8_Template, 1, 19, "mj-conversation-chat-area", 28)(9, PSStudioResourceComponent_Conditional_4_Conditional_10_Conditional_9_Template, 2, 0, "div", 29);
130
154
  i0.ɵɵelementEnd()();
131
155
  } if (rf & 2) {
132
- const ctx_r3 = i0.ɵɵnextContext(2);
156
+ const ctx_r1 = i0.ɵɵnextContext(2);
133
157
  i0.ɵɵadvance(8);
134
- i0.ɵɵconditional(ctx_r3.currentUser ? 8 : 9);
158
+ i0.ɵɵconditional(ctx_r1.currentUser ? 8 : 9);
135
159
  } }
136
- function PSStudioResourceComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
137
- i0.ɵɵelementStart(0, "div", 3)(1, "aside", 4);
138
- i0.ɵɵrepeaterCreate(2, PSStudioResourceComponent_Conditional_3_For_3_Template, 3, 1, null, null, i0.ɵɵrepeaterTrackByIdentity);
160
+ function PSStudioResourceComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
161
+ i0.ɵɵelementStart(0, "div", 10)(1, "aside", 11);
162
+ i0.ɵɵrepeaterCreate(2, PSStudioResourceComponent_Conditional_4_For_3_Template, 3, 1, null, null, i0.ɵɵrepeaterTrackByIdentity);
139
163
  i0.ɵɵelementEnd();
140
- i0.ɵɵelementStart(4, "section", 5);
141
- i0.ɵɵconditionalCreate(5, PSStudioResourceComponent_Conditional_3_Case_5_Template, 1, 3, "ps-home", 6)(6, PSStudioResourceComponent_Conditional_3_Case_6_Template, 1, 3, "ps-pipelines", 6)(7, PSStudioResourceComponent_Conditional_3_Case_7_Template, 1, 1, "ps-catalog", 7)(8, PSStudioResourceComponent_Conditional_3_Case_8_Template, 1, 3, "ps-experiments", 6)(9, PSStudioResourceComponent_Conditional_3_Case_9_Template, 1, 1, "ps-compare", 7);
164
+ i0.ɵɵelementStart(4, "section", 12);
165
+ i0.ɵɵconditionalCreate(5, PSStudioResourceComponent_Conditional_4_Case_5_Template, 1, 3, "ps-home", 13)(6, PSStudioResourceComponent_Conditional_4_Case_6_Template, 1, 3, "ps-pipelines", 13)(7, PSStudioResourceComponent_Conditional_4_Case_7_Template, 1, 1, "ps-catalog", 14)(8, PSStudioResourceComponent_Conditional_4_Case_8_Template, 1, 3, "ps-experiments", 13)(9, PSStudioResourceComponent_Conditional_4_Case_9_Template, 1, 1, "ps-compare", 14);
142
166
  i0.ɵɵelementEnd();
143
- i0.ɵɵconditionalCreate(10, PSStudioResourceComponent_Conditional_3_Conditional_10_Template, 10, 1, "aside", 8);
167
+ i0.ɵɵconditionalCreate(10, PSStudioResourceComponent_Conditional_4_Conditional_10_Template, 10, 1, "aside", 15);
144
168
  i0.ɵɵelementEnd();
145
169
  } if (rf & 2) {
146
- let tmp_4_0;
147
- const ctx_r3 = i0.ɵɵnextContext();
148
- i0.ɵɵclassProp("chat-open", ctx_r3.chatOpen);
170
+ let tmp_5_0;
171
+ const ctx_r1 = i0.ɵɵnextContext();
172
+ i0.ɵɵclassProp("chat-open", ctx_r1.chatOpen);
149
173
  i0.ɵɵadvance(2);
150
- i0.ɵɵrepeater(ctx_r3.groups);
174
+ i0.ɵɵrepeater(ctx_r1.groups);
151
175
  i0.ɵɵadvance(2);
152
- i0.ɵɵattribute("data-testid", "ps-panel-" + ctx_r3.activeSection);
176
+ i0.ɵɵclassProp("fill", ctx_r1.activeSection === "pipelines");
177
+ i0.ɵɵattribute("data-testid", "ps-panel-" + ctx_r1.activeSection);
153
178
  i0.ɵɵadvance();
154
- i0.ɵɵconditional((tmp_4_0 = ctx_r3.activeSection) === "home" ? 5 : tmp_4_0 === "pipelines" ? 6 : tmp_4_0 === "catalog" ? 7 : tmp_4_0 === "experiments" ? 8 : tmp_4_0 === "compare" ? 9 : -1);
179
+ i0.ɵɵconditional((tmp_5_0 = ctx_r1.activeSection) === "home" ? 5 : tmp_5_0 === "pipelines" ? 6 : tmp_5_0 === "catalog" ? 7 : tmp_5_0 === "experiments" ? 8 : tmp_5_0 === "compare" ? 9 : -1);
155
180
  i0.ɵɵadvance(5);
156
- i0.ɵɵconditional(ctx_r3.chatOpen ? 10 : -1);
181
+ i0.ɵɵconditional(ctx_r1.chatOpen ? 10 : -1);
157
182
  } }
158
183
  /** Predictive Studio application ID (from `metadata/applications/.predictive-studio-application.json`). */
159
184
  const PREDICTIVE_STUDIO_APP_ID = '299C9272-8D38-40CA-85D4-0980F2C9FAD1';
@@ -199,14 +224,70 @@ let PSStudioResourceComponent = class PSStudioResourceComponent extends PSResour
199
224
  this.cdrLocal.detectChanges();
200
225
  }
201
226
  }
227
+ /** Deep agent context for the Studio door (build/run workbench counts + active section). */
202
228
  extraAgentContext() {
203
- return { ActiveSection: sectionLabel(this.sections, this.activeSection) };
229
+ return buildStudioAgentContext({
230
+ ActiveSection: this.activeSection,
231
+ ActiveSectionLabel: this.activeLabel,
232
+ SectionLabels: this.sections.map((s) => s.label),
233
+ PublishedModelCount: this.engine.PublishedModels.length,
234
+ RunningSessionCount: this.engine.RunningSessions.length,
235
+ PipelineCount: this.engine.Pipelines.length,
236
+ AlgorithmCount: this.engine.Algorithms.length,
237
+ ExperimentCount: this.engine.Experiments.length,
238
+ TrainingRunCount: this.engine.TrainingRuns.length,
239
+ ChatOpen: this.chatOpen,
240
+ });
241
+ }
242
+ /**
243
+ * 🔒 Read/navigate-only agent tools for the Studio door: switch the active section, or open the docked
244
+ * Model Dev Agent co-pilot. NO build/train/publish tool is exposed — model creation runs through the
245
+ * co-pilot conversation (the approve-gated builder), never a fire-and-forget agent tool.
246
+ */
247
+ registerAgentTools() {
248
+ this.navigationService.SetAgentClientTools(this, [
249
+ {
250
+ Name: 'SwitchStudioSection',
251
+ Description: 'Switch the Studio workbench to a section. Pass the section key or label (see SectionLabels): Overview, Training Pipelines, Algorithm Catalog, Experiments, or Compare Runs.',
252
+ ParameterSchema: { type: 'object', properties: { section: { type: 'string', description: 'The section key or label to switch to' } } },
253
+ Handler: async (params) => {
254
+ const check = validateStringParam(params['section'], 'section');
255
+ if (!check.ok)
256
+ return check.result;
257
+ const candidates = this.sections.map((s) => ({ ID: s.key, Name: s.label }));
258
+ const match = resolvePSRecord(check.value, candidates);
259
+ if (!match)
260
+ return { Success: false, ErrorMessage: buildPSNotFoundError(check.value, candidates, 'section') };
261
+ this.selectSection(match.ID);
262
+ return { Success: true, Data: { activeSection: match.Name } };
263
+ },
264
+ },
265
+ {
266
+ Name: 'OpenModelDevAgentCopilot',
267
+ Description: 'Open the docked Model Development Agent co-pilot in the Studio (does not send a message — the user drives the conversation). Use when the user wants to design/build a new prediction.',
268
+ ParameterSchema: { type: 'object', properties: {} },
269
+ Handler: async () => {
270
+ this.openCopilot();
271
+ return { Success: true, Data: { chatOpen: true } };
272
+ },
273
+ },
274
+ ]);
204
275
  }
205
276
  // ── left-nav ─────────────────────────────────────────────────────
206
277
  get groups() { return sectionGroups(this.sections); }
207
278
  itemsForGroup(group) { return sectionsInGroup(this.sections, group); }
208
279
  get activeLabel() { return sectionLabel(this.sections, this.activeSection); }
209
- get activeIcon() { return sectionIcon(this.sections, this.activeSection); }
280
+ /** Section-specific subtitle for the interior header (so every section doesn't repeat one generic line). */
281
+ get activeSubtitle() {
282
+ const map = {
283
+ home: 'Start a new prediction from your data, a template, or the agent.',
284
+ pipelines: 'Assemble features and train from the algorithm catalog.',
285
+ catalog: 'Browse algorithms with a fit guide for your use case.',
286
+ experiments: 'Run and track model experiments.',
287
+ compare: 'Compare runs on the honest holdout score.',
288
+ };
289
+ return map[this.activeSection] ?? '';
290
+ }
210
291
  selectSection(key) {
211
292
  if (this.activeSection === key)
212
293
  return;
@@ -239,11 +320,21 @@ let PSStudioResourceComponent = class PSStudioResourceComponent extends PSResour
239
320
  this.pendingPrompt = starterPrompt;
240
321
  this.chatOpen = true;
241
322
  void this.ensureModelDevAgentResolved();
323
+ this.publishAgentContext();
324
+ this.cdrLocal.detectChanges();
325
+ }
326
+ /** Open the docked co-pilot (clean chat) — used by the read-only `OpenModelDevAgentCopilot` agent tool. */
327
+ openCopilot() {
328
+ this.pendingPrompt = null;
329
+ this.chatOpen = true;
330
+ void this.ensureModelDevAgentResolved();
331
+ this.publishAgentContext();
242
332
  this.cdrLocal.detectChanges();
243
333
  }
244
334
  closeChat() {
245
335
  this.chatOpen = false;
246
336
  this.pendingPrompt = null;
337
+ this.publishAgentContext();
247
338
  this.cdrLocal.detectChanges();
248
339
  }
249
340
  /** Chat-area created its backing conversation on the first send — capture it + leave new-mode so the thread renders. */
@@ -275,16 +366,18 @@ let PSStudioResourceComponent = class PSStudioResourceComponent extends PSResour
275
366
  }
276
367
  }
277
368
  static ɵfac = /*@__PURE__*/ (() => { let ɵPSStudioResourceComponent_BaseFactory; return function PSStudioResourceComponent_Factory(__ngFactoryType__) { return (ɵPSStudioResourceComponent_BaseFactory || (ɵPSStudioResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(PSStudioResourceComponent)))(__ngFactoryType__ || PSStudioResourceComponent); }; })();
278
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSStudioResourceComponent, selectors: [["mj-ps-studio-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [["Subtitle", "Assemble features, train from the algorithm catalog, and run experiments", 3, "Title"], ["text", "Loading Studio\u2026", "size", "medium"], ["data-testid", "ps-studio-shell", 1, "ps-studio-host", 3, "chat-open"], ["data-testid", "ps-studio-shell", 1, "ps-studio-host"], [1, "ps-leftnav"], [1, "ps-content"], [3, "engine", "provider", "currentUser"], [3, "engine"], ["data-testid", "ps-studio-copilot", 1, "ps-copilot"], [1, "ps-nav-group"], [1, "ps-nav-item", 3, "active"], [1, "ps-nav-item", 3, "click"], [3, "navigate", "askAgent", "engine", "provider", "currentUser"], [3, "askAgent", "engine", "provider", "currentUser"], [3, "askAgent", "engine"], [1, "ps-copilot-head"], [1, "ps-copilot-title"], [1, "fa-solid", "fa-robot"], ["aria-label", "Close agent chat", 1, "ps-copilot-close", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "ps-copilot-body"], ["emptyStateGreeting", "Describe a prediction goal and I'll design the pipeline.", 3, "Provider", "environmentId", "currentUser", "conversation", "conversationId", "isNewConversation", "suppressNewConversationEmptyState", "allowMentions", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "showAgentPicker", "showAgentModePicker", "defaultAgentId", "pendingMessage", "applicationScope", "applicationId", "appContext"], [1, "ps-copilot-empty"], ["emptyStateGreeting", "Describe a prediction goal and I'll design the pipeline.", 3, "conversationCreated", "pendingMessageConsumed", "Provider", "environmentId", "currentUser", "conversation", "conversationId", "isNewConversation", "suppressNewConversationEmptyState", "allowMentions", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "showAgentPicker", "showAgentModePicker", "defaultAgentId", "pendingMessage", "applicationScope", "applicationId", "appContext"], ["text", "Connecting\u2026", "size", "small"]], template: function PSStudioResourceComponent_Template(rf, ctx) { if (rf & 1) {
369
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSStudioResourceComponent, selectors: [["mj-ps-studio-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 5, consts: [[3, "Title", "Subtitle"], [3, "Flex", "Padding"], ["text", "Loading Studio\u2026", "size", "medium"], ["data-testid", "ps-load-error", "role", "alert", 1, "ps-load-error"], ["data-testid", "ps-studio-shell", 1, "ps-studio-host", 3, "chat-open"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "ps-load-error-text"], [1, "ps-load-error-detail"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-rotate-right"], ["data-testid", "ps-studio-shell", 1, "ps-studio-host"], [1, "ps-leftnav"], [1, "ps-content"], [3, "engine", "provider", "currentUser"], [3, "engine"], ["data-testid", "ps-studio-copilot", 1, "ps-copilot"], [1, "ps-nav-group"], [1, "ps-nav-item", 3, "active"], [1, "ps-nav-item", 3, "click"], [3, "navigate", "askAgent", "engine", "provider", "currentUser"], [3, "askAgent", "engine", "provider", "currentUser"], [3, "askAgent", "engine"], [1, "ps-copilot-head"], [1, "ps-copilot-title"], [1, "fa-solid", "fa-robot"], ["aria-label", "Close agent chat", 1, "ps-copilot-close", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "ps-copilot-body"], [3, "Provider", "environmentId", "currentUser", "conversation", "conversationId", "isNewConversation", "suppressNewConversationEmptyState", "allowMentions", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "showAgentPicker", "showAgentModePicker", "defaultAgentId", "pendingMessage", "applicationScope", "applicationId", "appContext"], [1, "ps-copilot-empty"], [3, "conversationCreated", "pendingMessageConsumed", "Provider", "environmentId", "currentUser", "conversation", "conversationId", "isNewConversation", "suppressNewConversationEmptyState", "allowMentions", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "showAgentPicker", "showAgentModePicker", "defaultAgentId", "pendingMessage", "applicationScope", "applicationId", "appContext"], ["text", "Connecting\u2026", "size", "small"]], template: function PSStudioResourceComponent_Template(rf, ctx) { if (rf & 1) {
279
370
  i0.ɵɵelement(0, "mj-page-header-interior", 0);
280
- i0.ɵɵelementStart(1, "mj-page-body-interior");
281
- i0.ɵɵconditionalCreate(2, PSStudioResourceComponent_Conditional_2_Template, 1, 0, "mj-loading", 1)(3, PSStudioResourceComponent_Conditional_3_Template, 11, 5, "div", 2);
371
+ i0.ɵɵelementStart(1, "mj-page-body-interior", 1);
372
+ i0.ɵɵconditionalCreate(2, PSStudioResourceComponent_Conditional_2_Template, 1, 0, "mj-loading", 2)(3, PSStudioResourceComponent_Conditional_3_Template, 10, 2, "div", 3)(4, PSStudioResourceComponent_Conditional_4_Template, 11, 7, "div", 4);
282
373
  i0.ɵɵelementEnd();
283
374
  } if (rf & 2) {
284
- i0.ɵɵproperty("Title", ctx.activeLabel);
285
- i0.ɵɵadvance(2);
286
- i0.ɵɵconditional(ctx.isLoading ? 2 : 3);
287
- } }, dependencies: [i1.MJPageHeaderInteriorComponent, i1.MJPageBodyInteriorComponent, i2.LoadingComponent, i3.ConversationChatAreaComponent, i4.PSHomeComponent, i5.PSCatalogComponent, i6.PSPipelinesComponent, i7.PSExperimentsComponent, i8.PSCompareComponent], styles: ["[_nghost-%COMP%] { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host[_ngcontent-%COMP%] { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav[_ngcontent-%COMP%] { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group[_ngcontent-%COMP%] { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n .ps-content[_ngcontent-%COMP%] { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n .ps-copilot[_ngcontent-%COMP%] { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n .ps-copilot-close[_ngcontent-%COMP%] { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body[_ngcontent-%COMP%] { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body[_ngcontent-%COMP%] mj-conversation-chat-area[_ngcontent-%COMP%] { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; flex: 1; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open[_ngcontent-%COMP%] .ps-content[_ngcontent-%COMP%], .ps-studio-host.chat-open[_ngcontent-%COMP%] .ps-leftnav[_ngcontent-%COMP%] { display: none; } .ps-copilot[_ngcontent-%COMP%] { width: 100%; max-width: none; border-left: none; } }"], changeDetection: 0 });
375
+ i0.ɵɵproperty("Title", ctx.activeLabel)("Subtitle", ctx.activeSubtitle);
376
+ i0.ɵɵadvance();
377
+ i0.ɵɵproperty("Flex", true)("Padding", false);
378
+ i0.ɵɵadvance();
379
+ i0.ɵɵconditional(ctx.isLoading ? 2 : ctx.loadError ? 3 : 4);
380
+ } }, dependencies: [i1.MJButtonDirective, i1.MJPageHeaderInteriorComponent, i1.MJPageBodyInteriorComponent, i2.LoadingComponent, i3.ConversationChatAreaComponent, i4.PSHomeComponent, i5.PSCatalogComponent, i6.PSPipelinesComponent, i7.PSExperimentsComponent, i8.PSCompareComponent], styles: ["[_nghost-%COMP%] { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host[_ngcontent-%COMP%] { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav[_ngcontent-%COMP%] { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group[_ngcontent-%COMP%] { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n .ps-content[_ngcontent-%COMP%] { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n \n\n\n .ps-content.fill[_ngcontent-%COMP%] { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }\n .ps-content.fill[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .ps-copilot[_ngcontent-%COMP%] { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n .ps-copilot-close[_ngcontent-%COMP%] { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body[_ngcontent-%COMP%] { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body[_ngcontent-%COMP%] mj-conversation-chat-area[_ngcontent-%COMP%] { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; flex: 1; }\n .ps-load-error[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 14px; max-width: 620px; margin: 32px auto; padding: 18px 20px; border: 1px solid var(--mj-status-error-border); background: var(--mj-status-error-bg); border-radius: var(--mj-radius-lg); }\n .ps-load-error[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { font-size: 24px; color: var(--mj-status-error); }\n .ps-load-error-text[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }\n .ps-load-error-text[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] { color: var(--mj-text-primary); }\n .ps-load-error-detail[_ngcontent-%COMP%] { color: var(--mj-text-secondary); font-size: var(--mj-text-sm); word-break: break-word; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open[_ngcontent-%COMP%] .ps-content[_ngcontent-%COMP%], .ps-studio-host.chat-open[_ngcontent-%COMP%] .ps-leftnav[_ngcontent-%COMP%] { display: none; } .ps-copilot[_ngcontent-%COMP%] { width: 100%; max-width: none; border-left: none; } }"], changeDetection: 0 });
288
381
  };
289
382
  PSStudioResourceComponent = __decorate([
290
383
  RegisterClass(BaseResourceComponent, 'PredictiveStudioStudioResource')
@@ -293,12 +386,20 @@ export { PSStudioResourceComponent };
293
386
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PSStudioResourceComponent, [{
294
387
  type: Component,
295
388
  args: [{ standalone: false, selector: 'mj-ps-studio-resource', template: `
296
- <mj-page-header-interior [Title]="activeLabel"
297
- Subtitle="Assemble features, train from the algorithm catalog, and run experiments">
389
+ <mj-page-header-interior [Title]="activeLabel" [Subtitle]="activeSubtitle">
298
390
  </mj-page-header-interior>
299
- <mj-page-body-interior>
391
+ <mj-page-body-interior [Flex]="true" [Padding]="false">
300
392
  @if (isLoading) {
301
393
  <mj-loading text="Loading Studio…" size="medium"></mj-loading>
394
+ } @else if (loadError) {
395
+ <div class="ps-load-error" data-testid="ps-load-error" role="alert">
396
+ <i class="fa-solid fa-triangle-exclamation"></i>
397
+ <div class="ps-load-error-text">
398
+ <strong>Couldn't load {{ sectionTitle }}</strong>
399
+ <span class="ps-load-error-detail">{{ loadError }}</span>
400
+ </div>
401
+ <button mjButton variant="secondary" size="sm" (click)="retryLoad()"><i class="fa-solid fa-rotate-right"></i> Try again</button>
402
+ </div>
302
403
  } @else {
303
404
  <div class="ps-studio-host" [class.chat-open]="chatOpen" data-testid="ps-studio-shell">
304
405
  <aside class="ps-leftnav">
@@ -313,7 +414,7 @@ export { PSStudioResourceComponent };
313
414
  }
314
415
  </aside>
315
416
 
316
- <section class="ps-content" [attr.data-testid]="'ps-panel-' + activeSection">
417
+ <section class="ps-content" [class.fill]="activeSection === 'pipelines'" [attr.data-testid]="'ps-panel-' + activeSection">
317
418
  @switch (activeSection) {
318
419
  @case ('home') { <ps-home [engine]="engine" [provider]="ProviderToUse" [currentUser]="ProviderToUse.CurrentUser" (navigate)="mapNavigate($event)" (askAgent)="onAskAgent($event)"></ps-home> }
319
420
  @case ('pipelines') { <ps-pipelines [engine]="engine" [provider]="ProviderToUse" [currentUser]="ProviderToUse.CurrentUser" (askAgent)="onAskAgent($event)"></ps-pipelines> }
@@ -340,8 +441,7 @@ export { PSStudioResourceComponent };
340
441
  [defaultAgentId]="modelDevAgentId" [pendingMessage]="pendingPrompt"
341
442
  [applicationScope]="'Application'" [applicationId]="applicationId" [appContext]="chatAppContext"
342
443
  (conversationCreated)="onChatConversationCreated($event)"
343
- (pendingMessageConsumed)="onChatPendingMessageConsumed()"
344
- emptyStateGreeting="Describe a prediction goal and I'll design the pipeline.">
444
+ (pendingMessageConsumed)="onChatPendingMessageConsumed()">
345
445
  </mj-conversation-chat-area>
346
446
  } @else { <div class="ps-copilot-empty"><mj-loading text="Connecting…" size="small"></mj-loading></div> }
347
447
  </div>
@@ -350,9 +450,9 @@ export { PSStudioResourceComponent };
350
450
  </div>
351
451
  }
352
452
  </mj-page-body-interior>
353
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n .ps-content { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n .ps-copilot { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n "] }]
453
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n .ps-content { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n /* Fill mode (pipelines): the section stops page-scrolling so the panel's inner\n columns (canvas / inspector) can each own their scrollbar. */\n .ps-content.fill { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }\n .ps-content.fill > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .ps-copilot { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n .ps-load-error { display: flex; align-items: center; gap: 14px; max-width: 620px; margin: 32px auto; padding: 18px 20px; border: 1px solid var(--mj-status-error-border); background: var(--mj-status-error-bg); border-radius: var(--mj-radius-lg); }\n .ps-load-error > i { font-size: 24px; color: var(--mj-status-error); }\n .ps-load-error-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }\n .ps-load-error-text strong { color: var(--mj-text-primary); }\n .ps-load-error-detail { color: var(--mj-text-secondary); font-size: var(--mj-text-sm); word-break: break-word; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n "] }]
354
454
  }], null, null); })();
355
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSStudioResourceComponent, { className: "PSStudioResourceComponent", filePath: "src/PredictiveStudio/resources/ps-studio-resource.component.ts", lineNumber: 124 }); })();
455
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSStudioResourceComponent, { className: "PSStudioResourceComponent", filePath: "src/PredictiveStudio/resources/ps-studio-resource.component.ts", lineNumber: 141 }); })();
356
456
  /** Tree-shaking prevention — called from the subpath module so the @RegisterClass survives bundling. */
357
457
  export function LoadPSStudioResource() {
358
458
  // intentionally empty
@@ -1 +1 @@
1
- {"version":3,"file":"ps-studio-resource.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/resources/ps-studio-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { LogError, UserInfo } from '@memberjunction/core';\nimport { MJConversationEntity, MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { PSResourceBase } from './ps-resource-base';\nimport { PSPanelKey } from '../predictive-studio.types';\nimport {\n STUDIO_SECTIONS,\n PSSection,\n sectionGroups,\n sectionsInGroup,\n sectionLabel,\n sectionIcon,\n hasSection,\n routeHomeNavigate,\n} from '../predictive-studio.nav';\n\n/** Predictive Studio application ID (from `metadata/applications/.predictive-studio-application.json`). */\nconst PREDICTIVE_STUDIO_APP_ID = '299C9272-8D38-40CA-85D4-0980F2C9FAD1';\nconst MODEL_DEV_AGENT_NAME = 'Model Development Agent';\n\n/**\n * **Studio** — the analyst workbench door (one of Predictive Studio's three consolidated nav items,\n * alongside `Predictions` and `Models`). Hosts the build/run section panels (`ps-home`, `ps-pipelines`,\n * `ps-catalog`, `ps-experiments`, `ps-compare`) behind an internal left-nav grouped by lifecycle\n * (Overview · Build · Run), so the outer app nav stays quiet while analysts get all the depth one click\n * in. The active section round-trips through the `section` query param (deep links + back/forward). A\n * single docked **Model Development Agent** copilot is shared by every section's \"Ask the agent\" CTA —\n * wired with the full conversation lifecycle (`isNewConversation` → `conversationCreated`) so the first\n * message actually creates + sends. Cross-door navigation (to a Models section) routes via the nav\n * service; see {@link routeHomeNavigate}.\n */\n@RegisterClass(BaseResourceComponent, 'PredictiveStudioStudioResource')\n@Component({\n standalone: false,\n selector: 'mj-ps-studio-resource',\n template: `\n <mj-page-header-interior [Title]=\"activeLabel\"\n Subtitle=\"Assemble features, train from the algorithm catalog, and run experiments\">\n </mj-page-header-interior>\n <mj-page-body-interior>\n @if (isLoading) {\n <mj-loading text=\"Loading Studio…\" size=\"medium\"></mj-loading>\n } @else {\n <div class=\"ps-studio-host\" [class.chat-open]=\"chatOpen\" data-testid=\"ps-studio-shell\">\n <aside class=\"ps-leftnav\">\n @for (group of groups; track group) {\n @if (group) { <div class=\"ps-nav-group\">{{ group }}</div> }\n @for (item of itemsForGroup(group); track item.key) {\n <button class=\"ps-nav-item\" [class.active]=\"activeSection === item.key\"\n [attr.data-testid]=\"'ps-nav-' + item.key\" (click)=\"selectSection(item.key)\">\n <i [class]=\"item.icon\"></i> <span>{{ item.label }}</span>\n </button>\n }\n }\n </aside>\n\n <section class=\"ps-content\" [attr.data-testid]=\"'ps-panel-' + activeSection\">\n @switch (activeSection) {\n @case ('home') { <ps-home [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (navigate)=\"mapNavigate($event)\" (askAgent)=\"onAskAgent($event)\"></ps-home> }\n @case ('pipelines') { <ps-pipelines [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (askAgent)=\"onAskAgent($event)\"></ps-pipelines> }\n @case ('catalog') { <ps-catalog [engine]=\"engine\" (askAgent)=\"onAskAgent($event)\"></ps-catalog> }\n @case ('experiments') { <ps-experiments [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\"></ps-experiments> }\n @case ('compare') { <ps-compare [engine]=\"engine\"></ps-compare> }\n }\n </section>\n\n @if (chatOpen) {\n <aside class=\"ps-copilot\" data-testid=\"ps-studio-copilot\">\n <div class=\"ps-copilot-head\">\n <div class=\"ps-copilot-title\"><i class=\"fa-solid fa-robot\"></i> Model Dev Agent</div>\n <button class=\"ps-copilot-close\" (click)=\"closeChat()\" aria-label=\"Close agent chat\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n <div class=\"ps-copilot-body\">\n @if (currentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\" [environmentId]=\"chatEnvironmentId\" [currentUser]=\"currentUser\"\n [conversation]=\"chatConversation\" [conversationId]=\"chatConversationId\" [isNewConversation]=\"chatIsNewConversation\"\n [suppressNewConversationEmptyState]=\"true\" [allowMentions]=\"false\" [overlayMode]=\"true\"\n [showExportButton]=\"false\" [showShareButton]=\"false\" [showArtifactIndicator]=\"false\"\n [showAgentPicker]=\"false\" [showAgentModePicker]=\"false\"\n [defaultAgentId]=\"modelDevAgentId\" [pendingMessage]=\"pendingPrompt\"\n [applicationScope]=\"'Application'\" [applicationId]=\"applicationId\" [appContext]=\"chatAppContext\"\n (conversationCreated)=\"onChatConversationCreated($event)\"\n (pendingMessageConsumed)=\"onChatPendingMessageConsumed()\"\n emptyStateGreeting=\"Describe a prediction goal and I'll design the pipeline.\">\n </mj-conversation-chat-area>\n } @else { <div class=\"ps-copilot-empty\"><mj-loading text=\"Connecting…\" size=\"small\"></mj-loading></div> }\n </div>\n </aside>\n }\n </div>\n }\n </mj-page-body-interior>\n `,\n styles: [\n `\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n .ps-content { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n .ps-copilot { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PSStudioResourceComponent extends PSResourceBase {\n protected readonly SectionKey = 'studio';\n protected readonly SectionLabel = 'Studio';\n protected readonly SectionIcon = 'fa-solid fa-flask-vial';\n\n private readonly cdrLocal = inject(ChangeDetectorRef);\n\n /** The active workbench section (which panel renders). Round-trips through the `section` query param. */\n public activeSection: PSPanelKey = 'home';\n public readonly sections: readonly PSSection[] = STUDIO_SECTIONS;\n\n // ── docked Model Dev Agent copilot ───────────────────────────────\n public chatOpen = false;\n public pendingPrompt: string | null = null;\n private _modelDevAgentId: string | null = null;\n /** Conversation lifecycle (see {@link onChatConversationCreated}) — without it the first send no-ops. */\n public chatConversation: MJConversationEntity | null = null;\n public chatConversationId: string | null = null;\n public chatIsNewConversation = true;\n\n override ngOnInit(): void {\n super.ngOnInit();\n const initial = this.GetQueryParams()['section'] as PSPanelKey | undefined;\n if (initial && hasSection(this.sections, initial)) this.activeSection = initial;\n }\n\n /** React to deep-link / back-forward `section` changes after the initial mount. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const next = params['section'] as PSPanelKey | undefined;\n if (next && next !== this.activeSection && hasSection(this.sections, next)) {\n this.activeSection = next;\n this.cdrLocal.detectChanges();\n }\n }\n\n protected override extraAgentContext(): Record<string, unknown> {\n return { ActiveSection: sectionLabel(this.sections, this.activeSection) };\n }\n\n // ── left-nav ─────────────────────────────────────────────────────\n public get groups(): string[] { return sectionGroups(this.sections); }\n public itemsForGroup(group: string): PSSection[] { return sectionsInGroup(this.sections, group); }\n public get activeLabel(): string { return sectionLabel(this.sections, this.activeSection); }\n public get activeIcon(): string { return sectionIcon(this.sections, this.activeSection); }\n\n public selectSection(key: PSPanelKey): void {\n if (this.activeSection === key) return;\n this.activeSection = key;\n this.UpdateQueryParams({ section: key });\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** The Overview panel's in-app navigation: switch section in-place, or cross to the Models door. */\n public mapNavigate(key: PSPanelKey): void {\n const target = routeHomeNavigate(key);\n if (target.kind === 'section') {\n this.selectSection(target.key);\n } else if (target.kind === 'app') {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, target.navLabel, { section: target.section });\n }\n }\n\n // ── copilot ──────────────────────────────────────────────────────\n public get currentUser(): UserInfo | null { return this.ProviderToUse.CurrentUser ?? null; }\n public get chatEnvironmentId(): string {\n return (this.Data?.Configuration?.['environmentId'] as string | undefined) || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n public get applicationId(): string | null { return (this.Data?.Configuration?.['applicationId'] as string | undefined) ?? null; }\n public get modelDevAgentId(): string | null { return this._modelDevAgentId; }\n public get chatAppContext(): Record<string, unknown> {\n return { app: 'Predictive Studio', section: this.activeSection, publishedModels: this.engine.Models.filter((m) => m.Status === 'Published').length };\n }\n\n public onAskAgent(starterPrompt: string): void {\n this.pendingPrompt = starterPrompt;\n this.chatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.cdrLocal.detectChanges();\n }\n\n public closeChat(): void {\n this.chatOpen = false;\n this.pendingPrompt = null;\n this.cdrLocal.detectChanges();\n }\n\n /** Chat-area created its backing conversation on the first send — capture it + leave new-mode so the thread renders. */\n public onChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n this.pendingPrompt = event.pendingMessage ?? null;\n this.chatConversation = event.conversation;\n this.chatConversationId = event.conversation.ID;\n this.chatIsNewConversation = false;\n this.cdrLocal.detectChanges();\n }\n\n /** Chat-area delivered the seeded prompt — clear the buffer so a re-render doesn't resend it. */\n public onChatPendingMessageConsumed(): void {\n this.pendingPrompt = null;\n this.cdrLocal.detectChanges();\n }\n\n private async ensureModelDevAgentResolved(): Promise<void> {\n if (this._modelDevAgentId) return;\n try {\n await AIEngineBase.Instance.Config(false, this.ProviderToUse.CurrentUser ?? undefined);\n this._modelDevAgentId =\n AIEngineBase.Instance.Agents?.find((a) => a.Name?.trim().toLowerCase() === MODEL_DEV_AGENT_NAME.toLowerCase())?.ID ?? null;\n if (!this._modelDevAgentId) LogError(`PSStudioResource: '${MODEL_DEV_AGENT_NAME}' not found — chat uses default-agent routing.`);\n this.cdrLocal.detectChanges();\n } catch (err) {\n LogError(`PSStudioResource.ensureModelDevAgentResolved: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n/** Tree-shaking prevention — called from the subpath module so the @RegisterClass survives bundling. */\nexport function LoadPSStudioResource(): void {\n // intentionally empty\n}\n"]}
1
+ {"version":3,"file":"ps-studio-resource.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/resources/ps-studio-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { LogError, UserInfo } from '@memberjunction/core';\nimport { MJConversationEntity, MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { PSResourceBase } from './ps-resource-base';\nimport { PSPanelKey } from '../predictive-studio.types';\nimport {\n STUDIO_SECTIONS,\n PSSection,\n sectionGroups,\n sectionsInGroup,\n sectionLabel,\n hasSection,\n routeHomeNavigate,\n} from '../predictive-studio.nav';\nimport { buildStudioAgentContext, resolvePSRecord, buildPSNotFoundError } from '../predictive-studio-agent-context';\nimport { validateStringParam } from '../../shared/agent-tool-validation';\n\n/** Predictive Studio application ID (from `metadata/applications/.predictive-studio-application.json`). */\nconst PREDICTIVE_STUDIO_APP_ID = '299C9272-8D38-40CA-85D4-0980F2C9FAD1';\nconst MODEL_DEV_AGENT_NAME = 'Model Development Agent';\n\n/**\n * **Studio** — the analyst workbench door (one of Predictive Studio's three consolidated nav items,\n * alongside `Predictions` and `Models`). Hosts the build/run section panels (`ps-home`, `ps-pipelines`,\n * `ps-catalog`, `ps-experiments`, `ps-compare`) behind an internal left-nav grouped by lifecycle\n * (Overview · Build · Run), so the outer app nav stays quiet while analysts get all the depth one click\n * in. The active section round-trips through the `section` query param (deep links + back/forward). A\n * single docked **Model Development Agent** copilot is shared by every section's \"Ask the agent\" CTA —\n * wired with the full conversation lifecycle (`isNewConversation` → `conversationCreated`) so the first\n * message actually creates + sends. Cross-door navigation (to a Models section) routes via the nav\n * service; see {@link routeHomeNavigate}.\n */\n@RegisterClass(BaseResourceComponent, 'PredictiveStudioStudioResource')\n@Component({\n standalone: false,\n selector: 'mj-ps-studio-resource',\n template: `\n <mj-page-header-interior [Title]=\"activeLabel\" [Subtitle]=\"activeSubtitle\">\n </mj-page-header-interior>\n <mj-page-body-interior [Flex]=\"true\" [Padding]=\"false\">\n @if (isLoading) {\n <mj-loading text=\"Loading Studio…\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"ps-load-error\" data-testid=\"ps-load-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"ps-load-error-text\">\n <strong>Couldn't load {{ sectionTitle }}</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"retryLoad()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else {\n <div class=\"ps-studio-host\" [class.chat-open]=\"chatOpen\" data-testid=\"ps-studio-shell\">\n <aside class=\"ps-leftnav\">\n @for (group of groups; track group) {\n @if (group) { <div class=\"ps-nav-group\">{{ group }}</div> }\n @for (item of itemsForGroup(group); track item.key) {\n <button class=\"ps-nav-item\" [class.active]=\"activeSection === item.key\"\n [attr.data-testid]=\"'ps-nav-' + item.key\" (click)=\"selectSection(item.key)\">\n <i [class]=\"item.icon\"></i> <span>{{ item.label }}</span>\n </button>\n }\n }\n </aside>\n\n <section class=\"ps-content\" [class.fill]=\"activeSection === 'pipelines'\" [attr.data-testid]=\"'ps-panel-' + activeSection\">\n @switch (activeSection) {\n @case ('home') { <ps-home [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (navigate)=\"mapNavigate($event)\" (askAgent)=\"onAskAgent($event)\"></ps-home> }\n @case ('pipelines') { <ps-pipelines [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (askAgent)=\"onAskAgent($event)\"></ps-pipelines> }\n @case ('catalog') { <ps-catalog [engine]=\"engine\" (askAgent)=\"onAskAgent($event)\"></ps-catalog> }\n @case ('experiments') { <ps-experiments [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\"></ps-experiments> }\n @case ('compare') { <ps-compare [engine]=\"engine\"></ps-compare> }\n }\n </section>\n\n @if (chatOpen) {\n <aside class=\"ps-copilot\" data-testid=\"ps-studio-copilot\">\n <div class=\"ps-copilot-head\">\n <div class=\"ps-copilot-title\"><i class=\"fa-solid fa-robot\"></i> Model Dev Agent</div>\n <button class=\"ps-copilot-close\" (click)=\"closeChat()\" aria-label=\"Close agent chat\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n <div class=\"ps-copilot-body\">\n @if (currentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\" [environmentId]=\"chatEnvironmentId\" [currentUser]=\"currentUser\"\n [conversation]=\"chatConversation\" [conversationId]=\"chatConversationId\" [isNewConversation]=\"chatIsNewConversation\"\n [suppressNewConversationEmptyState]=\"true\" [allowMentions]=\"false\" [overlayMode]=\"true\"\n [showExportButton]=\"false\" [showShareButton]=\"false\" [showArtifactIndicator]=\"false\"\n [showAgentPicker]=\"false\" [showAgentModePicker]=\"false\"\n [defaultAgentId]=\"modelDevAgentId\" [pendingMessage]=\"pendingPrompt\"\n [applicationScope]=\"'Application'\" [applicationId]=\"applicationId\" [appContext]=\"chatAppContext\"\n (conversationCreated)=\"onChatConversationCreated($event)\"\n (pendingMessageConsumed)=\"onChatPendingMessageConsumed()\">\n </mj-conversation-chat-area>\n } @else { <div class=\"ps-copilot-empty\"><mj-loading text=\"Connecting…\" size=\"small\"></mj-loading></div> }\n </div>\n </aside>\n }\n </div>\n }\n </mj-page-body-interior>\n `,\n styles: [\n `\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; }\n .ps-leftnav { width: 210px; flex: none; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 10px 8px; display: flex; flex-direction: column; gap: 2px; }\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 12px 10px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n .ps-content { flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n /* Fill mode (pipelines): the section stops page-scrolling so the panel's inner\n columns (canvas / inspector) can each own their scrollbar. */\n .ps-content.fill { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }\n .ps-content.fill > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .ps-copilot { width: 420px; max-width: 42vw; flex: none; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n .ps-load-error { display: flex; align-items: center; gap: 14px; max-width: 620px; margin: 32px auto; padding: 18px 20px; border: 1px solid var(--mj-status-error-border); background: var(--mj-status-error-bg); border-radius: var(--mj-radius-lg); }\n .ps-load-error > i { font-size: 24px; color: var(--mj-status-error); }\n .ps-load-error-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }\n .ps-load-error-text strong { color: var(--mj-text-primary); }\n .ps-load-error-detail { color: var(--mj-text-secondary); font-size: var(--mj-text-sm); word-break: break-word; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PSStudioResourceComponent extends PSResourceBase {\n protected readonly SectionKey = 'studio';\n protected readonly SectionLabel = 'Studio';\n protected readonly SectionIcon = 'fa-solid fa-flask-vial';\n\n private readonly cdrLocal = inject(ChangeDetectorRef);\n\n /** The active workbench section (which panel renders). Round-trips through the `section` query param. */\n public activeSection: PSPanelKey = 'home';\n public readonly sections: readonly PSSection[] = STUDIO_SECTIONS;\n\n // ── docked Model Dev Agent copilot ───────────────────────────────\n public chatOpen = false;\n public pendingPrompt: string | null = null;\n private _modelDevAgentId: string | null = null;\n /** Conversation lifecycle (see {@link onChatConversationCreated}) — without it the first send no-ops. */\n public chatConversation: MJConversationEntity | null = null;\n public chatConversationId: string | null = null;\n public chatIsNewConversation = true;\n\n override ngOnInit(): void {\n super.ngOnInit();\n const initial = this.GetQueryParams()['section'] as PSPanelKey | undefined;\n if (initial && hasSection(this.sections, initial)) this.activeSection = initial;\n }\n\n /** React to deep-link / back-forward `section` changes after the initial mount. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const next = params['section'] as PSPanelKey | undefined;\n if (next && next !== this.activeSection && hasSection(this.sections, next)) {\n this.activeSection = next;\n this.cdrLocal.detectChanges();\n }\n }\n\n /** Deep agent context for the Studio door (build/run workbench counts + active section). */\n protected override extraAgentContext(): Record<string, unknown> {\n return buildStudioAgentContext({\n ActiveSection: this.activeSection,\n ActiveSectionLabel: this.activeLabel,\n SectionLabels: this.sections.map((s) => s.label),\n PublishedModelCount: this.engine.PublishedModels.length,\n RunningSessionCount: this.engine.RunningSessions.length,\n PipelineCount: this.engine.Pipelines.length,\n AlgorithmCount: this.engine.Algorithms.length,\n ExperimentCount: this.engine.Experiments.length,\n TrainingRunCount: this.engine.TrainingRuns.length,\n ChatOpen: this.chatOpen,\n });\n }\n\n /**\n * 🔒 Read/navigate-only agent tools for the Studio door: switch the active section, or open the docked\n * Model Dev Agent co-pilot. NO build/train/publish tool is exposed — model creation runs through the\n * co-pilot conversation (the approve-gated builder), never a fire-and-forget agent tool.\n */\n protected override registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'SwitchStudioSection',\n Description:\n 'Switch the Studio workbench to a section. Pass the section key or label (see SectionLabels): Overview, Training Pipelines, Algorithm Catalog, Experiments, or Compare Runs.',\n ParameterSchema: { type: 'object', properties: { section: { type: 'string', description: 'The section key or label to switch to' } } },\n Handler: async (params: Record<string, unknown>) => {\n const check = validateStringParam(params['section'], 'section');\n if (!check.ok) return check.result;\n const candidates = this.sections.map((s) => ({ ID: s.key, Name: s.label }));\n const match = resolvePSRecord(check.value, candidates);\n if (!match) return { Success: false, ErrorMessage: buildPSNotFoundError(check.value, candidates, 'section') };\n this.selectSection(match.ID as PSPanelKey);\n return { Success: true, Data: { activeSection: match.Name } };\n },\n },\n {\n Name: 'OpenModelDevAgentCopilot',\n Description:\n 'Open the docked Model Development Agent co-pilot in the Studio (does not send a message — the user drives the conversation). Use when the user wants to design/build a new prediction.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n this.openCopilot();\n return { Success: true, Data: { chatOpen: true } };\n },\n },\n ]);\n }\n\n // ── left-nav ─────────────────────────────────────────────────────\n public get groups(): string[] { return sectionGroups(this.sections); }\n public itemsForGroup(group: string): PSSection[] { return sectionsInGroup(this.sections, group); }\n public get activeLabel(): string { return sectionLabel(this.sections, this.activeSection); }\n\n /** Section-specific subtitle for the interior header (so every section doesn't repeat one generic line). */\n public get activeSubtitle(): string {\n const map: Record<string, string> = {\n home: 'Start a new prediction from your data, a template, or the agent.',\n pipelines: 'Assemble features and train from the algorithm catalog.',\n catalog: 'Browse algorithms with a fit guide for your use case.',\n experiments: 'Run and track model experiments.',\n compare: 'Compare runs on the honest holdout score.',\n };\n return map[this.activeSection] ?? '';\n }\n\n public selectSection(key: PSPanelKey): void {\n if (this.activeSection === key) return;\n this.activeSection = key;\n this.UpdateQueryParams({ section: key });\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** The Overview panel's in-app navigation: switch section in-place, or cross to the Models door. */\n public mapNavigate(key: PSPanelKey): void {\n const target = routeHomeNavigate(key);\n if (target.kind === 'section') {\n this.selectSection(target.key);\n } else if (target.kind === 'app') {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, target.navLabel, { section: target.section });\n }\n }\n\n // ── copilot ──────────────────────────────────────────────────────\n public get currentUser(): UserInfo | null { return this.ProviderToUse.CurrentUser ?? null; }\n\n public get chatEnvironmentId(): string {\n return (this.Data?.Configuration?.['environmentId'] as string | undefined) || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n public get applicationId(): string | null { return (this.Data?.Configuration?.['applicationId'] as string | undefined) ?? null; }\n public get modelDevAgentId(): string | null { return this._modelDevAgentId; }\n public get chatAppContext(): Record<string, unknown> {\n return { app: 'Predictive Studio', section: this.activeSection, publishedModels: this.engine.Models.filter((m) => m.Status === 'Published').length };\n }\n\n public onAskAgent(starterPrompt: string): void {\n this.pendingPrompt = starterPrompt;\n this.chatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** Open the docked co-pilot (clean chat) — used by the read-only `OpenModelDevAgentCopilot` agent tool. */\n public openCopilot(): void {\n this.pendingPrompt = null;\n this.chatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n public closeChat(): void {\n this.chatOpen = false;\n this.pendingPrompt = null;\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** Chat-area created its backing conversation on the first send — capture it + leave new-mode so the thread renders. */\n public onChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n this.pendingPrompt = event.pendingMessage ?? null;\n this.chatConversation = event.conversation;\n this.chatConversationId = event.conversation.ID;\n this.chatIsNewConversation = false;\n this.cdrLocal.detectChanges();\n }\n\n /** Chat-area delivered the seeded prompt — clear the buffer so a re-render doesn't resend it. */\n public onChatPendingMessageConsumed(): void {\n this.pendingPrompt = null;\n this.cdrLocal.detectChanges();\n }\n\n private async ensureModelDevAgentResolved(): Promise<void> {\n if (this._modelDevAgentId) return;\n try {\n await AIEngineBase.Instance.Config(false, this.ProviderToUse.CurrentUser ?? undefined);\n this._modelDevAgentId =\n AIEngineBase.Instance.Agents?.find((a) => a.Name?.trim().toLowerCase() === MODEL_DEV_AGENT_NAME.toLowerCase())?.ID ?? null;\n if (!this._modelDevAgentId) LogError(`PSStudioResource: '${MODEL_DEV_AGENT_NAME}' not found — chat uses default-agent routing.`);\n this.cdrLocal.detectChanges();\n } catch (err) {\n LogError(`PSStudioResource.ensureModelDevAgentResolved: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n/** Tree-shaking prevention — called from the subpath module so the @RegisterClass survives bundling. */\nexport function LoadPSStudioResource(): void {\n // intentionally empty\n}\n"]}