@forwardimpact/model 0.5.0 → 0.7.1

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/lib/profile.js DELETED
@@ -1,262 +0,0 @@
1
- /**
2
- * Unified Profile Derivation
3
- *
4
- * Shared functions for deriving skill and behaviour profiles for both
5
- * human jobs and AI agents. This module provides:
6
- *
7
- * 1. Filtering functions - reusable filters for skills and behaviours
8
- * 2. Sorting functions - sort by level/maturity for display
9
- * 3. prepareBaseProfile() - shared profile derivation used by both job.js and agent.js
10
- *
11
- * The core derivation (deriveSkillMatrix, deriveBehaviourProfile) remains in
12
- * derivation.js. This module adds post-processing for specific use cases.
13
- *
14
- * Agent filtering keeps only skills at the highest derived level. This ensures
15
- * track modifiers are respected—a broad skill boosted by a +1 track modifier
16
- * may reach the same level as primary skills and thus be included.
17
- */
18
-
19
- import {
20
- SKILL_LEVEL_ORDER,
21
- BEHAVIOUR_MATURITY_ORDER,
22
- } from "@forwardimpact/schema/levels";
23
- import {
24
- deriveSkillMatrix,
25
- deriveBehaviourProfile,
26
- deriveResponsibilities,
27
- } from "./derivation.js";
28
-
29
- // =============================================================================
30
- // Skill Filters
31
- // =============================================================================
32
-
33
- /**
34
- * Build set of capabilities with positive track modifiers
35
- * @param {Object} track - Track definition
36
- * @returns {Set<string>} Set of capability IDs with positive modifiers
37
- */
38
- export function getPositiveTrackCapabilities(track) {
39
- return new Set(
40
- Object.entries(track.skillModifiers || {})
41
- .filter(([_, modifier]) => modifier > 0)
42
- .map(([capability]) => capability),
43
- );
44
- }
45
-
46
- /**
47
- * Filter out human-only skills
48
- * Human-only skills are those requiring human presence/experience
49
- * @param {Array} skillMatrix - Skill matrix entries
50
- * @returns {Array} Filtered skill matrix
51
- */
52
- export function filterHumanOnlySkills(skillMatrix) {
53
- return skillMatrix.filter((entry) => !entry.isHumanOnly);
54
- }
55
-
56
- /**
57
- * Filter skills to keep only those at the highest derived level
58
- * After track modifiers are applied, some skills will be at higher levels
59
- * than others. This filter keeps only the skills at the maximum level.
60
- * @param {Array} skillMatrix - Skill matrix entries with derived levels
61
- * @returns {Array} Filtered skill matrix containing only highest-level skills
62
- */
63
- export function filterByHighestLevel(skillMatrix) {
64
- if (skillMatrix.length === 0) return [];
65
-
66
- // Find the highest level index in the matrix
67
- const maxLevelIndex = Math.max(
68
- ...skillMatrix.map((entry) => SKILL_LEVEL_ORDER.indexOf(entry.level)),
69
- );
70
-
71
- // Keep only skills at that level
72
- return skillMatrix.filter(
73
- (entry) => SKILL_LEVEL_ORDER.indexOf(entry.level) === maxLevelIndex,
74
- );
75
- }
76
-
77
- /**
78
- * Apply agent-specific skill filters
79
- * Filters to human-only skills and keeps only skills at the highest derived level.
80
- * This approach respects track modifiers—a broad skill boosted to the same level
81
- * as primary skills will be included.
82
- * @param {Array} skillMatrix - Skill matrix entries with derived levels
83
- * @returns {Array} Filtered skill matrix
84
- */
85
- export function filterSkillsForAgent(skillMatrix) {
86
- // First exclude human-only skills
87
- const withoutHumanOnly = filterHumanOnlySkills(skillMatrix);
88
-
89
- // Then keep only skills at the highest level
90
- return filterByHighestLevel(withoutHumanOnly);
91
- }
92
-
93
- // =============================================================================
94
- // Sorting Functions
95
- // =============================================================================
96
-
97
- /**
98
- * Sort skills by level (highest first)
99
- * Used for agent profiles where top skills should appear first
100
- * @param {Array} skillMatrix - Skill matrix entries
101
- * @returns {Array} Sorted skill matrix (new array)
102
- */
103
- export function sortByLevelDescending(skillMatrix) {
104
- return [...skillMatrix].sort((a, b) => {
105
- const aIndex = SKILL_LEVEL_ORDER.indexOf(a.level);
106
- const bIndex = SKILL_LEVEL_ORDER.indexOf(b.level);
107
- return bIndex - aIndex;
108
- });
109
- }
110
-
111
- /**
112
- * Sort behaviours by maturity (highest first)
113
- * Used for agent profiles where top behaviours should appear first
114
- * @param {Array} behaviourProfile - Behaviour profile entries
115
- * @returns {Array} Sorted behaviour profile (new array)
116
- */
117
- export function sortByMaturityDescending(behaviourProfile) {
118
- return [...behaviourProfile].sort((a, b) => {
119
- const aIndex = BEHAVIOUR_MATURITY_ORDER.indexOf(a.maturity);
120
- const bIndex = BEHAVIOUR_MATURITY_ORDER.indexOf(b.maturity);
121
- return bIndex - aIndex;
122
- });
123
- }
124
-
125
- // =============================================================================
126
- // Profile Derivation
127
- // =============================================================================
128
-
129
- /**
130
- * @typedef {Object} ProfileOptions
131
- * @property {boolean} [excludeHumanOnly=false] - Filter out human-only skills
132
- * @property {boolean} [keepHighestLevelOnly=false] - Keep only skills at the highest derived level
133
- * @property {boolean} [sortByLevel=false] - Sort skills by level descending
134
- * @property {boolean} [sortByMaturity=false] - Sort behaviours by maturity descending
135
- */
136
-
137
- /**
138
- * @typedef {Object} BaseProfile
139
- * @property {Array} skillMatrix - Derived skill matrix
140
- * @property {Array} behaviourProfile - Derived behaviour profile
141
- * @property {Array} derivedResponsibilities - Derived responsibilities (if capabilities provided)
142
- * @property {Object} discipline - The discipline
143
- * @property {Object} track - The track
144
- * @property {Object} grade - The grade
145
- */
146
-
147
- /**
148
- * Prepare a base profile shared by jobs and agents
149
- *
150
- * This is the unified entry point for profile derivation. Both human jobs
151
- * and AI agents use this function, with different options:
152
- *
153
- * - Human jobs: No filtering, default sorting by type
154
- * - AI agents: Filter humanOnly, keep only highest-level skills, sort by level
155
- *
156
- * @param {Object} params
157
- * @param {Object} params.discipline - The discipline
158
- * @param {Object} params.track - The track
159
- * @param {Object} params.grade - The grade
160
- * @param {Array} params.skills - All available skills
161
- * @param {Array} params.behaviours - All available behaviours
162
- * @param {Array} [params.capabilities] - Optional capabilities for responsibility derivation
163
- * @param {ProfileOptions} [params.options={}] - Filtering and sorting options
164
- * @returns {BaseProfile} The prepared profile
165
- */
166
- export function prepareBaseProfile({
167
- discipline,
168
- track,
169
- grade,
170
- skills,
171
- behaviours,
172
- capabilities,
173
- options = {},
174
- }) {
175
- const {
176
- excludeHumanOnly = false,
177
- keepHighestLevelOnly = false,
178
- sortByLevel = false,
179
- sortByMaturity = false,
180
- } = options;
181
-
182
- // Core derivation
183
- let skillMatrix = deriveSkillMatrix({ discipline, grade, track, skills });
184
- let behaviourProfile = deriveBehaviourProfile({
185
- discipline,
186
- grade,
187
- track,
188
- behaviours,
189
- });
190
-
191
- // Apply skill filters
192
- if (excludeHumanOnly) {
193
- skillMatrix = filterHumanOnlySkills(skillMatrix);
194
- }
195
- if (keepHighestLevelOnly) {
196
- skillMatrix = filterByHighestLevel(skillMatrix);
197
- }
198
-
199
- // Apply sorting
200
- if (sortByLevel) {
201
- skillMatrix = sortByLevelDescending(skillMatrix);
202
- }
203
- if (sortByMaturity) {
204
- behaviourProfile = sortByMaturityDescending(behaviourProfile);
205
- }
206
-
207
- // Derive responsibilities if capabilities provided
208
- let derivedResponsibilities = [];
209
- if (capabilities && capabilities.length > 0) {
210
- derivedResponsibilities = deriveResponsibilities({
211
- skillMatrix,
212
- capabilities,
213
- track,
214
- });
215
- }
216
-
217
- return {
218
- skillMatrix,
219
- behaviourProfile,
220
- derivedResponsibilities,
221
- discipline,
222
- track,
223
- grade,
224
- };
225
- }
226
-
227
- /**
228
- * Preset options for agent profile derivation
229
- * Excludes human-only skills, keeps only skills at the highest derived level,
230
- * and sorts by level/maturity descending
231
- */
232
- export const AGENT_PROFILE_OPTIONS = {
233
- excludeHumanOnly: true,
234
- keepHighestLevelOnly: true,
235
- sortByLevel: true,
236
- sortByMaturity: true,
237
- };
238
-
239
- /**
240
- * Prepare a profile optimized for agent generation
241
- * Convenience function that applies AGENT_PROFILE_OPTIONS
242
- * @param {Object} params - Same as prepareBaseProfile, without options
243
- * @returns {BaseProfile} The prepared profile
244
- */
245
- export function prepareAgentProfile({
246
- discipline,
247
- track,
248
- grade,
249
- skills,
250
- behaviours,
251
- capabilities,
252
- }) {
253
- return prepareBaseProfile({
254
- discipline,
255
- track,
256
- grade,
257
- skills,
258
- behaviours,
259
- capabilities,
260
- options: AGENT_PROFILE_OPTIONS,
261
- });
262
- }
File without changes