@traits-dev/core 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-1c7xQG2q.d.cts → index-Ct4kuPk7.d.cts} +23 -4
- package/dist/{index-1c7xQG2q.d.ts → index-Ct4kuPk7.d.ts} +23 -4
- package/dist/index.cjs +271 -71
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +271 -71
- package/dist/internal.cjs +542 -72
- package/dist/internal.d.cts +16 -3
- package/dist/internal.d.ts +16 -3
- package/dist/internal.js +540 -72
- package/package.json +1 -1
|
@@ -25,13 +25,18 @@ interface ContextAdaptation {
|
|
|
25
25
|
inject?: string[];
|
|
26
26
|
priority?: number;
|
|
27
27
|
}
|
|
28
|
+
interface LockedRule {
|
|
29
|
+
rule: string;
|
|
30
|
+
locked?: boolean;
|
|
31
|
+
}
|
|
32
|
+
type RuleConstraint = string | LockedRule;
|
|
28
33
|
interface CapabilityHandoff {
|
|
29
34
|
trigger: string;
|
|
30
35
|
action: string;
|
|
31
36
|
}
|
|
32
37
|
interface ProfileCapabilities {
|
|
33
38
|
tools: string[];
|
|
34
|
-
constraints:
|
|
39
|
+
constraints: RuleConstraint[];
|
|
35
40
|
handoff: CapabilityHandoff;
|
|
36
41
|
}
|
|
37
42
|
interface PersonalityProfile {
|
|
@@ -60,12 +65,12 @@ interface PersonalityProfile {
|
|
|
60
65
|
[key: string]: DimensionValue | HumorDimensionValue | undefined;
|
|
61
66
|
};
|
|
62
67
|
vocabulary?: VocabularyConstraints;
|
|
63
|
-
behavioral_rules?:
|
|
68
|
+
behavioral_rules?: RuleConstraint[];
|
|
64
69
|
context_adaptations?: ContextAdaptation[];
|
|
65
70
|
capabilities?: ProfileCapabilities;
|
|
66
71
|
localization?: Record<string, unknown>;
|
|
67
72
|
channel_adaptations?: Record<string, unknown>;
|
|
68
|
-
extends?: string;
|
|
73
|
+
extends?: string | string[];
|
|
69
74
|
behavioral_rules_remove?: string[];
|
|
70
75
|
context_adaptations_remove?: string[];
|
|
71
76
|
[key: string]: unknown;
|
|
@@ -143,6 +148,8 @@ interface ExtendsDiagnostics {
|
|
|
143
148
|
interface ExtendsResult {
|
|
144
149
|
profile: PersonalityProfile;
|
|
145
150
|
parentPath: string | null;
|
|
151
|
+
parentPaths: string[];
|
|
152
|
+
parentProfile: PersonalityProfile | null;
|
|
146
153
|
diagnostics: ExtendsDiagnostics;
|
|
147
154
|
}
|
|
148
155
|
interface ContextResolution {
|
|
@@ -189,6 +196,18 @@ declare function injectPersonality({ compiledPersonality, system, model }: {
|
|
|
189
196
|
model?: string;
|
|
190
197
|
}): string;
|
|
191
198
|
|
|
199
|
+
type EvalScenarioCategory = "standard" | "frustrated" | "edge" | "multi-turn" | "formal" | "casual" | "mixed";
|
|
200
|
+
type EvalScenarioMessage = {
|
|
201
|
+
role: "user" | "assistant";
|
|
202
|
+
content: string;
|
|
203
|
+
};
|
|
204
|
+
type EvalScenario = {
|
|
205
|
+
id: string;
|
|
206
|
+
category: EvalScenarioCategory;
|
|
207
|
+
domain?: string;
|
|
208
|
+
messages: EvalScenarioMessage[];
|
|
209
|
+
expected_behavior?: string;
|
|
210
|
+
};
|
|
192
211
|
type EvalSample = {
|
|
193
212
|
id?: string;
|
|
194
213
|
prompt?: string;
|
|
@@ -359,4 +378,4 @@ declare function runImportAnalysis(promptText: unknown, options?: ImportOptions)
|
|
|
359
378
|
yaml: string;
|
|
360
379
|
}>;
|
|
361
380
|
|
|
362
|
-
export {
|
|
381
|
+
export { normalizeProfile as A, renderImportedProfileYAML as B, type CapabilityHandoff as C, type DimensionName as D, type EvalScenario as E, resolveActiveContext as F, resolveExtends as G, type HumorDimensionObject as H, type ImportOptions as I, runImportAnalysis as J, runTier1EvaluationForProfile as K, type Level as L, runTier2Evaluation as M, runTier2EvaluationForProfile as N, runTier3Evaluation as O, type PersonalityProfile as P, runTier3EvaluationForProfile as Q, type RuleConstraint as R, validateEvalScenario as S, type Tier1Options as T, validateEvalScenarios as U, type ValidationResult as V, validateProfile as W, validateResolvedProfile as X, type ValidationCheckSummary as a, type ValidationDiagnostic as b, type CompileOptions as c, type CompiledPersonality as d, type ContextAdaptation as e, type ContextResolution as f, type DimensionObject as g, type DimensionShorthand as h, type DimensionValue as i, type EvalSample as j, type ExtendsDiagnostics as k, type ExtendsResult as l, type HumorDimensionValue as m, type HumorStyle as n, type LockedRule as o, type ProfileCapabilities as p, type Tier2Options as q, runTier1Evaluation as r, type Tier3Options as s, type VocabularyConstraints as t, compileProfile as u, compileResolvedProfile as v, evaluateTier1Response as w, injectPersonality as x, loadProfileFile as y, mapImportAnalysisToProfile as z };
|
|
@@ -25,13 +25,18 @@ interface ContextAdaptation {
|
|
|
25
25
|
inject?: string[];
|
|
26
26
|
priority?: number;
|
|
27
27
|
}
|
|
28
|
+
interface LockedRule {
|
|
29
|
+
rule: string;
|
|
30
|
+
locked?: boolean;
|
|
31
|
+
}
|
|
32
|
+
type RuleConstraint = string | LockedRule;
|
|
28
33
|
interface CapabilityHandoff {
|
|
29
34
|
trigger: string;
|
|
30
35
|
action: string;
|
|
31
36
|
}
|
|
32
37
|
interface ProfileCapabilities {
|
|
33
38
|
tools: string[];
|
|
34
|
-
constraints:
|
|
39
|
+
constraints: RuleConstraint[];
|
|
35
40
|
handoff: CapabilityHandoff;
|
|
36
41
|
}
|
|
37
42
|
interface PersonalityProfile {
|
|
@@ -60,12 +65,12 @@ interface PersonalityProfile {
|
|
|
60
65
|
[key: string]: DimensionValue | HumorDimensionValue | undefined;
|
|
61
66
|
};
|
|
62
67
|
vocabulary?: VocabularyConstraints;
|
|
63
|
-
behavioral_rules?:
|
|
68
|
+
behavioral_rules?: RuleConstraint[];
|
|
64
69
|
context_adaptations?: ContextAdaptation[];
|
|
65
70
|
capabilities?: ProfileCapabilities;
|
|
66
71
|
localization?: Record<string, unknown>;
|
|
67
72
|
channel_adaptations?: Record<string, unknown>;
|
|
68
|
-
extends?: string;
|
|
73
|
+
extends?: string | string[];
|
|
69
74
|
behavioral_rules_remove?: string[];
|
|
70
75
|
context_adaptations_remove?: string[];
|
|
71
76
|
[key: string]: unknown;
|
|
@@ -143,6 +148,8 @@ interface ExtendsDiagnostics {
|
|
|
143
148
|
interface ExtendsResult {
|
|
144
149
|
profile: PersonalityProfile;
|
|
145
150
|
parentPath: string | null;
|
|
151
|
+
parentPaths: string[];
|
|
152
|
+
parentProfile: PersonalityProfile | null;
|
|
146
153
|
diagnostics: ExtendsDiagnostics;
|
|
147
154
|
}
|
|
148
155
|
interface ContextResolution {
|
|
@@ -189,6 +196,18 @@ declare function injectPersonality({ compiledPersonality, system, model }: {
|
|
|
189
196
|
model?: string;
|
|
190
197
|
}): string;
|
|
191
198
|
|
|
199
|
+
type EvalScenarioCategory = "standard" | "frustrated" | "edge" | "multi-turn" | "formal" | "casual" | "mixed";
|
|
200
|
+
type EvalScenarioMessage = {
|
|
201
|
+
role: "user" | "assistant";
|
|
202
|
+
content: string;
|
|
203
|
+
};
|
|
204
|
+
type EvalScenario = {
|
|
205
|
+
id: string;
|
|
206
|
+
category: EvalScenarioCategory;
|
|
207
|
+
domain?: string;
|
|
208
|
+
messages: EvalScenarioMessage[];
|
|
209
|
+
expected_behavior?: string;
|
|
210
|
+
};
|
|
192
211
|
type EvalSample = {
|
|
193
212
|
id?: string;
|
|
194
213
|
prompt?: string;
|
|
@@ -359,4 +378,4 @@ declare function runImportAnalysis(promptText: unknown, options?: ImportOptions)
|
|
|
359
378
|
yaml: string;
|
|
360
379
|
}>;
|
|
361
380
|
|
|
362
|
-
export {
|
|
381
|
+
export { normalizeProfile as A, renderImportedProfileYAML as B, type CapabilityHandoff as C, type DimensionName as D, type EvalScenario as E, resolveActiveContext as F, resolveExtends as G, type HumorDimensionObject as H, type ImportOptions as I, runImportAnalysis as J, runTier1EvaluationForProfile as K, type Level as L, runTier2Evaluation as M, runTier2EvaluationForProfile as N, runTier3Evaluation as O, type PersonalityProfile as P, runTier3EvaluationForProfile as Q, type RuleConstraint as R, validateEvalScenario as S, type Tier1Options as T, validateEvalScenarios as U, type ValidationResult as V, validateProfile as W, validateResolvedProfile as X, type ValidationCheckSummary as a, type ValidationDiagnostic as b, type CompileOptions as c, type CompiledPersonality as d, type ContextAdaptation as e, type ContextResolution as f, type DimensionObject as g, type DimensionShorthand as h, type DimensionValue as i, type EvalSample as j, type ExtendsDiagnostics as k, type ExtendsResult as l, type HumorDimensionValue as m, type HumorStyle as n, type LockedRule as o, type ProfileCapabilities as p, type Tier2Options as q, runTier1Evaluation as r, type Tier3Options as s, type VocabularyConstraints as t, compileProfile as u, compileResolvedProfile as v, evaluateTier1Response as w, injectPersonality as x, loadProfileFile as y, mapImportAnalysisToProfile as z };
|
package/dist/index.cjs
CHANGED
|
@@ -102,6 +102,37 @@ function isClaudeModel(model) {
|
|
|
102
102
|
function isGptModel(model) {
|
|
103
103
|
return /gpt/i.test(String(model ?? ""));
|
|
104
104
|
}
|
|
105
|
+
function isLockedRule(value) {
|
|
106
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
107
|
+
const candidate = value;
|
|
108
|
+
if (typeof candidate.rule !== "string" || candidate.rule.trim().length === 0) return false;
|
|
109
|
+
if (candidate.locked != null && typeof candidate.locked !== "boolean") return false;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
function ruleConstraintText(entry) {
|
|
113
|
+
if (typeof entry === "string") {
|
|
114
|
+
const text = entry.trim();
|
|
115
|
+
return text.length > 0 ? text : null;
|
|
116
|
+
}
|
|
117
|
+
if (isLockedRule(entry)) {
|
|
118
|
+
return entry.rule.trim();
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function normalizeRuleConstraints(value) {
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const entry of asArray(value)) {
|
|
125
|
+
if (typeof entry === "string") {
|
|
126
|
+
const text = entry.trim();
|
|
127
|
+
if (!text) continue;
|
|
128
|
+
out.push({ rule: text, locked: false });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (!isLockedRule(entry)) continue;
|
|
132
|
+
out.push({ rule: entry.rule.trim(), locked: Boolean(entry.locked) });
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
105
136
|
|
|
106
137
|
// src/profile/merge.ts
|
|
107
138
|
var PASS_THROUGH_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -117,17 +148,6 @@ var PASS_THROUGH_FIELDS = /* @__PURE__ */ new Set([
|
|
|
117
148
|
"behavioral_rules_remove",
|
|
118
149
|
"context_adaptations_remove"
|
|
119
150
|
]);
|
|
120
|
-
function dedupExact(items) {
|
|
121
|
-
const seen = /* @__PURE__ */ new Set();
|
|
122
|
-
const out = [];
|
|
123
|
-
for (const item of items) {
|
|
124
|
-
const key = String(item);
|
|
125
|
-
if (seen.has(key)) continue;
|
|
126
|
-
seen.add(key);
|
|
127
|
-
out.push(item);
|
|
128
|
-
}
|
|
129
|
-
return out;
|
|
130
|
-
}
|
|
131
151
|
function dedupCaseInsensitive(items) {
|
|
132
152
|
const seen = /* @__PURE__ */ new Set();
|
|
133
153
|
const out = [];
|
|
@@ -170,8 +190,29 @@ function mergeVocabulary(parentVocab = {}, childVocab = {}) {
|
|
|
170
190
|
if (mergedForbidden.length) merged.forbidden_terms = mergedForbidden;
|
|
171
191
|
return merged;
|
|
172
192
|
}
|
|
193
|
+
function mergeRuleConstraints(parentRules = [], childRules = [], options) {
|
|
194
|
+
const out = [];
|
|
195
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
196
|
+
const combined = [
|
|
197
|
+
...normalizeRuleConstraints(parentRules),
|
|
198
|
+
...normalizeRuleConstraints(childRules)
|
|
199
|
+
];
|
|
200
|
+
for (const entry of combined) {
|
|
201
|
+
const key = options.caseInsensitive ? entry.rule.toLowerCase() : entry.rule;
|
|
202
|
+
const existingIndex = byKey.get(key);
|
|
203
|
+
if (existingIndex == null) {
|
|
204
|
+
byKey.set(key, out.length);
|
|
205
|
+
out.push({ rule: entry.rule, locked: entry.locked });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
out[existingIndex].locked = out[existingIndex].locked || entry.locked;
|
|
209
|
+
}
|
|
210
|
+
return out.map(
|
|
211
|
+
(entry) => entry.locked ? { rule: entry.rule, locked: true } : entry.rule
|
|
212
|
+
);
|
|
213
|
+
}
|
|
173
214
|
function mergeBehavioralRules(parentRules = [], childRules = []) {
|
|
174
|
-
return
|
|
215
|
+
return mergeRuleConstraints(parentRules, childRules, { caseInsensitive: false });
|
|
175
216
|
}
|
|
176
217
|
function mergeContextAdaptations(parentAdaptations = [], childAdaptations = []) {
|
|
177
218
|
const base = asArray(parentAdaptations).map((item) => clone(item));
|
|
@@ -203,13 +244,13 @@ function mergeCapabilities(parentCapabilities, childCapabilities) {
|
|
|
203
244
|
...asArray(parentCapabilities.tools),
|
|
204
245
|
...asArray(childCapabilities.tools)
|
|
205
246
|
]);
|
|
206
|
-
const mergedConstraints = dedupCaseInsensitive([
|
|
207
|
-
...asArray(parentCapabilities.constraints),
|
|
208
|
-
...asArray(childCapabilities.constraints)
|
|
209
|
-
]);
|
|
210
247
|
return {
|
|
211
248
|
tools: mergedTools,
|
|
212
|
-
constraints:
|
|
249
|
+
constraints: mergeRuleConstraints(
|
|
250
|
+
parentCapabilities.constraints,
|
|
251
|
+
childCapabilities.constraints,
|
|
252
|
+
{ caseInsensitive: true }
|
|
253
|
+
),
|
|
213
254
|
handoff: {
|
|
214
255
|
trigger: childCapabilities.handoff?.trigger ?? parentCapabilities.handoff?.trigger ?? "",
|
|
215
256
|
action: childCapabilities.handoff?.action ?? parentCapabilities.handoff?.action ?? ""
|
|
@@ -232,9 +273,15 @@ function applyExplicitRemovals(childProfile, mergedProfile) {
|
|
|
232
273
|
);
|
|
233
274
|
const childAdaptationRemovals = asArray(childProfile.context_adaptations_remove);
|
|
234
275
|
if (childBehavioralRemovals.length) {
|
|
235
|
-
mergedProfile.behavioral_rules = asArray(
|
|
236
|
-
|
|
237
|
-
)
|
|
276
|
+
mergedProfile.behavioral_rules = asArray(
|
|
277
|
+
mergedProfile.behavioral_rules
|
|
278
|
+
).filter((ruleEntry) => {
|
|
279
|
+
const ruleText = ruleConstraintText(ruleEntry);
|
|
280
|
+
if (!ruleText) return false;
|
|
281
|
+
if (!childBehavioralRemovals.includes(ruleText)) return true;
|
|
282
|
+
if (typeof ruleEntry === "object" && ruleEntry.locked === true) return true;
|
|
283
|
+
return false;
|
|
284
|
+
});
|
|
238
285
|
}
|
|
239
286
|
if (childForbiddenRemovals.length) {
|
|
240
287
|
const nextForbidden = removeCaseInsensitive(
|
|
@@ -289,37 +336,89 @@ function mergeProfiles(parentProfile, childProfile) {
|
|
|
289
336
|
}
|
|
290
337
|
|
|
291
338
|
// src/profile/extends.ts
|
|
339
|
+
function normalizeExtendsTargets(value) {
|
|
340
|
+
if (value == null) return [];
|
|
341
|
+
if (typeof value === "string") {
|
|
342
|
+
return value.trim().length > 0 ? [value] : null;
|
|
343
|
+
}
|
|
344
|
+
if (!Array.isArray(value) || value.length === 0) return null;
|
|
345
|
+
const targets = [];
|
|
346
|
+
for (const item of value) {
|
|
347
|
+
if (typeof item !== "string" || item.trim().length === 0) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
targets.push(item);
|
|
351
|
+
}
|
|
352
|
+
return targets;
|
|
353
|
+
}
|
|
292
354
|
function resolveExtends(profilePath, options = {}) {
|
|
293
355
|
const diagnostics = { warnings: [], errors: [] };
|
|
294
356
|
const childProfile = loadProfileFile(profilePath);
|
|
295
|
-
|
|
357
|
+
const extendsTargets = normalizeExtendsTargets(childProfile?.extends);
|
|
358
|
+
if (!extendsTargets || extendsTargets.length === 0) {
|
|
296
359
|
return {
|
|
297
360
|
profile: childProfile,
|
|
298
361
|
parentPath: null,
|
|
362
|
+
parentPaths: [],
|
|
363
|
+
parentProfile: null,
|
|
299
364
|
diagnostics
|
|
300
365
|
};
|
|
301
366
|
}
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
367
|
+
const parentPaths = [];
|
|
368
|
+
let mergedParent = null;
|
|
369
|
+
for (const extendsName of extendsTargets) {
|
|
370
|
+
const parentPath = resolveParentPath(profilePath, extendsName, options);
|
|
371
|
+
if (!parentPath) {
|
|
372
|
+
diagnostics.errors.push({
|
|
373
|
+
code: "E_RESOLVE_EXTENDS",
|
|
374
|
+
severity: "error",
|
|
375
|
+
message: `Unable to resolve parent profile "${extendsName}".`
|
|
376
|
+
});
|
|
377
|
+
return {
|
|
378
|
+
profile: childProfile,
|
|
379
|
+
parentPath: parentPaths[0] ?? null,
|
|
380
|
+
parentPaths,
|
|
381
|
+
parentProfile: null,
|
|
382
|
+
diagnostics
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
const parentProfile2 = loadProfileFile(parentPath);
|
|
386
|
+
if (parentProfile2?.extends) {
|
|
387
|
+
diagnostics.errors.push({
|
|
388
|
+
code: "E_EXTENDS_CHAIN",
|
|
389
|
+
severity: "error",
|
|
390
|
+
message: "extends chains are not supported in MVP."
|
|
391
|
+
});
|
|
392
|
+
return {
|
|
393
|
+
profile: childProfile,
|
|
394
|
+
parentPath: parentPaths[0] ?? parentPath,
|
|
395
|
+
parentPaths: [...parentPaths, parentPath],
|
|
396
|
+
parentProfile: null,
|
|
397
|
+
diagnostics
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
parentPaths.push(parentPath);
|
|
401
|
+
mergedParent = mergedParent ? mergeProfiles(mergedParent, parentProfile2) : parentProfile2;
|
|
310
402
|
}
|
|
311
|
-
const parentProfile =
|
|
312
|
-
if (parentProfile
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
403
|
+
const parentProfile = mergedParent;
|
|
404
|
+
if (!parentProfile) {
|
|
405
|
+
return {
|
|
406
|
+
profile: childProfile,
|
|
407
|
+
parentPath: null,
|
|
408
|
+
parentPaths: [],
|
|
409
|
+
parentProfile: null,
|
|
410
|
+
diagnostics
|
|
411
|
+
};
|
|
319
412
|
}
|
|
320
413
|
const merged = mergeProfiles(parentProfile, childProfile);
|
|
321
414
|
delete merged.extends;
|
|
322
|
-
return {
|
|
415
|
+
return {
|
|
416
|
+
profile: merged,
|
|
417
|
+
parentPath: parentPaths[0] ?? null,
|
|
418
|
+
parentPaths,
|
|
419
|
+
parentProfile,
|
|
420
|
+
diagnostics
|
|
421
|
+
};
|
|
323
422
|
}
|
|
324
423
|
|
|
325
424
|
// src/profile/normalize.ts
|
|
@@ -364,7 +463,7 @@ function resolveActiveContext(profile, context = {}) {
|
|
|
364
463
|
|
|
365
464
|
// src/validator/overspec.ts
|
|
366
465
|
function computeConstraintCount(profile) {
|
|
367
|
-
const behavioralRules =
|
|
466
|
+
const behavioralRules = normalizeRuleConstraints(profile?.behavioral_rules).length;
|
|
368
467
|
const preferredTerms = asArray(profile?.vocabulary?.preferred_terms).length;
|
|
369
468
|
const forbiddenTerms = asArray(profile?.vocabulary?.forbidden_terms).length;
|
|
370
469
|
const contextAdaptations = asArray(profile?.context_adaptations).length;
|
|
@@ -406,7 +505,7 @@ function checkOverspec(profile) {
|
|
|
406
505
|
|
|
407
506
|
// src/validator/schema.ts
|
|
408
507
|
var HUMOR_STYLES = ["none", "dry", "subtle-wit", "playful"];
|
|
409
|
-
var SUPPORTED_SCHEMAS = /* @__PURE__ */ new Set(["v1.4", "v1.5"]);
|
|
508
|
+
var SUPPORTED_SCHEMAS = /* @__PURE__ */ new Set(["v1.4", "v1.5", "v1.6"]);
|
|
410
509
|
var TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
411
510
|
"schema",
|
|
412
511
|
"meta",
|
|
@@ -438,6 +537,9 @@ function isString(value) {
|
|
|
438
537
|
function isStringArray(value) {
|
|
439
538
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
440
539
|
}
|
|
540
|
+
function isNonEmptyStringArray(value) {
|
|
541
|
+
return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && item.trim().length > 0);
|
|
542
|
+
}
|
|
441
543
|
function pushDiagnostic(target, code, message, location) {
|
|
442
544
|
target.push({
|
|
443
545
|
code,
|
|
@@ -463,6 +565,66 @@ function validateScalarField(parent, key, location, diagnostics) {
|
|
|
463
565
|
);
|
|
464
566
|
}
|
|
465
567
|
}
|
|
568
|
+
function validateRuleConstraintArray(value, field, diagnostics, options) {
|
|
569
|
+
if (!Array.isArray(value)) {
|
|
570
|
+
pushDiagnostic(
|
|
571
|
+
diagnostics,
|
|
572
|
+
"V001",
|
|
573
|
+
`Expected "${field}" to be an array`,
|
|
574
|
+
field
|
|
575
|
+
);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
value.forEach((entry, idx) => {
|
|
579
|
+
const location = `${field}[${idx}]`;
|
|
580
|
+
if (typeof entry === "string") return;
|
|
581
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
582
|
+
pushDiagnostic(
|
|
583
|
+
diagnostics,
|
|
584
|
+
"V001",
|
|
585
|
+
`Expected "${location}" to be a string or { rule, locked? } object`,
|
|
586
|
+
location
|
|
587
|
+
);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (!options.allowObjects) {
|
|
591
|
+
pushDiagnostic(
|
|
592
|
+
diagnostics,
|
|
593
|
+
"V001",
|
|
594
|
+
`Object rule entries in "${field}" require schema version "v1.6"`,
|
|
595
|
+
location
|
|
596
|
+
);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const ruleObject = entry;
|
|
600
|
+
for (const key of Object.keys(ruleObject)) {
|
|
601
|
+
if (key !== "rule" && key !== "locked") {
|
|
602
|
+
pushDiagnostic(
|
|
603
|
+
diagnostics,
|
|
604
|
+
"V001",
|
|
605
|
+
`Unknown key "${key}" in ${location}`,
|
|
606
|
+
`${location}.${key}`
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
if (!isString(ruleObject.rule)) {
|
|
611
|
+
pushDiagnostic(
|
|
612
|
+
diagnostics,
|
|
613
|
+
"V001",
|
|
614
|
+
`Expected "${location}.rule" to be a non-empty string`,
|
|
615
|
+
`${location}.rule`
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
if (ruleObject.locked != null && typeof ruleObject.locked !== "boolean") {
|
|
619
|
+
pushDiagnostic(
|
|
620
|
+
diagnostics,
|
|
621
|
+
"V001",
|
|
622
|
+
`Expected "${location}.locked" to be a boolean`,
|
|
623
|
+
`${location}.locked`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
466
628
|
function validateDimensionValue(value, dimension, location, dimensionsDiagnostics, rangeDiagnostics) {
|
|
467
629
|
if (typeof value === "string") {
|
|
468
630
|
if (!LEVEL_INDEX.has(value)) {
|
|
@@ -613,13 +775,25 @@ function validateSchema(profile) {
|
|
|
613
775
|
"schema"
|
|
614
776
|
);
|
|
615
777
|
}
|
|
616
|
-
if (profile.extends != null
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
778
|
+
if (profile.extends != null) {
|
|
779
|
+
const isStringExtends = isString(profile.extends);
|
|
780
|
+
const isArrayExtends = isNonEmptyStringArray(profile.extends);
|
|
781
|
+
if (!isStringExtends && !isArrayExtends) {
|
|
782
|
+
pushDiagnostic(
|
|
783
|
+
structureDiagnostics,
|
|
784
|
+
"V001",
|
|
785
|
+
`Expected "extends" to be a non-empty string or non-empty array of non-empty strings`,
|
|
786
|
+
"extends"
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
if (Array.isArray(profile.extends) && profile.schema !== "v1.6") {
|
|
790
|
+
pushDiagnostic(
|
|
791
|
+
structureDiagnostics,
|
|
792
|
+
"V001",
|
|
793
|
+
`Array "extends" requires schema version "v1.6"`,
|
|
794
|
+
"extends"
|
|
795
|
+
);
|
|
796
|
+
}
|
|
623
797
|
}
|
|
624
798
|
if (!isObject(profile.meta)) {
|
|
625
799
|
pushDiagnostic(structureDiagnostics, "V001", `Missing required "meta" section`, "meta");
|
|
@@ -745,20 +919,17 @@ function validateSchema(profile) {
|
|
|
745
919
|
}
|
|
746
920
|
}
|
|
747
921
|
}
|
|
748
|
-
if (profile.behavioral_rules != null
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
`Expected "behavioral_rules" to be an array of strings`,
|
|
753
|
-
"behavioral_rules"
|
|
754
|
-
);
|
|
922
|
+
if (profile.behavioral_rules != null) {
|
|
923
|
+
validateRuleConstraintArray(profile.behavioral_rules, "behavioral_rules", structureDiagnostics, {
|
|
924
|
+
allowObjects: profile.schema === "v1.6"
|
|
925
|
+
});
|
|
755
926
|
}
|
|
756
927
|
if (profile.capabilities != null) {
|
|
757
|
-
if (profile.schema !== "v1.5") {
|
|
928
|
+
if (profile.schema !== "v1.5" && profile.schema !== "v1.6") {
|
|
758
929
|
pushDiagnostic(
|
|
759
930
|
structureDiagnostics,
|
|
760
931
|
"V001",
|
|
761
|
-
`The "capabilities" section requires schema version "v1.5"`,
|
|
932
|
+
`The "capabilities" section requires schema version "v1.5" or "v1.6"`,
|
|
762
933
|
"capabilities"
|
|
763
934
|
);
|
|
764
935
|
}
|
|
@@ -788,13 +959,20 @@ function validateSchema(profile) {
|
|
|
788
959
|
"capabilities.tools"
|
|
789
960
|
);
|
|
790
961
|
}
|
|
791
|
-
if (
|
|
962
|
+
if (profile.capabilities.constraints == null) {
|
|
792
963
|
pushDiagnostic(
|
|
793
964
|
structureDiagnostics,
|
|
794
965
|
"V001",
|
|
795
|
-
`Expected "capabilities.constraints" to be an array
|
|
966
|
+
`Expected "capabilities.constraints" to be an array`,
|
|
796
967
|
"capabilities.constraints"
|
|
797
968
|
);
|
|
969
|
+
} else {
|
|
970
|
+
validateRuleConstraintArray(
|
|
971
|
+
profile.capabilities.constraints,
|
|
972
|
+
"capabilities.constraints",
|
|
973
|
+
structureDiagnostics,
|
|
974
|
+
{ allowObjects: profile.schema === "v1.6" }
|
|
975
|
+
);
|
|
798
976
|
}
|
|
799
977
|
if (!isObject(profile.capabilities.handoff)) {
|
|
800
978
|
pushDiagnostic(
|
|
@@ -1091,7 +1269,9 @@ function collectS001Candidates(profile) {
|
|
|
1091
1269
|
text: normalizeText(profile.identity.backstory)
|
|
1092
1270
|
});
|
|
1093
1271
|
}
|
|
1094
|
-
asArray(profile?.behavioral_rules).forEach((
|
|
1272
|
+
asArray(profile?.behavioral_rules).forEach((ruleEntry, idx) => {
|
|
1273
|
+
const rule = ruleConstraintText(ruleEntry);
|
|
1274
|
+
if (!rule) return;
|
|
1095
1275
|
candidates.push({
|
|
1096
1276
|
location: `behavioral_rules[${idx}]`,
|
|
1097
1277
|
text: normalizeText(rule)
|
|
@@ -1111,7 +1291,9 @@ function collectS001Candidates(profile) {
|
|
|
1111
1291
|
}
|
|
1112
1292
|
function collectS005Candidates(profile) {
|
|
1113
1293
|
const candidates = [];
|
|
1114
|
-
asArray(profile?.behavioral_rules).forEach((
|
|
1294
|
+
asArray(profile?.behavioral_rules).forEach((ruleEntry, idx) => {
|
|
1295
|
+
const rule = ruleConstraintText(ruleEntry);
|
|
1296
|
+
if (!rule) return;
|
|
1115
1297
|
candidates.push({
|
|
1116
1298
|
location: `behavioral_rules[${idx}]`,
|
|
1117
1299
|
text: normalizeText(rule)
|
|
@@ -1143,7 +1325,9 @@ function collectS005Candidates(profile) {
|
|
|
1143
1325
|
}
|
|
1144
1326
|
function collectS008Candidates(profile) {
|
|
1145
1327
|
const candidates = [];
|
|
1146
|
-
asArray(profile?.behavioral_rules).forEach((
|
|
1328
|
+
asArray(profile?.behavioral_rules).forEach((ruleEntry, idx) => {
|
|
1329
|
+
const rule = ruleConstraintText(ruleEntry);
|
|
1330
|
+
if (!rule) return;
|
|
1147
1331
|
candidates.push({
|
|
1148
1332
|
location: `behavioral_rules[${idx}]`,
|
|
1149
1333
|
text: normalizeText(rule)
|
|
@@ -1287,6 +1471,19 @@ function checkS006(parentProfile, childProfile, mergedProfile) {
|
|
|
1287
1471
|
severity: "warning",
|
|
1288
1472
|
message: "Explicit behavioral_rules_remove detected. Behavioral rules are safety-relevant."
|
|
1289
1473
|
});
|
|
1474
|
+
const lockedParentRules = new Set(
|
|
1475
|
+
normalizeRuleConstraints(parentProfile.behavioral_rules).filter((rule) => rule.locked).map((rule) => rule.rule)
|
|
1476
|
+
);
|
|
1477
|
+
const lockedRemovals = childBehavioralRemovals.filter(
|
|
1478
|
+
(rule) => lockedParentRules.has(rule)
|
|
1479
|
+
);
|
|
1480
|
+
if (lockedRemovals.length > 0) {
|
|
1481
|
+
diagnostics.push({
|
|
1482
|
+
code: "S006",
|
|
1483
|
+
severity: "error",
|
|
1484
|
+
message: `behavioral_rules_remove attempted to remove locked inherited rules: ${lockedRemovals.join("; ")}`
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1290
1487
|
}
|
|
1291
1488
|
if (childForbiddenRemovals.length) {
|
|
1292
1489
|
diagnostics.push({
|
|
@@ -1295,9 +1492,9 @@ function checkS006(parentProfile, childProfile, mergedProfile) {
|
|
|
1295
1492
|
message: "Explicit vocabulary.forbidden_terms_remove detected. Forbidden terms are safety-relevant."
|
|
1296
1493
|
});
|
|
1297
1494
|
}
|
|
1298
|
-
const parentBehavioralCount =
|
|
1495
|
+
const parentBehavioralCount = normalizeRuleConstraints(parentProfile.behavioral_rules).length;
|
|
1299
1496
|
const parentForbiddenCount = asArray(parentProfile?.vocabulary?.forbidden_terms).length;
|
|
1300
|
-
const mergedBehavioralCount =
|
|
1497
|
+
const mergedBehavioralCount = normalizeRuleConstraints(mergedProfile.behavioral_rules).length;
|
|
1301
1498
|
const mergedForbiddenCount = asArray(mergedProfile?.vocabulary?.forbidden_terms).length;
|
|
1302
1499
|
if (mergedBehavioralCount < parentBehavioralCount || mergedForbiddenCount < parentForbiddenCount) {
|
|
1303
1500
|
diagnostics.push({
|
|
@@ -1467,11 +1664,10 @@ function validateProfile(profilePath, options = {}) {
|
|
|
1467
1664
|
(diagnostic) => normalizeDiagnosticSeverity(diagnostic, "error")
|
|
1468
1665
|
);
|
|
1469
1666
|
let s006Diagnostics = [];
|
|
1470
|
-
if (resolvedErrors.length === 0 && resolved.
|
|
1667
|
+
if (resolvedErrors.length === 0 && resolved.parentProfile) {
|
|
1471
1668
|
try {
|
|
1472
1669
|
const childProfile = loadProfileFile(profilePath);
|
|
1473
|
-
|
|
1474
|
-
s006Diagnostics = checkS006(parentProfile, childProfile, resolved.profile);
|
|
1670
|
+
s006Diagnostics = checkS006(resolved.parentProfile, childProfile, resolved.profile);
|
|
1475
1671
|
} catch (error) {
|
|
1476
1672
|
s006Diagnostics = [
|
|
1477
1673
|
{
|
|
@@ -1833,7 +2029,7 @@ function renderPersonalityText(profile, model, contextResolution, compileOptions
|
|
|
1833
2029
|
lines.push(`Protected refusal terms (always available): ${PROTECTED_REFUSAL_TERMS.join("; ")}`);
|
|
1834
2030
|
lines.push("");
|
|
1835
2031
|
lines.push("[BEHAVIORAL RULES]");
|
|
1836
|
-
const rules =
|
|
2032
|
+
const rules = normalizeRuleConstraints(profile.behavioral_rules).map((entry) => entry.rule);
|
|
1837
2033
|
if (rules.length === 0) {
|
|
1838
2034
|
lines.push("- (none)");
|
|
1839
2035
|
} else {
|
|
@@ -1841,10 +2037,12 @@ function renderPersonalityText(profile, model, contextResolution, compileOptions
|
|
|
1841
2037
|
lines.push(`- ${rule}`);
|
|
1842
2038
|
}
|
|
1843
2039
|
}
|
|
1844
|
-
if (profile.schema === "v1.5" && profile.capabilities) {
|
|
2040
|
+
if ((profile.schema === "v1.5" || profile.schema === "v1.6") && profile.capabilities) {
|
|
1845
2041
|
const capabilities = profile.capabilities;
|
|
1846
2042
|
const tools = asArray(capabilities.tools);
|
|
1847
|
-
const constraints =
|
|
2043
|
+
const constraints = normalizeRuleConstraints(capabilities.constraints).map(
|
|
2044
|
+
(entry) => entry.rule
|
|
2045
|
+
);
|
|
1848
2046
|
lines.push("");
|
|
1849
2047
|
lines.push("[CAPABILITY BOUNDARIES]");
|
|
1850
2048
|
lines.push(
|
|
@@ -2138,7 +2336,7 @@ function evaluateTier1Response(profile, responseText, options = {}) {
|
|
|
2138
2336
|
forbidden_matched: forbiddenMatches,
|
|
2139
2337
|
pass: forbiddenMatches === 0
|
|
2140
2338
|
};
|
|
2141
|
-
const behavioralRules =
|
|
2339
|
+
const behavioralRules = normalizeRuleConstraints(profile?.behavioral_rules);
|
|
2142
2340
|
const structureCheck = {
|
|
2143
2341
|
behavioral_rule_count: behavioralRules.length,
|
|
2144
2342
|
response_non_empty: response.trim().length > 0,
|
|
@@ -2820,7 +3018,9 @@ function buildJudgeUserPrompt(profile, sample) {
|
|
|
2820
3018
|
const targets = collectVoiceTargets(profile);
|
|
2821
3019
|
const preferredTerms = asArray(profile?.vocabulary?.preferred_terms);
|
|
2822
3020
|
const forbiddenTerms = asArray(profile?.vocabulary?.forbidden_terms);
|
|
2823
|
-
const behavioralRules =
|
|
3021
|
+
const behavioralRules = normalizeRuleConstraints(profile?.behavioral_rules).map(
|
|
3022
|
+
(entry) => entry.rule
|
|
3023
|
+
);
|
|
2824
3024
|
return [
|
|
2825
3025
|
`Profile: ${profile?.meta?.name ?? "unknown"}`,
|
|
2826
3026
|
`Role: ${profile?.identity?.role ?? "assistant"}`,
|
package/dist/index.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as CapabilityHandoff, c as CompileOptions, d as CompiledPersonality, e as ContextAdaptation, f as ContextResolution, D as DimensionName, g as DimensionObject, h as DimensionShorthand, i as DimensionValue,
|
|
1
|
+
export { C as CapabilityHandoff, c as CompileOptions, d as CompiledPersonality, e as ContextAdaptation, f as ContextResolution, D as DimensionName, g as DimensionObject, h as DimensionShorthand, i as DimensionValue, j as EvalSample, k as ExtendsDiagnostics, l as ExtendsResult, H as HumorDimensionObject, m as HumorDimensionValue, n as HumorStyle, I as ImportOptions, L as Level, o as LockedRule, P as PersonalityProfile, p as ProfileCapabilities, R as RuleConstraint, T as Tier1Options, q as Tier2Options, s as Tier3Options, b as ValidationDiagnostic, V as ValidationResult, t as VocabularyConstraints, u as compileProfile, v as compileResolvedProfile, w as evaluateTier1Response, x as injectPersonality, y as loadProfileFile, A as normalizeProfile, F as resolveActiveContext, G as resolveExtends, J as runImportAnalysis, r as runTier1Evaluation, K as runTier1EvaluationForProfile, M as runTier2Evaluation, N as runTier2EvaluationForProfile, O as runTier3Evaluation, Q as runTier3EvaluationForProfile, S as validateEvalScenario, U as validateEvalScenarios, W as validateProfile, X as validateResolvedProfile } from './index-Ct4kuPk7.cjs';
|