@memberjunction/ng-dashboards 6.2.0-edge.5 → 6.2.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +15 -7
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +209 -57
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +28 -16
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +30 -6
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +15 -7
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/sensitive-fields.d.ts +9 -4
- package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -1
- package/dist/AI/components/vectors/sensitive-fields.js +39 -14
- package/dist/AI/components/vectors/sensitive-fields.js.map +1 -1
- package/dist/AI/components/vectors/vector-document-rules.d.ts +13 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-document-rules.js +14 -0
- package/dist/AI/components/vectors/vector-document-rules.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +34 -14
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +127 -50
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
- package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-store-selection.js +57 -0
- package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +236 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +374 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts +195 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js +2910 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js.map +1 -0
- package/dist/ChiefOfStaff/index.d.ts +3 -0
- package/dist/ChiefOfStaff/index.d.ts.map +1 -0
- package/dist/ChiefOfStaff/index.js +3 -0
- package/dist/ChiefOfStaff/index.js.map +1 -0
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +2 -1
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +23 -18
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +11 -10
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
- package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
- package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +24 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +146 -50
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
- package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
- package/dist/LoginStudio/login-studio-resource.component.d.ts +10 -2
- package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -1
- package/dist/LoginStudio/login-studio-resource.component.js +110 -77
- package/dist/LoginStudio/login-studio-resource.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +118 -65
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
- package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.js +256 -521
- package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +122 -249
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
- package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +335 -326
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js +51 -2
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
- package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +185 -103
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +22 -21
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +8 -2
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +71 -71
- package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
- package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
- package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
- package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
*
|
|
22
22
|
* Layer 1 alone would be a prompt-shaped guarantee, which is no guarantee at all.
|
|
23
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* What the vectors are for. A `'duplicate-detection'` document may embed a date of birth (see
|
|
26
|
+
* {@link BIRTH_DATE_FIELD_PATTERNS}); every other refusal applies to every purpose.
|
|
27
|
+
*/
|
|
28
|
+
export type VectorFieldPurpose = 'duplicate-detection' | 'other';
|
|
24
29
|
/**
|
|
25
30
|
* True when this field name must not be embedded.
|
|
26
31
|
*
|
|
@@ -28,11 +33,11 @@
|
|
|
28
33
|
* `authorname`, which contains `auth` — so it is refused. That is the trade accepted above:
|
|
29
34
|
* a visible false refusal the user can work around beats a silent disclosure they cannot.
|
|
30
35
|
*/
|
|
31
|
-
export declare function IsSensitiveFieldName(name: string | null | undefined): boolean;
|
|
32
|
-
/** Drops every
|
|
36
|
+
export declare function IsSensitiveFieldName(name: string | null | undefined, purpose?: VectorFieldPurpose): boolean;
|
|
37
|
+
/** Drops every field that must not be embedded for this purpose, preserving order. */
|
|
33
38
|
export declare function WithoutSensitiveFields<T extends {
|
|
34
39
|
Name: string;
|
|
35
|
-
}>(fields: ReadonlyArray<T
|
|
40
|
+
}>(fields: ReadonlyArray<T>, purpose?: VectorFieldPurpose): T[];
|
|
36
41
|
/**
|
|
37
42
|
* Sensitive field names referenced by a template's `{{Placeholder}}` tokens.
|
|
38
43
|
*
|
|
@@ -40,7 +45,7 @@ export declare function WithoutSensitiveFields<T extends {
|
|
|
40
45
|
* user can type a field the picker never offered. Returns the offending names so the
|
|
41
46
|
* refusal can say which ones, rather than only that something was wrong.
|
|
42
47
|
*/
|
|
43
|
-
export declare function SensitiveFieldsInTemplate(templateText: string | null | undefined): string[];
|
|
48
|
+
export declare function SensitiveFieldsInTemplate(templateText: string | null | undefined, purpose?: VectorFieldPurpose): string[];
|
|
44
49
|
/**
|
|
45
50
|
* Field names referenced by a template's `{{Placeholder}}` tokens, in order of appearance
|
|
46
51
|
* and including repeats.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sensitive-fields.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/sensitive-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;
|
|
1
|
+
{"version":3,"file":"sensitive-fields.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/sensitive-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA0DH;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,GAAG,OAAO,CAAC;AAkHjE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,GAAE,kBAA4B,GAAG,OAAO,CAkBpH;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,kBAA4B,GAAG,CAAC,EAAE,CAEvI;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,GAAE,kBAA4B,GAAG,MAAM,EAAE,CAQlI;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAa1F"}
|
|
@@ -49,19 +49,32 @@ const SENSITIVE_FIELD_PATTERNS = [
|
|
|
49
49
|
// and `OAuthToken` are still caught by `auth`.
|
|
50
50
|
'password', 'passwd', 'pwd', 'secret', 'apikey', 'accesskey', 'privatekey',
|
|
51
51
|
'accesstoken', 'refreshtoken', 'apitoken', 'bearertoken', 'sessiontoken',
|
|
52
|
-
'salt', 'hash', 'credential', 'auth', 'connectionstring',
|
|
52
|
+
'salt', 'hash', 'credential', 'auth', 'connectionstring', 'passcode', 'biometric',
|
|
53
53
|
// Government and tax identifiers. `tin` is deliberately absent: `taxid` already covers
|
|
54
54
|
// the concept, while `t-i-n` is a substring of ordinary English (Ra-tin-g, Marke-tin-g,
|
|
55
55
|
// Set-tin-gs, Mee-tin-g) and matched 43 MJ columns, none of them a tax identifier.
|
|
56
|
-
// A whole-word `tin` is in SENSITIVE_FIELD_WHOLE_WORD_PATTERNS below.
|
|
56
|
+
// A whole-word `tin` is in SENSITIVE_FIELD_WHOLE_WORD_PATTERNS below. `pin` and `otp`
|
|
57
|
+
// are whole-word for the same reason; `passcode` and `biometric` are long enough to be
|
|
58
|
+
// safe as substrings.
|
|
57
59
|
'socialsec', 'nationalinsurance', 'taxid', 'passport', 'driverlicense', 'driverslicense',
|
|
58
60
|
// Financial
|
|
59
61
|
'bank', 'routing', 'iban', 'swift', 'accountnumber', 'cardnumber', 'cardnum', 'cvv',
|
|
60
62
|
'cvc', 'creditcard', 'salary', 'compensation', 'income',
|
|
61
63
|
// Protected characteristics and other special-category data
|
|
62
64
|
'ethnic', 'religion', 'political', 'sexualorientation', 'disability',
|
|
63
|
-
'healthcondition', 'diagnosis', 'medicalrecord',
|
|
65
|
+
'healthcondition', 'diagnosis', 'medicalrecord',
|
|
64
66
|
];
|
|
67
|
+
/**
|
|
68
|
+
* Date of birth: refused like the patterns above, except in a document built for duplicate
|
|
69
|
+
* detection. Telling two records for the same person apart from two people who share a name
|
|
70
|
+
* is what a birth date is for, and without it duplicate detection on people loses most of its
|
|
71
|
+
* precision. Every other purpose (search, classification) still refuses it.
|
|
72
|
+
*
|
|
73
|
+
* `dateofbirth` and `birthdate` match anywhere in the name; `dob` must begin a word, for the
|
|
74
|
+
* reason given at {@link SENSITIVE_FIELD_WORD_PATTERNS}.
|
|
75
|
+
*/
|
|
76
|
+
const BIRTH_DATE_FIELD_PATTERNS = ['dateofbirth', 'birthdate'];
|
|
77
|
+
const BIRTH_DATE_FIELD_WORD_PATTERNS = ['dob'];
|
|
65
78
|
/**
|
|
66
79
|
* Patterns that must BEGIN A WORD in the field name rather than appear anywhere in it.
|
|
67
80
|
*
|
|
@@ -74,13 +87,14 @@ const SENSITIVE_FIELD_PATTERNS = [
|
|
|
74
87
|
*
|
|
75
88
|
* Anchoring loses no true positives, because all three are whole words wherever they are
|
|
76
89
|
* meant: `ssn`, `employee_ssn`, `EmployeeSSN`, `SSNumber`, `dob`, `DOB`, `race`,
|
|
77
|
-
* `EmployeeRace`. (`
|
|
90
|
+
* `EmployeeRace`. (`dob` itself lives in {@link BIRTH_DATE_FIELD_WORD_PATTERNS}, because duplicate
|
|
91
|
+
* detection may use it.)
|
|
78
92
|
*
|
|
79
93
|
* `idtoken` is here for the same reason: as a substring it sits inside `Pa-idToken-s` and
|
|
80
94
|
* `Val-idToken-Count`, which are counts, while `IdToken`, `IDToken` and `id_token` all begin
|
|
81
95
|
* a word.
|
|
82
96
|
*/
|
|
83
|
-
const SENSITIVE_FIELD_WORD_PATTERNS = ['ssn', '
|
|
97
|
+
const SENSITIVE_FIELD_WORD_PATTERNS = ['ssn', 'race', 'idtoken'];
|
|
84
98
|
/**
|
|
85
99
|
* Patterns that must be a WHOLE WORD: begin a word and end at the end of the name or where
|
|
86
100
|
* the next word begins.
|
|
@@ -88,8 +102,12 @@ const SENSITIVE_FIELD_WORD_PATTERNS = ['ssn', 'dob', 'race', 'idtoken'];
|
|
|
88
102
|
* `tin` (tax identification number) is too short even for a word start: `Tint`, `TinyInt`
|
|
89
103
|
* and `Tinker` all begin with it. As a word of its own it means one thing: `TIN`,
|
|
90
104
|
* `VendorTIN`, `vendor_tin`, `TINNumber`.
|
|
105
|
+
*
|
|
106
|
+
* `pin` (a personal identification number) and `otp` (a one-time password) are whole words
|
|
107
|
+
* for the same reason: `Shipping`, `Mapping`, `Pinned` and `Hotpot` contain them. `UserPin`,
|
|
108
|
+
* `PIN` and `OTPCode` are refused; `Pinned` and `PinnedAt` are not.
|
|
91
109
|
*/
|
|
92
|
-
const SENSITIVE_FIELD_WHOLE_WORD_PATTERNS = ['tin'];
|
|
110
|
+
const SENSITIVE_FIELD_WHOLE_WORD_PATTERNS = ['tin', 'pin', 'otp'];
|
|
93
111
|
/** Characters dropped by normalisation. The two spellings must stay in step. */
|
|
94
112
|
const SEPARATORS_GLOBAL = /[\s_\-.]/g;
|
|
95
113
|
const SEPARATOR = /[\s_\-.]/;
|
|
@@ -169,7 +187,7 @@ function matchesWholeWord(normalized, wordStarts, pattern) {
|
|
|
169
187
|
* `authorname`, which contains `auth` — so it is refused. That is the trade accepted above:
|
|
170
188
|
* a visible false refusal the user can work around beats a silent disclosure they cannot.
|
|
171
189
|
*/
|
|
172
|
-
export function IsSensitiveFieldName(name) {
|
|
190
|
+
export function IsSensitiveFieldName(name, purpose = 'other') {
|
|
173
191
|
if (!name) {
|
|
174
192
|
return false;
|
|
175
193
|
}
|
|
@@ -178,12 +196,19 @@ export function IsSensitiveFieldName(name) {
|
|
|
178
196
|
return true;
|
|
179
197
|
}
|
|
180
198
|
const wordStarts = wordStartOffsets(name);
|
|
181
|
-
|
|
182
|
-
|| SENSITIVE_FIELD_WHOLE_WORD_PATTERNS.some((pattern) => matchesWholeWord(normalized, wordStarts, pattern))
|
|
199
|
+
if (SENSITIVE_FIELD_WORD_PATTERNS.some((pattern) => matchesAtWordStart(normalized, wordStarts, pattern))
|
|
200
|
+
|| SENSITIVE_FIELD_WHOLE_WORD_PATTERNS.some((pattern) => matchesWholeWord(normalized, wordStarts, pattern))) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
if (purpose === 'duplicate-detection') {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return BIRTH_DATE_FIELD_PATTERNS.some((pattern) => normalized.includes(pattern))
|
|
207
|
+
|| BIRTH_DATE_FIELD_WORD_PATTERNS.some((pattern) => matchesAtWordStart(normalized, wordStarts, pattern));
|
|
183
208
|
}
|
|
184
|
-
/** Drops every
|
|
185
|
-
export function WithoutSensitiveFields(fields) {
|
|
186
|
-
return fields.filter((f) => !IsSensitiveFieldName(f.Name));
|
|
209
|
+
/** Drops every field that must not be embedded for this purpose, preserving order. */
|
|
210
|
+
export function WithoutSensitiveFields(fields, purpose = 'other') {
|
|
211
|
+
return fields.filter((f) => !IsSensitiveFieldName(f.Name, purpose));
|
|
187
212
|
}
|
|
188
213
|
/**
|
|
189
214
|
* Sensitive field names referenced by a template's `{{Placeholder}}` tokens.
|
|
@@ -192,10 +217,10 @@ export function WithoutSensitiveFields(fields) {
|
|
|
192
217
|
* user can type a field the picker never offered. Returns the offending names so the
|
|
193
218
|
* refusal can say which ones, rather than only that something was wrong.
|
|
194
219
|
*/
|
|
195
|
-
export function SensitiveFieldsInTemplate(templateText) {
|
|
220
|
+
export function SensitiveFieldsInTemplate(templateText, purpose = 'other') {
|
|
196
221
|
const found = new Set();
|
|
197
222
|
for (const token of TemplatePlaceholderNames(templateText)) {
|
|
198
|
-
if (IsSensitiveFieldName(token)) {
|
|
223
|
+
if (IsSensitiveFieldName(token, purpose)) {
|
|
199
224
|
found.add(token);
|
|
200
225
|
}
|
|
201
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sensitive-fields.js","sourceRoot":"","sources":["../../../../src/AI/components/vectors/sensitive-fields.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Fields that must never be embedded into a vector index.\n *\n * Vectorizing a column copies its values into a third-party vector database, where they\n * live outside the entity permissions that normally guard them and are retrievable by\n * nearest-neighbour search rather than by an authorized query. For a password hash, a\n * national insurance or social security number, a bank account or a salary, that is not a\n * feature with a caveat — it is a disclosure.\n *\n * The field picker's suggestions come from a language model, which has no notion of which\n * columns are sensitive and will happily propose `PasswordHash` if the use case seems to\n * call for identity matching. So the refusal cannot live in the prompt: it has to be a\n * property of the code on both sides of the model.\n *\n * Two layers, deliberately:\n *\n * 1. The model never sees these fields, on the entity or on its related entities, so it\n * cannot suggest them.\n * 2. The saved template is re-checked, because the template is hand-editable after the\n * model returns and a user can type a field name the picker never offered.\n *\n * Layer 1 alone would be a prompt-shaped guarantee, which is no guarantee at all.\n */\n\n/**\n * Substrings that mark a column as unembeddable, matched case-insensitively against the\n * field name with separators ignored — so `password_hash`, `PasswordHash` and `PASSWORD`\n * all match the same rule.\n *\n * These are substrings rather than whole names on purpose. Real schemas spell the same\n * concept a dozen ways (`SSNumber`, `employee_ssn`, `ClientSecretEncrypted`), and the cost\n * of the two kinds of mistake is not symmetric: refusing a harmless column produces a\n * visible, correctable annoyance, while embedding a sensitive one is silent and, once\n * written to the index, not fully reversible.\n *\n * That asymmetry justifies over-refusing a column that RESEMBLES the concept — `AuthorName`\n * contains `auth`, and `auth` really is the prefix of authentication, so the resemblance\n * carries some signal and refusing it is a trade we accept. It does not justify a match\n * with no semantic relationship at all. `Rating` is not refused because it looks like a tax\n * identifier; it is refused because the letters `t-i-n` happen to sit inside an unrelated\n * English word, which trades away a usable column for no signal whatsoever. Patterns of\n * that shape belong in {@link SENSITIVE_FIELD_WORD_PATTERNS} or nowhere — see\n * `vector-sensitive-fields.test.ts`, which pins the refusal count over MJ's own field names\n * so that re-adding one is a red test rather than a quiet doubling of the blast radius.\n */\nconst SENSITIVE_FIELD_PATTERNS: ReadonlyArray<string> = [\n // Credentials and secrets. `token` is NOT here on its own: MJ alone has 36 columns that\n // are token *counts* (`ContextWindowMaxTokens`, `InputTokenLimit`, `FirstTokenTime`),\n // and a count is not a secret. The compounds below keep the credentials; `AuthToken`\n // and `OAuthToken` are still caught by `auth`.\n 'password', 'passwd', 'pwd', 'secret', 'apikey', 'accesskey', 'privatekey',\n 'accesstoken', 'refreshtoken', 'apitoken', 'bearertoken', 'sessiontoken',\n 'salt', 'hash', 'credential', 'auth', 'connectionstring',\n // Government and tax identifiers. `tin` is deliberately absent: `taxid` already covers\n // the concept, while `t-i-n` is a substring of ordinary English (Ra-tin-g, Marke-tin-g,\n // Set-tin-gs, Mee-tin-g) and matched 43 MJ columns, none of them a tax identifier.\n // A whole-word `tin` is in SENSITIVE_FIELD_WHOLE_WORD_PATTERNS below.\n 'socialsec', 'nationalinsurance', 'taxid', 'passport', 'driverlicense', 'driverslicense',\n // Financial\n 'bank', 'routing', 'iban', 'swift', 'accountnumber', 'cardnumber', 'cardnum', 'cvv',\n 'cvc', 'creditcard', 'salary', 'compensation', 'income',\n // Protected characteristics and other special-category data\n 'ethnic', 'religion', 'political', 'sexualorientation', 'disability',\n 'healthcondition', 'diagnosis', 'medicalrecord', 'dateofbirth', 'birthdate',\n];\n\n/**\n * Patterns that must BEGIN A WORD in the field name rather than appear anywhere in it.\n *\n * These three are short enough that as bare substrings they collide with unrelated words\n * and catch nothing real: `ssn` is inside `cla-ssn-ame` (every `*ClassName` column in MJ),\n * `dob` is inside `recor-dob-ject`, `race` is inside `StackT-race` and `T-race-ID`. Each of\n * those matches carries zero information about sensitivity, and because the template check\n * throws, a user who needs `{{Rating}}` or `{{StackTrace}}` has no workaround at all — it\n * is a feature they cannot use, not an annoyance they route around.\n *\n * Anchoring loses no true positives, because all three are whole words wherever they are\n * meant: `ssn`, `employee_ssn`, `EmployeeSSN`, `SSNumber`, `dob`, `DOB`, `race`,\n * `EmployeeRace`. (`date_of_birth` and `DateOfBirth` are covered by `dateofbirth` above.)\n *\n * `idtoken` is here for the same reason: as a substring it sits inside `Pa-idToken-s` and\n * `Val-idToken-Count`, which are counts, while `IdToken`, `IDToken` and `id_token` all begin\n * a word.\n */\nconst SENSITIVE_FIELD_WORD_PATTERNS: ReadonlyArray<string> = ['ssn', 'dob', 'race', 'idtoken'];\n\n/**\n * Patterns that must be a WHOLE WORD: begin a word and end at the end of the name or where\n * the next word begins.\n *\n * `tin` (tax identification number) is too short even for a word start: `Tint`, `TinyInt`\n * and `Tinker` all begin with it. As a word of its own it means one thing: `TIN`,\n * `VendorTIN`, `vendor_tin`, `TINNumber`.\n */\nconst SENSITIVE_FIELD_WHOLE_WORD_PATTERNS: ReadonlyArray<string> = ['tin'];\n\n/** Characters dropped by normalisation. The two spellings must stay in step. */\nconst SEPARATORS_GLOBAL = /[\\s_\\-.]/g;\nconst SEPARATOR = /[\\s_\\-.]/;\nconst LOWER_OR_DIGIT = /[a-z0-9]/;\nconst UPPER = /[A-Z]/;\nconst LOWER = /[a-z]/;\n\n/** Normalises a field name for matching: lower-cased, separators and spaces removed. */\nfunction normalizeFieldName(name: string): string {\n return name.toLowerCase().replace(SEPARATORS_GLOBAL, '');\n}\n\n/**\n * The offsets in `normalizeFieldName(name)` at which a word begins.\n *\n * Normalisation *removes* separators rather than replacing them, so by the time a pattern is\n * matched there is no separator left to anchor a `\\b` against — `employee_ssn` and\n * `className` are both one unbroken run of letters (`employeessn`, `classname`). A regex word\n * boundary would therefore match at offset 0 and nowhere else, which is not the boundary we\n * need. So the word starts are computed from the ORIGINAL spelling, where the evidence still\n * exists, and carried as offsets into the normalised string.\n *\n * A word starts at the beginning, after a separator, and at the two camelCase transitions:\n * lower-or-digit followed by upper (`employee|SSN`), and the tail of an acronym run that\n * begins a capitalised word (`SS|Number`, so `SSNumber` still matches `ssn`).\n */\nfunction wordStartOffsets(name: string): ReadonlySet<number> {\n const starts = new Set<number>();\n let offset = 0;\n let startsWord = true;\n for (let i = 0; i < name.length; i++) {\n const ch = name[i];\n if (SEPARATOR.test(ch)) {\n // Dropped by normalizeFieldName, so it consumes no offset — but whatever\n // survives next begins a word.\n startsWord = true;\n continue;\n }\n const prev = i > 0 ? name[i - 1] : '';\n const next = i + 1 < name.length ? name[i + 1] : '';\n if (UPPER.test(ch) && (LOWER_OR_DIGIT.test(prev) || (UPPER.test(prev) && LOWER.test(next)))) {\n startsWord = true;\n }\n if (startsWord) {\n starts.add(offset);\n }\n startsWord = false;\n offset++;\n }\n return starts;\n}\n\n/** True when `pattern` occurs in `normalized` starting at one of `wordStarts`. */\nfunction matchesAtWordStart(normalized: string, wordStarts: ReadonlySet<number>, pattern: string): boolean {\n let at = normalized.indexOf(pattern);\n while (at !== -1) {\n if (wordStarts.has(at)) {\n return true;\n }\n at = normalized.indexOf(pattern, at + 1);\n }\n return false;\n}\n\n/** True when `pattern` occurs in `normalized` as a whole word, by the offsets in `wordStarts`. */\nfunction matchesWholeWord(normalized: string, wordStarts: ReadonlySet<number>, pattern: string): boolean {\n let at = normalized.indexOf(pattern);\n while (at !== -1) {\n const end = at + pattern.length;\n if (wordStarts.has(at) && (end === normalized.length || wordStarts.has(end))) {\n return true;\n }\n at = normalized.indexOf(pattern, at + 1);\n }\n return false;\n}\n\n/**\n * True when this field name must not be embedded.\n *\n * Note `hash` and `auth` are deliberately broad. A column called `AuthorName` normalises to\n * `authorname`, which contains `auth` — so it is refused. That is the trade accepted above:\n * a visible false refusal the user can work around beats a silent disclosure they cannot.\n */\nexport function IsSensitiveFieldName(name: string | null | undefined): boolean {\n if (!name) {\n return false;\n }\n const normalized = normalizeFieldName(name);\n if (SENSITIVE_FIELD_PATTERNS.some((pattern) => normalized.includes(pattern))) {\n return true;\n }\n const wordStarts = wordStartOffsets(name);\n return SENSITIVE_FIELD_WORD_PATTERNS.some((pattern) => matchesAtWordStart(normalized, wordStarts, pattern))\n || SENSITIVE_FIELD_WHOLE_WORD_PATTERNS.some((pattern) => matchesWholeWord(normalized, wordStarts, pattern));\n}\n\n/** Drops every sensitive field from a list, preserving order. */\nexport function WithoutSensitiveFields<T extends { Name: string }>(fields: ReadonlyArray<T>): T[] {\n return fields.filter((f) => !IsSensitiveFieldName(f.Name));\n}\n\n/**\n * Sensitive field names referenced by a template's `{{Placeholder}}` tokens.\n *\n * This is the second layer. The template is hand-editable after the model returns, so a\n * user can type a field the picker never offered. Returns the offending names so the\n * refusal can say which ones, rather than only that something was wrong.\n */\nexport function SensitiveFieldsInTemplate(templateText: string | null | undefined): string[] {\n const found = new Set<string>();\n for (const token of TemplatePlaceholderNames(templateText)) {\n if (IsSensitiveFieldName(token)) {\n found.add(token);\n }\n }\n return [...found].sort();\n}\n\n/**\n * Field names referenced by a template's `{{Placeholder}}` tokens, in order of appearance\n * and including repeats.\n *\n * Exported so the field-count cap in `vector-document-rules.ts` parses placeholders the same\n * way this refusal does. Two parsers that drift apart would mean a template that satisfies\n * one guard and evades the other.\n */\nexport function TemplatePlaceholderNames(templateText: string | null | undefined): string[] {\n if (!templateText) {\n return [];\n }\n // Nunjucks/Handlebars-style placeholders. The field name is the first identifier\n // inside the braces; filters and whitespace after it are ignored.\n const placeholder = /\\{\\{\\s*([A-Za-z0-9_.\\-]+)/g;\n const names: string[] = [];\n let match: RegExpExecArray | null;\n while ((match = placeholder.exec(templateText)) !== null) {\n names.push(match[1]);\n }\n return names;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sensitive-fields.js","sourceRoot":"","sources":["../../../../src/AI/components/vectors/sensitive-fields.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Fields that must never be embedded into a vector index.\n *\n * Vectorizing a column copies its values into a third-party vector database, where they\n * live outside the entity permissions that normally guard them and are retrievable by\n * nearest-neighbour search rather than by an authorized query. For a password hash, a\n * national insurance or social security number, a bank account or a salary, that is not a\n * feature with a caveat — it is a disclosure.\n *\n * The field picker's suggestions come from a language model, which has no notion of which\n * columns are sensitive and will happily propose `PasswordHash` if the use case seems to\n * call for identity matching. So the refusal cannot live in the prompt: it has to be a\n * property of the code on both sides of the model.\n *\n * Two layers, deliberately:\n *\n * 1. The model never sees these fields, on the entity or on its related entities, so it\n * cannot suggest them.\n * 2. The saved template is re-checked, because the template is hand-editable after the\n * model returns and a user can type a field name the picker never offered.\n *\n * Layer 1 alone would be a prompt-shaped guarantee, which is no guarantee at all.\n */\n\n/**\n * Substrings that mark a column as unembeddable, matched case-insensitively against the\n * field name with separators ignored — so `password_hash`, `PasswordHash` and `PASSWORD`\n * all match the same rule.\n *\n * These are substrings rather than whole names on purpose. Real schemas spell the same\n * concept a dozen ways (`SSNumber`, `employee_ssn`, `ClientSecretEncrypted`), and the cost\n * of the two kinds of mistake is not symmetric: refusing a harmless column produces a\n * visible, correctable annoyance, while embedding a sensitive one is silent and, once\n * written to the index, not fully reversible.\n *\n * That asymmetry justifies over-refusing a column that RESEMBLES the concept — `AuthorName`\n * contains `auth`, and `auth` really is the prefix of authentication, so the resemblance\n * carries some signal and refusing it is a trade we accept. It does not justify a match\n * with no semantic relationship at all. `Rating` is not refused because it looks like a tax\n * identifier; it is refused because the letters `t-i-n` happen to sit inside an unrelated\n * English word, which trades away a usable column for no signal whatsoever. Patterns of\n * that shape belong in {@link SENSITIVE_FIELD_WORD_PATTERNS} or nowhere — see\n * `vector-sensitive-fields.test.ts`, which pins the refusal count over MJ's own field names\n * so that re-adding one is a red test rather than a quiet doubling of the blast radius.\n */\nconst SENSITIVE_FIELD_PATTERNS: ReadonlyArray<string> = [\n // Credentials and secrets. `token` is NOT here on its own: MJ alone has 36 columns that\n // are token *counts* (`ContextWindowMaxTokens`, `InputTokenLimit`, `FirstTokenTime`),\n // and a count is not a secret. The compounds below keep the credentials; `AuthToken`\n // and `OAuthToken` are still caught by `auth`.\n 'password', 'passwd', 'pwd', 'secret', 'apikey', 'accesskey', 'privatekey',\n 'accesstoken', 'refreshtoken', 'apitoken', 'bearertoken', 'sessiontoken',\n 'salt', 'hash', 'credential', 'auth', 'connectionstring', 'passcode', 'biometric',\n // Government and tax identifiers. `tin` is deliberately absent: `taxid` already covers\n // the concept, while `t-i-n` is a substring of ordinary English (Ra-tin-g, Marke-tin-g,\n // Set-tin-gs, Mee-tin-g) and matched 43 MJ columns, none of them a tax identifier.\n // A whole-word `tin` is in SENSITIVE_FIELD_WHOLE_WORD_PATTERNS below. `pin` and `otp`\n // are whole-word for the same reason; `passcode` and `biometric` are long enough to be\n // safe as substrings.\n 'socialsec', 'nationalinsurance', 'taxid', 'passport', 'driverlicense', 'driverslicense',\n // Financial\n 'bank', 'routing', 'iban', 'swift', 'accountnumber', 'cardnumber', 'cardnum', 'cvv',\n 'cvc', 'creditcard', 'salary', 'compensation', 'income',\n // Protected characteristics and other special-category data\n 'ethnic', 'religion', 'political', 'sexualorientation', 'disability',\n 'healthcondition', 'diagnosis', 'medicalrecord',\n];\n\n/**\n * Date of birth: refused like the patterns above, except in a document built for duplicate\n * detection. Telling two records for the same person apart from two people who share a name\n * is what a birth date is for, and without it duplicate detection on people loses most of its\n * precision. Every other purpose (search, classification) still refuses it.\n *\n * `dateofbirth` and `birthdate` match anywhere in the name; `dob` must begin a word, for the\n * reason given at {@link SENSITIVE_FIELD_WORD_PATTERNS}.\n */\nconst BIRTH_DATE_FIELD_PATTERNS: ReadonlyArray<string> = ['dateofbirth', 'birthdate'];\nconst BIRTH_DATE_FIELD_WORD_PATTERNS: ReadonlyArray<string> = ['dob'];\n\n/**\n * What the vectors are for. A `'duplicate-detection'` document may embed a date of birth (see\n * {@link BIRTH_DATE_FIELD_PATTERNS}); every other refusal applies to every purpose.\n */\nexport type VectorFieldPurpose = 'duplicate-detection' | 'other';\n\n/**\n * Patterns that must BEGIN A WORD in the field name rather than appear anywhere in it.\n *\n * These three are short enough that as bare substrings they collide with unrelated words\n * and catch nothing real: `ssn` is inside `cla-ssn-ame` (every `*ClassName` column in MJ),\n * `dob` is inside `recor-dob-ject`, `race` is inside `StackT-race` and `T-race-ID`. Each of\n * those matches carries zero information about sensitivity, and because the template check\n * throws, a user who needs `{{Rating}}` or `{{StackTrace}}` has no workaround at all — it\n * is a feature they cannot use, not an annoyance they route around.\n *\n * Anchoring loses no true positives, because all three are whole words wherever they are\n * meant: `ssn`, `employee_ssn`, `EmployeeSSN`, `SSNumber`, `dob`, `DOB`, `race`,\n * `EmployeeRace`. (`dob` itself lives in {@link BIRTH_DATE_FIELD_WORD_PATTERNS}, because duplicate\n * detection may use it.)\n *\n * `idtoken` is here for the same reason: as a substring it sits inside `Pa-idToken-s` and\n * `Val-idToken-Count`, which are counts, while `IdToken`, `IDToken` and `id_token` all begin\n * a word.\n */\nconst SENSITIVE_FIELD_WORD_PATTERNS: ReadonlyArray<string> = ['ssn', 'race', 'idtoken'];\n\n/**\n * Patterns that must be a WHOLE WORD: begin a word and end at the end of the name or where\n * the next word begins.\n *\n * `tin` (tax identification number) is too short even for a word start: `Tint`, `TinyInt`\n * and `Tinker` all begin with it. As a word of its own it means one thing: `TIN`,\n * `VendorTIN`, `vendor_tin`, `TINNumber`.\n *\n * `pin` (a personal identification number) and `otp` (a one-time password) are whole words\n * for the same reason: `Shipping`, `Mapping`, `Pinned` and `Hotpot` contain them. `UserPin`,\n * `PIN` and `OTPCode` are refused; `Pinned` and `PinnedAt` are not.\n */\nconst SENSITIVE_FIELD_WHOLE_WORD_PATTERNS: ReadonlyArray<string> = ['tin', 'pin', 'otp'];\n\n/** Characters dropped by normalisation. The two spellings must stay in step. */\nconst SEPARATORS_GLOBAL = /[\\s_\\-.]/g;\nconst SEPARATOR = /[\\s_\\-.]/;\nconst LOWER_OR_DIGIT = /[a-z0-9]/;\nconst UPPER = /[A-Z]/;\nconst LOWER = /[a-z]/;\n\n/** Normalises a field name for matching: lower-cased, separators and spaces removed. */\nfunction normalizeFieldName(name: string): string {\n return name.toLowerCase().replace(SEPARATORS_GLOBAL, '');\n}\n\n/**\n * The offsets in `normalizeFieldName(name)` at which a word begins.\n *\n * Normalisation *removes* separators rather than replacing them, so by the time a pattern is\n * matched there is no separator left to anchor a `\\b` against — `employee_ssn` and\n * `className` are both one unbroken run of letters (`employeessn`, `classname`). A regex word\n * boundary would therefore match at offset 0 and nowhere else, which is not the boundary we\n * need. So the word starts are computed from the ORIGINAL spelling, where the evidence still\n * exists, and carried as offsets into the normalised string.\n *\n * A word starts at the beginning, after a separator, and at the two camelCase transitions:\n * lower-or-digit followed by upper (`employee|SSN`), and the tail of an acronym run that\n * begins a capitalised word (`SS|Number`, so `SSNumber` still matches `ssn`).\n */\nfunction wordStartOffsets(name: string): ReadonlySet<number> {\n const starts = new Set<number>();\n let offset = 0;\n let startsWord = true;\n for (let i = 0; i < name.length; i++) {\n const ch = name[i];\n if (SEPARATOR.test(ch)) {\n // Dropped by normalizeFieldName, so it consumes no offset — but whatever\n // survives next begins a word.\n startsWord = true;\n continue;\n }\n const prev = i > 0 ? name[i - 1] : '';\n const next = i + 1 < name.length ? name[i + 1] : '';\n if (UPPER.test(ch) && (LOWER_OR_DIGIT.test(prev) || (UPPER.test(prev) && LOWER.test(next)))) {\n startsWord = true;\n }\n if (startsWord) {\n starts.add(offset);\n }\n startsWord = false;\n offset++;\n }\n return starts;\n}\n\n/** True when `pattern` occurs in `normalized` starting at one of `wordStarts`. */\nfunction matchesAtWordStart(normalized: string, wordStarts: ReadonlySet<number>, pattern: string): boolean {\n let at = normalized.indexOf(pattern);\n while (at !== -1) {\n if (wordStarts.has(at)) {\n return true;\n }\n at = normalized.indexOf(pattern, at + 1);\n }\n return false;\n}\n\n/** True when `pattern` occurs in `normalized` as a whole word, by the offsets in `wordStarts`. */\nfunction matchesWholeWord(normalized: string, wordStarts: ReadonlySet<number>, pattern: string): boolean {\n let at = normalized.indexOf(pattern);\n while (at !== -1) {\n const end = at + pattern.length;\n if (wordStarts.has(at) && (end === normalized.length || wordStarts.has(end))) {\n return true;\n }\n at = normalized.indexOf(pattern, at + 1);\n }\n return false;\n}\n\n/**\n * True when this field name must not be embedded.\n *\n * Note `hash` and `auth` are deliberately broad. A column called `AuthorName` normalises to\n * `authorname`, which contains `auth` — so it is refused. That is the trade accepted above:\n * a visible false refusal the user can work around beats a silent disclosure they cannot.\n */\nexport function IsSensitiveFieldName(name: string | null | undefined, purpose: VectorFieldPurpose = 'other'): boolean {\n if (!name) {\n return false;\n }\n const normalized = normalizeFieldName(name);\n if (SENSITIVE_FIELD_PATTERNS.some((pattern) => normalized.includes(pattern))) {\n return true;\n }\n const wordStarts = wordStartOffsets(name);\n if (SENSITIVE_FIELD_WORD_PATTERNS.some((pattern) => matchesAtWordStart(normalized, wordStarts, pattern))\n || SENSITIVE_FIELD_WHOLE_WORD_PATTERNS.some((pattern) => matchesWholeWord(normalized, wordStarts, pattern))) {\n return true;\n }\n if (purpose === 'duplicate-detection') {\n return false;\n }\n return BIRTH_DATE_FIELD_PATTERNS.some((pattern) => normalized.includes(pattern))\n || BIRTH_DATE_FIELD_WORD_PATTERNS.some((pattern) => matchesAtWordStart(normalized, wordStarts, pattern));\n}\n\n/** Drops every field that must not be embedded for this purpose, preserving order. */\nexport function WithoutSensitiveFields<T extends { Name: string }>(fields: ReadonlyArray<T>, purpose: VectorFieldPurpose = 'other'): T[] {\n return fields.filter((f) => !IsSensitiveFieldName(f.Name, purpose));\n}\n\n/**\n * Sensitive field names referenced by a template's `{{Placeholder}}` tokens.\n *\n * This is the second layer. The template is hand-editable after the model returns, so a\n * user can type a field the picker never offered. Returns the offending names so the\n * refusal can say which ones, rather than only that something was wrong.\n */\nexport function SensitiveFieldsInTemplate(templateText: string | null | undefined, purpose: VectorFieldPurpose = 'other'): string[] {\n const found = new Set<string>();\n for (const token of TemplatePlaceholderNames(templateText)) {\n if (IsSensitiveFieldName(token, purpose)) {\n found.add(token);\n }\n }\n return [...found].sort();\n}\n\n/**\n * Field names referenced by a template's `{{Placeholder}}` tokens, in order of appearance\n * and including repeats.\n *\n * Exported so the field-count cap in `vector-document-rules.ts` parses placeholders the same\n * way this refusal does. Two parsers that drift apart would mean a template that satisfies\n * one guard and evades the other.\n */\nexport function TemplatePlaceholderNames(templateText: string | null | undefined): string[] {\n if (!templateText) {\n return [];\n }\n // Nunjucks/Handlebars-style placeholders. The field name is the first identifier\n // inside the braces; filters and whitespace after it are ignored.\n const placeholder = /\\{\\{\\s*([A-Za-z0-9_.\\-]+)/g;\n const names: string[] = [];\n let match: RegExpExecArray | null;\n while ((match = placeholder.exec(templateText)) !== null) {\n names.push(match[1]);\n }\n return names;\n}\n"]}
|
|
@@ -123,4 +123,17 @@ export declare function IsVectorizableEntity(entity: {
|
|
|
123
123
|
Name: string;
|
|
124
124
|
SchemaName?: string | null;
|
|
125
125
|
}): boolean;
|
|
126
|
+
/** Match thresholds an Entity Document stores, as fractions of 1. */
|
|
127
|
+
export interface DocumentMatchThresholds {
|
|
128
|
+
Potential: number;
|
|
129
|
+
Absolute: number;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The thresholds a model suggestion can put on the document it becomes. The suggestion panel
|
|
133
|
+
* shows the model's potential and absolute thresholds, and Save used to drop them, so the
|
|
134
|
+
* document kept the defaults the user never saw. Returns null when the suggestion's values are
|
|
135
|
+
* not usable as stored: each must be a number above 0 and at most 1 (the same fraction-of-1
|
|
136
|
+
* scale the document uses), and potential may not exceed absolute.
|
|
137
|
+
*/
|
|
138
|
+
export declare function SuggestedMatchThresholds(potential: number | null | undefined, absolute: number | null | undefined): DocumentMatchThresholds | null;
|
|
126
139
|
//# sourceMappingURL=vector-document-rules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-document-rules.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-document-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG7E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAK9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQnG;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GACjD;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAW9F;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAAqB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrD,OAAO,CAKT"}
|
|
1
|
+
{"version":3,"file":"vector-document-rules.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-document-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG7E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAK9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQnG;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GACjD;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAW9F;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAAqB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrD,OAAO,CAKT;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,uBAAuB,GAAG,IAAI,CAOhC"}
|
|
@@ -165,4 +165,18 @@ export function IsVectorizableEntity(entity) {
|
|
|
165
165
|
}
|
|
166
166
|
return !entity.Name.startsWith('MJ:');
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* The thresholds a model suggestion can put on the document it becomes. The suggestion panel
|
|
170
|
+
* shows the model's potential and absolute thresholds, and Save used to drop them, so the
|
|
171
|
+
* document kept the defaults the user never saw. Returns null when the suggestion's values are
|
|
172
|
+
* not usable as stored: each must be a number above 0 and at most 1 (the same fraction-of-1
|
|
173
|
+
* scale the document uses), and potential may not exceed absolute.
|
|
174
|
+
*/
|
|
175
|
+
export function SuggestedMatchThresholds(potential, absolute) {
|
|
176
|
+
const usable = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0 && v <= 1;
|
|
177
|
+
if (!usable(potential) || !usable(absolute) || potential > absolute) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
return { Potential: potential, Absolute: absolute };
|
|
181
|
+
}
|
|
168
182
|
//# sourceMappingURL=vector-document-rules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-document-rules.js","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-document-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rules the Vectors tab applies when it turns a model suggestion into real metadata.\n *\n * Three separate refusals live here, and they share a theme with `sensitive-fields.ts`: the\n * suggestion comes from a language model and the template stays hand-editable afterwards, so\n * anything that matters has to be a property of the code rather than of the prompt.\n *\n * 1. The Entity Document Type is resolved from the use case the user actually picked,\n * instead of always writing a duplicate-detection document.\n * 2. The number of interpolated fields is bounded, because an unbounded list is how a\n * template balloons and how columns nobody chose end up embedded.\n * 3. MemberJunction's own internal entities are not offered as vectorization targets.\n *\n * Kept out of the component so each rule can be tested as a function rather than through a\n * TestBed, matching how `sensitive-fields.ts` is structured.\n */\n\nimport { TemplatePlaceholderNames } from './sensitive-fields';\n\n// ─── 1. Entity Document Type per use case ────────────────────────────────────\n\n/**\n * The Entity Document Type each use case writes.\n *\n * The dialog offers these use cases, and until now every one of them produced a\n * `Record Duplicate` document — the type name was hardcoded in the save path, so choosing\n * \"search\" silently discarded the choice and wrote the wrong type. A vector pool is typed:\n * `Provider.SearchEntity` and the Search Entity action read `Search`-typed documents, so a\n * search request stored as `Record Duplicate` is not merely mislabelled, it is not found by\n * the thing that wanted it.\n *\n * The two names here are MJ's own, not invented: both are seeded Entity Document Types, and\n * the Vectorize Entity action's `EntityDocumentType` parameter is documented as defaulting\n * to `Record Duplicate` and accepting `Search`.\n *\n * The dialog's Use Case buttons are exactly this map's keys. There is no `classification`\n * entry: MJ seeds no `Classification` type, so that button failed on every stock install and\n * was removed until the type exists (#5630).\n */\nexport const ENTITY_DOCUMENT_TYPE_BY_USE_CASE: Readonly<Record<string, string>> = {\n 'duplicate detection': 'Record Duplicate',\n 'search': 'Search',\n};\n\n/**\n * The Entity Document Type name for a use case, or null when the use case is unrecognised.\n *\n * Returns null rather than falling back to a default: a use case this code does not know\n * about must not quietly become a duplicate-detection document.\n */\nexport function EntityDocumentTypeForUseCase(useCase: string | null | undefined): string | null {\n if (!useCase) {\n return null;\n }\n return ENTITY_DOCUMENT_TYPE_BY_USE_CASE[useCase.trim().toLowerCase()] ?? null;\n}\n\n/**\n * The use case the suggestion prompt is given for an existing document of this type, or null\n * when the type has none (e.g. `Context`).\n *\n * The edit panel's \"Regenerate template\" uses it, so a regenerated template still matches the\n * document's type. It reads the same map as {@link EntityDocumentTypeForUseCase}, so the two\n * directions cannot drift. Callers refuse on null rather than substitute a use case.\n */\nexport function SuggestionUseCaseForDocumentType(typeName: string | null | undefined): string | null {\n if (!typeName) {\n return null;\n }\n const wanted = typeName.trim().toLowerCase();\n const match = Object.entries(ENTITY_DOCUMENT_TYPE_BY_USE_CASE)\n .find(([, documentType]) => documentType.toLowerCase() === wanted);\n return match ? match[0] : null;\n}\n\n// ─── 2. How many fields a template may interpolate ───────────────────────────\n\n/**\n * The most distinct fields one generated template may interpolate.\n *\n * Derived from the suggestion prompt's own contract rather than copied from elsewhere.\n * `metadata/prompts/templates/system/entity-document-suggestion.template.md` requires\n * \"**Output must be 1-4 natural language sentences**\" and explains at length why a\n * key-value dump embeds badly compared with English prose.\n *\n * So: 4 sentences — the prompt's own ceiling — times 6 interpolations per sentence, past\n * which a sentence stops being the natural English the prompt demands and becomes the dump\n * it explicitly forbids. That gives 24.\n *\n * Cross-check against the prompt's three worked examples, which interpolate 8, 6 and 4\n * distinct placeholders: 24 is three times the richest thing the prompt itself demonstrates,\n * so the cap cannot fire on anything the prompt teaches a model to produce. It fires when a\n * model has ignored the sentence contract and reached for the whole table.\n */\nexport const MAX_TEMPLATE_FIELDS = 24;\n\n/** Distinct `{{Placeholder}}` field names a template interpolates. */\nexport function TemplateFieldNames(templateText: string | null | undefined): string[] {\n return [...new Set(TemplatePlaceholderNames(templateText))];\n}\n\n/**\n * Truncates a model-supplied field list to the cap.\n *\n * Truncation rather than refusal, because this list is the model's own description of what\n * it selected and is shown as chips — dropping the tail and saying so is more useful than\n * discarding the whole suggestion. The authoritative refusal is on the template, below,\n * since the template is what actually gets embedded.\n */\nexport function CapSelectedFields(\n fields: ReadonlyArray<string> | null | undefined,\n): { fields: string[]; dropped: number } {\n if (!fields || fields.length === 0) {\n return { fields: [], dropped: 0 };\n }\n const unique = [...new Set(fields)];\n if (unique.length <= MAX_TEMPLATE_FIELDS) {\n return { fields: unique, dropped: 0 };\n }\n return {\n fields: unique.slice(0, MAX_TEMPLATE_FIELDS),\n dropped: unique.length - MAX_TEMPLATE_FIELDS,\n };\n}\n\n/**\n * The refusal message when a template interpolates more fields than the cap allows, or null\n * when it is within the cap.\n *\n * A template cannot be truncated without mangling its prose, so this one refuses rather than\n * trimming — and the message carries both numbers, because \"too many fields\" without the\n * count is not actionable. The template is editable in the dialog, so the user can act on it\n * without losing the suggestion.\n */\nexport function TemplateFieldCapRefusal(templateText: string | null | undefined): string | null {\n const names = TemplateFieldNames(templateText);\n if (names.length <= MAX_TEMPLATE_FIELDS) {\n return null;\n }\n return (\n `This template interpolates ${names.length} fields, and at most ${MAX_TEMPLATE_FIELDS} ` +\n `may be embedded. A template this wide stops reading like the natural language that ` +\n `embeds well, and pulls in columns nobody chose. Remove ` +\n `${names.length - MAX_TEMPLATE_FIELDS} field(s) from the template and save again.`\n );\n}\n\n// ─── 3. Which entities may be offered as vectorization targets ───────────────\n\n/**\n * Schemas whose entities are not offered in the picker.\n *\n * Follows the existing frontend precedent — `FRONTEND_BLOCKED_SCHEMAS` in\n * `DatabaseDesigner/services/database-designer.engine.ts` and in\n * `DatabaseDesigner/components/create-wizard/steps/step-relationships.component.ts`, both\n * `new Set(['__mj'])` — rather than inventing a rule.\n */\nexport const VECTOR_BLOCKED_SCHEMAS: ReadonlySet<string> = new Set(['__mj']);\n\n/**\n * True when an entity may be offered as a vectorization target.\n *\n * The picker previously listed every entity in metadata, so MemberJunction's own ~378\n * internal entities — prompt runs, audit logs, record changes, credentials — were offered\n * alongside the user's business tables, both as noise and as embedding targets.\n *\n * Two rules, and they currently pick out the same set: every `MJ:`-prefixed entity is in the\n * `__mj` schema and vice versa (378 and 378, exactly coextensive, in the 5.46 baseline). The\n * name-prefix rule is therefore defence in depth against an MJ entity registered into some\n * other schema, not extra coverage today. Said plainly so nobody later reads it as load\n * bearing and is surprised.\n *\n * Note MJ does seed two `Search`-typed documents over `__mj` entities (`AI Agents Search`,\n * `AI Prompts Search`), so framework entities are not unvectorizable in principle. Those\n * arrive through metadata sync, which is a different authoring channel with a different\n * audience; this dialog is where a business user configures vectorization of their own data,\n * and burying their tables under the framework's is the defect being fixed.\n */\nexport function IsVectorizableEntity(\n entity: { Name: string; SchemaName?: string | null },\n): boolean {\n if (entity.SchemaName && VECTOR_BLOCKED_SCHEMAS.has(entity.SchemaName)) {\n return false;\n }\n return !entity.Name.startsWith('MJ:');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"vector-document-rules.js","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-document-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAqC;IAC9E,qBAAqB,EAAE,kBAAkB;IACzC,QAAQ,EAAE,QAAQ;CACrB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAkC;IAC3E,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,gCAAgC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AAClF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gCAAgC,CAAC,QAAmC;IAChF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC;SACzD,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;IACvE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC;AAED,gFAAgF;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,sEAAsE;AACtE,MAAM,UAAU,kBAAkB,CAAC,YAAuC;IACtE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,wBAAwB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC7B,MAAgD;IAEhD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACtC,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,IAAI,mBAAmB,EAAE,CAAC;QACvC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO;QACH,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC;QAC5C,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,mBAAmB;KAC/C,CAAC;AACN,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,YAAuC;IAC3E,MAAM,KAAK,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,KAAK,CAAC,MAAM,IAAI,mBAAmB,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,CACH,8BAA8B,KAAK,CAAC,MAAM,wBAAwB,mBAAmB,GAAG;QACxF,qFAAqF;QACrF,yDAAyD;QACzD,GAAG,KAAK,CAAC,MAAM,GAAG,mBAAmB,6CAA6C,CACrF,CAAC;AACN,CAAC;AAED,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,oBAAoB,CAChC,MAAoD;IAEpD,IAAI,MAAM,CAAC,UAAU,IAAI,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACpC,SAAoC,EACpC,QAAmC;IAEnC,MAAM,MAAM,GAAG,CAAC,CAA4B,EAAe,EAAE,CACzD,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,SAAS,GAAG,QAAQ,EAAE,CAAC;QAClE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACxD,CAAC","sourcesContent":["/**\n * Rules the Vectors tab applies when it turns a model suggestion into real metadata.\n *\n * Three separate refusals live here, and they share a theme with `sensitive-fields.ts`: the\n * suggestion comes from a language model and the template stays hand-editable afterwards, so\n * anything that matters has to be a property of the code rather than of the prompt.\n *\n * 1. The Entity Document Type is resolved from the use case the user actually picked,\n * instead of always writing a duplicate-detection document.\n * 2. The number of interpolated fields is bounded, because an unbounded list is how a\n * template balloons and how columns nobody chose end up embedded.\n * 3. MemberJunction's own internal entities are not offered as vectorization targets.\n *\n * Kept out of the component so each rule can be tested as a function rather than through a\n * TestBed, matching how `sensitive-fields.ts` is structured.\n */\n\nimport { TemplatePlaceholderNames } from './sensitive-fields';\n\n// ─── 1. Entity Document Type per use case ────────────────────────────────────\n\n/**\n * The Entity Document Type each use case writes.\n *\n * The dialog offers these use cases, and until now every one of them produced a\n * `Record Duplicate` document — the type name was hardcoded in the save path, so choosing\n * \"search\" silently discarded the choice and wrote the wrong type. A vector pool is typed:\n * `Provider.SearchEntity` and the Search Entity action read `Search`-typed documents, so a\n * search request stored as `Record Duplicate` is not merely mislabelled, it is not found by\n * the thing that wanted it.\n *\n * The two names here are MJ's own, not invented: both are seeded Entity Document Types, and\n * the Vectorize Entity action's `EntityDocumentType` parameter is documented as defaulting\n * to `Record Duplicate` and accepting `Search`.\n *\n * The dialog's Use Case buttons are exactly this map's keys. There is no `classification`\n * entry: MJ seeds no `Classification` type, so that button failed on every stock install and\n * was removed until the type exists (#5630).\n */\nexport const ENTITY_DOCUMENT_TYPE_BY_USE_CASE: Readonly<Record<string, string>> = {\n 'duplicate detection': 'Record Duplicate',\n 'search': 'Search',\n};\n\n/**\n * The Entity Document Type name for a use case, or null when the use case is unrecognised.\n *\n * Returns null rather than falling back to a default: a use case this code does not know\n * about must not quietly become a duplicate-detection document.\n */\nexport function EntityDocumentTypeForUseCase(useCase: string | null | undefined): string | null {\n if (!useCase) {\n return null;\n }\n return ENTITY_DOCUMENT_TYPE_BY_USE_CASE[useCase.trim().toLowerCase()] ?? null;\n}\n\n/**\n * The use case the suggestion prompt is given for an existing document of this type, or null\n * when the type has none (e.g. `Context`).\n *\n * The edit panel's \"Regenerate template\" uses it, so a regenerated template still matches the\n * document's type. It reads the same map as {@link EntityDocumentTypeForUseCase}, so the two\n * directions cannot drift. Callers refuse on null rather than substitute a use case.\n */\nexport function SuggestionUseCaseForDocumentType(typeName: string | null | undefined): string | null {\n if (!typeName) {\n return null;\n }\n const wanted = typeName.trim().toLowerCase();\n const match = Object.entries(ENTITY_DOCUMENT_TYPE_BY_USE_CASE)\n .find(([, documentType]) => documentType.toLowerCase() === wanted);\n return match ? match[0] : null;\n}\n\n// ─── 2. How many fields a template may interpolate ───────────────────────────\n\n/**\n * The most distinct fields one generated template may interpolate.\n *\n * Derived from the suggestion prompt's own contract rather than copied from elsewhere.\n * `metadata/prompts/templates/system/entity-document-suggestion.template.md` requires\n * \"**Output must be 1-4 natural language sentences**\" and explains at length why a\n * key-value dump embeds badly compared with English prose.\n *\n * So: 4 sentences — the prompt's own ceiling — times 6 interpolations per sentence, past\n * which a sentence stops being the natural English the prompt demands and becomes the dump\n * it explicitly forbids. That gives 24.\n *\n * Cross-check against the prompt's three worked examples, which interpolate 8, 6 and 4\n * distinct placeholders: 24 is three times the richest thing the prompt itself demonstrates,\n * so the cap cannot fire on anything the prompt teaches a model to produce. It fires when a\n * model has ignored the sentence contract and reached for the whole table.\n */\nexport const MAX_TEMPLATE_FIELDS = 24;\n\n/** Distinct `{{Placeholder}}` field names a template interpolates. */\nexport function TemplateFieldNames(templateText: string | null | undefined): string[] {\n return [...new Set(TemplatePlaceholderNames(templateText))];\n}\n\n/**\n * Truncates a model-supplied field list to the cap.\n *\n * Truncation rather than refusal, because this list is the model's own description of what\n * it selected and is shown as chips — dropping the tail and saying so is more useful than\n * discarding the whole suggestion. The authoritative refusal is on the template, below,\n * since the template is what actually gets embedded.\n */\nexport function CapSelectedFields(\n fields: ReadonlyArray<string> | null | undefined,\n): { fields: string[]; dropped: number } {\n if (!fields || fields.length === 0) {\n return { fields: [], dropped: 0 };\n }\n const unique = [...new Set(fields)];\n if (unique.length <= MAX_TEMPLATE_FIELDS) {\n return { fields: unique, dropped: 0 };\n }\n return {\n fields: unique.slice(0, MAX_TEMPLATE_FIELDS),\n dropped: unique.length - MAX_TEMPLATE_FIELDS,\n };\n}\n\n/**\n * The refusal message when a template interpolates more fields than the cap allows, or null\n * when it is within the cap.\n *\n * A template cannot be truncated without mangling its prose, so this one refuses rather than\n * trimming — and the message carries both numbers, because \"too many fields\" without the\n * count is not actionable. The template is editable in the dialog, so the user can act on it\n * without losing the suggestion.\n */\nexport function TemplateFieldCapRefusal(templateText: string | null | undefined): string | null {\n const names = TemplateFieldNames(templateText);\n if (names.length <= MAX_TEMPLATE_FIELDS) {\n return null;\n }\n return (\n `This template interpolates ${names.length} fields, and at most ${MAX_TEMPLATE_FIELDS} ` +\n `may be embedded. A template this wide stops reading like the natural language that ` +\n `embeds well, and pulls in columns nobody chose. Remove ` +\n `${names.length - MAX_TEMPLATE_FIELDS} field(s) from the template and save again.`\n );\n}\n\n// ─── 3. Which entities may be offered as vectorization targets ───────────────\n\n/**\n * Schemas whose entities are not offered in the picker.\n *\n * Follows the existing frontend precedent — `FRONTEND_BLOCKED_SCHEMAS` in\n * `DatabaseDesigner/services/database-designer.engine.ts` and in\n * `DatabaseDesigner/components/create-wizard/steps/step-relationships.component.ts`, both\n * `new Set(['__mj'])` — rather than inventing a rule.\n */\nexport const VECTOR_BLOCKED_SCHEMAS: ReadonlySet<string> = new Set(['__mj']);\n\n/**\n * True when an entity may be offered as a vectorization target.\n *\n * The picker previously listed every entity in metadata, so MemberJunction's own ~378\n * internal entities — prompt runs, audit logs, record changes, credentials — were offered\n * alongside the user's business tables, both as noise and as embedding targets.\n *\n * Two rules, and they currently pick out the same set: every `MJ:`-prefixed entity is in the\n * `__mj` schema and vice versa (378 and 378, exactly coextensive, in the 5.46 baseline). The\n * name-prefix rule is therefore defence in depth against an MJ entity registered into some\n * other schema, not extra coverage today. Said plainly so nobody later reads it as load\n * bearing and is surprised.\n *\n * Note MJ does seed two `Search`-typed documents over `__mj` entities (`AI Agents Search`,\n * `AI Prompts Search`), so framework entities are not unvectorizable in principle. Those\n * arrive through metadata sync, which is a different authoring channel with a different\n * audience; this dialog is where a business user configures vectorization of their own data,\n * and burying their tables under the framework's is the defect being fixed.\n */\nexport function IsVectorizableEntity(\n entity: { Name: string; SchemaName?: string | null },\n): boolean {\n if (entity.SchemaName && VECTOR_BLOCKED_SCHEMAS.has(entity.SchemaName)) {\n return false;\n }\n return !entity.Name.startsWith('MJ:');\n}\n\n/** Match thresholds an Entity Document stores, as fractions of 1. */\nexport interface DocumentMatchThresholds {\n Potential: number;\n Absolute: number;\n}\n\n/**\n * The thresholds a model suggestion can put on the document it becomes. The suggestion panel\n * shows the model's potential and absolute thresholds, and Save used to drop them, so the\n * document kept the defaults the user never saw. Returns null when the suggestion's values are\n * not usable as stored: each must be a number above 0 and at most 1 (the same fraction-of-1\n * scale the document uses), and potential may not exceed absolute.\n */\nexport function SuggestedMatchThresholds(\n potential: number | null | undefined,\n absolute: number | null | undefined\n): DocumentMatchThresholds | null {\n const usable = (v: number | null | undefined): v is number =>\n typeof v === 'number' && Number.isFinite(v) && v > 0 && v <= 1;\n if (!usable(potential) || !usable(absolute) || potential > absolute) {\n return null;\n }\n return { Potential: potential, Absolute: absolute };\n}\n"]}
|
|
@@ -12,6 +12,7 @@ import { ResourceData, MJVectorDatabaseEntity } from '@memberjunction/core-entit
|
|
|
12
12
|
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
|
|
13
13
|
import { ViewToggleOption } from '@memberjunction/ng-ui-components';
|
|
14
14
|
import { KPICardData } from '../widgets/kpi-card.component';
|
|
15
|
+
import { VectorIndexOption } from './vector-store-selection';
|
|
15
16
|
import * as i0 from "@angular/core";
|
|
16
17
|
/** Flattened row for the entity sync table */
|
|
17
18
|
interface EntitySyncRow {
|
|
@@ -50,6 +51,11 @@ export declare class VectorManagementResourceComponent extends BaseResourceCompo
|
|
|
50
51
|
private activityService;
|
|
51
52
|
protected navigationService: NavigationService;
|
|
52
53
|
protected destroy$: Subject<void>;
|
|
54
|
+
/**
|
|
55
|
+
* How long a sync may go without a progress event before the tab stops waiting. Reaching it does
|
|
56
|
+
* not mean the sync finished (see subscribeToPipelineProgress).
|
|
57
|
+
*/
|
|
58
|
+
private static readonly SYNC_SILENCE_LIMIT_MS;
|
|
53
59
|
/** View mode: 'index' = Option A (shared index as hero, entity docs as children),
|
|
54
60
|
* 'operations' = Option C (operations monitoring with real-time sync status) */
|
|
55
61
|
ViewMode: 'index' | 'operations';
|
|
@@ -149,20 +155,29 @@ export declare class VectorManagementResourceComponent extends BaseResourceCompo
|
|
|
149
155
|
}[];
|
|
150
156
|
/** Selected vector index ID — if user picks an existing one */
|
|
151
157
|
SelectedVectorIndexID: string;
|
|
152
|
-
/**
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
/**
|
|
159
|
+
* The indexes the suggestion panel offers: those in the selected database built with the selected
|
|
160
|
+
* embedding model, so a chosen index can never store a different model than the one shown.
|
|
161
|
+
*/
|
|
162
|
+
get FilteredIndexesForSelectedDB(): VectorIndexOption[];
|
|
163
|
+
/** The indexes the edit panel offers, matched to its database and embedding model the same way. */
|
|
164
|
+
get EditFilteredIndexes(): VectorIndexOption[];
|
|
165
|
+
/** Suggestion panel: picking an index moves the model and database dropdowns to its values. */
|
|
166
|
+
OnSuggestVectorIndexChange(indexID: string): void;
|
|
167
|
+
/** Suggestion panel: a chosen index from another database goes back to Auto. */
|
|
168
|
+
OnSuggestVectorDBChange(databaseID: string): void;
|
|
169
|
+
/** Suggestion panel: a chosen index built with another model goes back to Auto. */
|
|
170
|
+
OnSuggestEmbeddingModelChange(embeddingModelID: string): void;
|
|
171
|
+
/** Edit panel: picking an index moves the model and database dropdowns to its values. */
|
|
172
|
+
OnEditVectorIndexChange(indexID: string): void;
|
|
173
|
+
/** Edit panel: a chosen index from another database goes back to Auto. */
|
|
174
|
+
OnEditVectorDBChange(databaseID: string): void;
|
|
175
|
+
/** Edit panel: a chosen index built with another model goes back to Auto. */
|
|
176
|
+
OnEditEmbeddingModelChange(embeddingModelID: string): void;
|
|
177
|
+
private get suggestSelection();
|
|
178
|
+
private applySuggestSelection;
|
|
179
|
+
private get editSelection();
|
|
180
|
+
private applyEditSelection;
|
|
166
181
|
/** Grouped entity list for the suggestion panel — schemas as groups, entities as items */
|
|
167
182
|
EntityGroups: {
|
|
168
183
|
SchemaName: string;
|
|
@@ -385,6 +400,11 @@ export declare class VectorManagementResourceComponent extends BaseResourceCompo
|
|
|
385
400
|
private callSuggestionPrompt;
|
|
386
401
|
/** Find the Entity Document Suggestion prompt from AIEngineBase */
|
|
387
402
|
private findSuggestionPrompt;
|
|
403
|
+
/**
|
|
404
|
+
* What a document for this use case embeds its fields for. Only a duplicate-detection document
|
|
405
|
+
* may embed a date of birth (see sensitive-fields.ts).
|
|
406
|
+
*/
|
|
407
|
+
private vectorFieldPurpose;
|
|
388
408
|
/** Build the data payload for the suggestion prompt */
|
|
389
409
|
private buildPromptData;
|
|
390
410
|
static ɵfac: i0.ɵɵFactoryDeclaration<VectorManagementResourceComponent, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-management-resource.component.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-management-resource.component.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAgC,SAAS,EAAE,aAAa,EAAoB,UAAU,EAAU,MAAM,eAAe,CAAC;AAC7H,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAG/B,OAAO,EACH,YAAY,EAEZ,sBAAsB,EAMzB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAmB,MAAM,2BAA2B,CAAC;AACtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;;
|
|
1
|
+
{"version":3,"file":"vector-management-resource.component.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/vectors/vector-management-resource.component.ts"],"names":[],"mappings":"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"}
|