holomime 1.0.0 → 1.1.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/README.md +160 -97
- package/dist/cli.js +2125 -325
- package/dist/index.d.ts +1770 -173
- package/dist/index.js +1726 -158
- package/dist/mcp-server.js +404 -93
- package/package.json +21 -6
package/dist/index.js
CHANGED
|
@@ -1,46 +1,212 @@
|
|
|
1
1
|
// src/core/types.ts
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/core/embodiment-types.ts
|
|
2
5
|
import { z } from "zod";
|
|
3
|
-
var
|
|
6
|
+
var modalitySchema = z.enum([
|
|
7
|
+
"gesture",
|
|
8
|
+
// arm/hand movement
|
|
9
|
+
"locomotion",
|
|
10
|
+
// walking, wheeling, navigating
|
|
11
|
+
"gaze",
|
|
12
|
+
// eye tracking, head orientation
|
|
13
|
+
"facial",
|
|
14
|
+
// facial expression actuators
|
|
15
|
+
"voice",
|
|
16
|
+
// prosody, volume, rate (not content)
|
|
17
|
+
"haptic",
|
|
18
|
+
// touch-based interaction
|
|
19
|
+
"posture",
|
|
20
|
+
// full-body orientation/lean
|
|
21
|
+
"manipulation"
|
|
22
|
+
// grasping, carrying, tool use
|
|
23
|
+
]);
|
|
24
|
+
var morphologySchema = z.enum([
|
|
25
|
+
"humanoid",
|
|
26
|
+
// bipedal, two arms, head
|
|
27
|
+
"humanoid_upper",
|
|
28
|
+
// torso-up only (desk robot, mounted)
|
|
29
|
+
"quadruped",
|
|
30
|
+
// four-legged
|
|
31
|
+
"wheeled",
|
|
32
|
+
// mobile base with upper body
|
|
33
|
+
"fixed",
|
|
34
|
+
// stationary (kiosk, screen + arm)
|
|
35
|
+
"swarm_unit",
|
|
36
|
+
// one node of a multi-body system
|
|
37
|
+
"avatar",
|
|
38
|
+
// virtual 3D body (no physical actuators)
|
|
39
|
+
"custom"
|
|
40
|
+
// user-defined
|
|
41
|
+
]);
|
|
42
|
+
var safetyEnvelopeSchema = z.object({
|
|
43
|
+
max_linear_speed_m_s: z.number().min(0).default(1.5),
|
|
44
|
+
max_angular_speed_rad_s: z.number().min(0).default(2),
|
|
45
|
+
min_proximity_m: z.number().min(0).default(0.3),
|
|
46
|
+
max_contact_force_n: z.number().min(0).default(10),
|
|
47
|
+
emergency_stop_decel_m_s2: z.number().min(0).default(5),
|
|
48
|
+
max_reach_m: z.number().min(0).optional(),
|
|
49
|
+
operating_temperature_c: z.tuple([z.number(), z.number()]).optional()
|
|
50
|
+
});
|
|
51
|
+
var embodimentSchema = z.object({
|
|
52
|
+
morphology: morphologySchema.default("humanoid"),
|
|
53
|
+
modalities: z.array(modalitySchema).default(["gesture", "gaze", "voice", "posture"]),
|
|
54
|
+
safety_envelope: safetyEnvelopeSchema.default({}),
|
|
55
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
56
|
+
});
|
|
57
|
+
var gazePolicySchema = z.object({
|
|
58
|
+
contact_ratio: z.number().min(0).max(1).default(0.6),
|
|
59
|
+
aversion_style: z.enum(["look_down", "look_away", "blink"]).default("look_away"),
|
|
60
|
+
tracking_mode: z.enum(["face", "speaker", "gesture_follow", "ambient"]).default("face")
|
|
61
|
+
});
|
|
62
|
+
var proxemicZoneSchema = z.object({
|
|
63
|
+
intimate_m: z.number().min(0).default(0.45),
|
|
64
|
+
personal_m: z.number().min(0).default(1.2),
|
|
65
|
+
social_m: z.number().min(0).default(3.6),
|
|
66
|
+
preferred_zone: z.enum(["intimate", "personal", "social", "adaptive"]).default("personal")
|
|
67
|
+
});
|
|
68
|
+
var hapticPolicySchema = z.object({
|
|
69
|
+
touch_permitted: z.boolean().default(false),
|
|
70
|
+
requires_consent: z.boolean().default(true),
|
|
71
|
+
allowed_contacts: z.array(z.enum([
|
|
72
|
+
"handshake",
|
|
73
|
+
"shoulder_tap",
|
|
74
|
+
"high_five",
|
|
75
|
+
"guide_touch",
|
|
76
|
+
"none"
|
|
77
|
+
])).default(["none"]),
|
|
78
|
+
max_force_n: z.number().min(0).optional()
|
|
79
|
+
});
|
|
80
|
+
var prosodySchema = z.object({
|
|
81
|
+
base_pitch_hz: z.number().optional(),
|
|
82
|
+
pitch_variation: z.number().min(0).max(1).default(0.5),
|
|
83
|
+
speaking_rate_wpm: z.number().default(150),
|
|
84
|
+
volume_db_offset: z.number().default(0),
|
|
85
|
+
pause_tendency: z.number().min(0).max(1).default(0.5)
|
|
86
|
+
});
|
|
87
|
+
var gestureSchema = z.object({
|
|
88
|
+
id: z.string(),
|
|
89
|
+
category: z.enum(["conversational", "emphatic", "deictic", "regulatory", "adaptive"]),
|
|
90
|
+
modalities: z.array(modalitySchema),
|
|
91
|
+
intensity_range: z.tuple([
|
|
92
|
+
z.number().min(0).max(1),
|
|
93
|
+
z.number().min(0).max(1)
|
|
94
|
+
]).default([0.3, 0.8]),
|
|
95
|
+
requires_consent: z.boolean().default(false)
|
|
96
|
+
});
|
|
97
|
+
var expressionSchema = z.object({
|
|
98
|
+
gesture_vocabulary: z.array(gestureSchema).default([]),
|
|
99
|
+
gaze: gazePolicySchema.default({}),
|
|
100
|
+
proxemics: proxemicZoneSchema.default({}),
|
|
101
|
+
haptics: hapticPolicySchema.default({}),
|
|
102
|
+
prosody: prosodySchema.default({}),
|
|
103
|
+
facial_expressiveness: z.number().min(0).max(1).default(0.5)
|
|
104
|
+
});
|
|
105
|
+
var physicalSafetySchema = z.object({
|
|
106
|
+
hard_limits: z.array(z.string()).default([
|
|
107
|
+
"Never exceed safety_envelope speeds",
|
|
108
|
+
"Never exceed max_contact_force_n",
|
|
109
|
+
"Emergency stop on unrecognized obstacle within min_proximity_m"
|
|
110
|
+
]),
|
|
111
|
+
require_consent_for: z.array(z.string()).default([
|
|
112
|
+
"haptic_contact",
|
|
113
|
+
"intimate_zone_entry"
|
|
114
|
+
]),
|
|
115
|
+
collision_response: z.enum(["stop", "retreat", "freeze"]).default("stop"),
|
|
116
|
+
unattended_policy: z.enum(["idle", "return_home", "shutdown"]).default("idle")
|
|
117
|
+
});
|
|
118
|
+
var motionParametersSchema = z.object({
|
|
119
|
+
// Speeds (normalized 0-1, scaled by safety_envelope at runtime)
|
|
120
|
+
base_speed: z.number().min(0).max(1),
|
|
121
|
+
gesture_speed: z.number().min(0).max(1),
|
|
122
|
+
gesture_amplitude: z.number().min(0).max(1),
|
|
123
|
+
gesture_frequency: z.number().min(0).max(1),
|
|
124
|
+
// Spatial
|
|
125
|
+
approach_distance: z.number().min(0).max(1),
|
|
126
|
+
spatial_exploration: z.number().min(0).max(1),
|
|
127
|
+
// Smoothness
|
|
128
|
+
movement_smoothness: z.number().min(0).max(1),
|
|
129
|
+
trajectory_variability: z.number().min(0).max(1),
|
|
130
|
+
// Timing
|
|
131
|
+
response_latency: z.number().min(0).max(1),
|
|
132
|
+
idle_animation_frequency: z.number().min(0).max(1),
|
|
133
|
+
// Social
|
|
134
|
+
gaze_contact_ratio: z.number().min(0).max(1),
|
|
135
|
+
head_tilt_tendency: z.number().min(0).max(1),
|
|
136
|
+
postural_openness: z.number().min(0).max(1),
|
|
137
|
+
smile_frequency: z.number().min(0).max(1),
|
|
138
|
+
// Voice prosody
|
|
139
|
+
voice_volume: z.number().min(0).max(1),
|
|
140
|
+
speaking_rate: z.number().min(0).max(1),
|
|
141
|
+
pitch_variation: z.number().min(0).max(1),
|
|
142
|
+
pause_duration: z.number().min(0).max(1)
|
|
143
|
+
});
|
|
144
|
+
var compiledEmbodiedConfigSchema = z.object({
|
|
145
|
+
// Base compiled config fields (duplicated to avoid circular import with types.ts)
|
|
146
|
+
provider: z.string(),
|
|
147
|
+
surface: z.literal("embodied"),
|
|
148
|
+
system_prompt: z.string(),
|
|
149
|
+
temperature: z.number().min(0).max(2),
|
|
150
|
+
top_p: z.number().min(0).max(1),
|
|
151
|
+
max_tokens: z.number().int().positive(),
|
|
152
|
+
metadata: z.object({
|
|
153
|
+
personality_hash: z.string(),
|
|
154
|
+
compiled_at: z.string(),
|
|
155
|
+
holomime_version: z.string()
|
|
156
|
+
}),
|
|
157
|
+
// Embodied-specific fields
|
|
158
|
+
motion_parameters: motionParametersSchema,
|
|
159
|
+
safety_envelope: safetyEnvelopeSchema,
|
|
160
|
+
active_modalities: z.array(modalitySchema),
|
|
161
|
+
gesture_vocabulary: z.array(z.string()),
|
|
162
|
+
prosody: prosodySchema,
|
|
163
|
+
gaze: gazePolicySchema,
|
|
164
|
+
proxemics: proxemicZoneSchema,
|
|
165
|
+
haptics: hapticPolicySchema
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// src/core/types.ts
|
|
169
|
+
var bigFiveDimensionSchema = z2.enum([
|
|
4
170
|
"openness",
|
|
5
171
|
"conscientiousness",
|
|
6
172
|
"extraversion",
|
|
7
173
|
"agreeableness",
|
|
8
174
|
"emotional_stability"
|
|
9
175
|
]);
|
|
10
|
-
var traitScore =
|
|
11
|
-
var opennessFacetsSchema =
|
|
176
|
+
var traitScore = z2.number().min(0).max(1);
|
|
177
|
+
var opennessFacetsSchema = z2.object({
|
|
12
178
|
imagination: traitScore,
|
|
13
179
|
intellectual_curiosity: traitScore,
|
|
14
180
|
aesthetic_sensitivity: traitScore,
|
|
15
181
|
willingness_to_experiment: traitScore
|
|
16
182
|
});
|
|
17
|
-
var conscientiousnessFacetsSchema =
|
|
183
|
+
var conscientiousnessFacetsSchema = z2.object({
|
|
18
184
|
self_discipline: traitScore,
|
|
19
185
|
orderliness: traitScore,
|
|
20
186
|
goal_orientation: traitScore,
|
|
21
187
|
attention_to_detail: traitScore
|
|
22
188
|
});
|
|
23
|
-
var extraversionFacetsSchema =
|
|
189
|
+
var extraversionFacetsSchema = z2.object({
|
|
24
190
|
assertiveness: traitScore,
|
|
25
191
|
enthusiasm: traitScore,
|
|
26
192
|
sociability: traitScore,
|
|
27
193
|
initiative: traitScore
|
|
28
194
|
});
|
|
29
|
-
var agreeablenessFacetsSchema =
|
|
195
|
+
var agreeablenessFacetsSchema = z2.object({
|
|
30
196
|
warmth: traitScore,
|
|
31
197
|
empathy: traitScore,
|
|
32
198
|
cooperation: traitScore,
|
|
33
199
|
trust_tendency: traitScore
|
|
34
200
|
});
|
|
35
|
-
var emotionalStabilityFacetsSchema =
|
|
201
|
+
var emotionalStabilityFacetsSchema = z2.object({
|
|
36
202
|
stress_tolerance: traitScore,
|
|
37
203
|
emotional_regulation: traitScore,
|
|
38
204
|
confidence: traitScore,
|
|
39
205
|
adaptability: traitScore
|
|
40
206
|
});
|
|
41
|
-
var bigFiveTraitSchema =
|
|
207
|
+
var bigFiveTraitSchema = z2.object({
|
|
42
208
|
score: traitScore,
|
|
43
|
-
facets:
|
|
209
|
+
facets: z2.union([
|
|
44
210
|
opennessFacetsSchema,
|
|
45
211
|
conscientiousnessFacetsSchema,
|
|
46
212
|
extraversionFacetsSchema,
|
|
@@ -48,16 +214,16 @@ var bigFiveTraitSchema = z.object({
|
|
|
48
214
|
emotionalStabilityFacetsSchema
|
|
49
215
|
])
|
|
50
216
|
});
|
|
51
|
-
var bigFiveSchema =
|
|
52
|
-
openness:
|
|
53
|
-
conscientiousness:
|
|
54
|
-
extraversion:
|
|
55
|
-
agreeableness:
|
|
56
|
-
emotional_stability:
|
|
217
|
+
var bigFiveSchema = z2.object({
|
|
218
|
+
openness: z2.object({ score: traitScore, facets: opennessFacetsSchema }),
|
|
219
|
+
conscientiousness: z2.object({ score: traitScore, facets: conscientiousnessFacetsSchema }),
|
|
220
|
+
extraversion: z2.object({ score: traitScore, facets: extraversionFacetsSchema }),
|
|
221
|
+
agreeableness: z2.object({ score: traitScore, facets: agreeablenessFacetsSchema }),
|
|
222
|
+
emotional_stability: z2.object({ score: traitScore, facets: emotionalStabilityFacetsSchema })
|
|
57
223
|
});
|
|
58
|
-
var attachmentStyleSchema =
|
|
59
|
-
var learningOrientationSchema =
|
|
60
|
-
var therapyDimensionsSchema =
|
|
224
|
+
var attachmentStyleSchema = z2.enum(["secure", "anxious", "avoidant", "disorganized"]);
|
|
225
|
+
var learningOrientationSchema = z2.enum(["growth", "fixed", "mixed"]);
|
|
226
|
+
var therapyDimensionsSchema = z2.object({
|
|
61
227
|
self_awareness: traitScore,
|
|
62
228
|
distress_tolerance: traitScore,
|
|
63
229
|
attachment_style: attachmentStyleSchema,
|
|
@@ -65,28 +231,28 @@ var therapyDimensionsSchema = z.object({
|
|
|
65
231
|
boundary_awareness: traitScore,
|
|
66
232
|
interpersonal_sensitivity: traitScore
|
|
67
233
|
});
|
|
68
|
-
var registerSchema =
|
|
234
|
+
var registerSchema = z2.enum([
|
|
69
235
|
"casual_professional",
|
|
70
236
|
"formal",
|
|
71
237
|
"conversational",
|
|
72
238
|
"adaptive"
|
|
73
239
|
]);
|
|
74
|
-
var outputFormatSchema =
|
|
75
|
-
var emojiPolicySchema =
|
|
76
|
-
var reasoningTransparencySchema =
|
|
77
|
-
var conflictApproachSchema =
|
|
240
|
+
var outputFormatSchema = z2.enum(["prose", "bullets", "mixed", "structured"]);
|
|
241
|
+
var emojiPolicySchema = z2.enum(["never", "sparingly", "freely"]);
|
|
242
|
+
var reasoningTransparencySchema = z2.enum(["hidden", "on_request", "always"]);
|
|
243
|
+
var conflictApproachSchema = z2.enum([
|
|
78
244
|
"direct_but_kind",
|
|
79
245
|
"curious_first",
|
|
80
246
|
"supportive_then_honest",
|
|
81
247
|
"diplomatic"
|
|
82
248
|
]);
|
|
83
|
-
var uncertaintyHandlingSchema =
|
|
249
|
+
var uncertaintyHandlingSchema = z2.enum([
|
|
84
250
|
"transparent",
|
|
85
251
|
"confident_transparency",
|
|
86
252
|
"minimize",
|
|
87
253
|
"reframe"
|
|
88
254
|
]);
|
|
89
|
-
var communicationSchema =
|
|
255
|
+
var communicationSchema = z2.object({
|
|
90
256
|
register: registerSchema.default("casual_professional"),
|
|
91
257
|
output_format: outputFormatSchema.default("mixed"),
|
|
92
258
|
emoji_policy: emojiPolicySchema.default("sparingly"),
|
|
@@ -94,69 +260,73 @@ var communicationSchema = z.object({
|
|
|
94
260
|
conflict_approach: conflictApproachSchema.default("direct_but_kind"),
|
|
95
261
|
uncertainty_handling: uncertaintyHandlingSchema.default("transparent")
|
|
96
262
|
});
|
|
97
|
-
var domainSchema =
|
|
98
|
-
expertise:
|
|
99
|
-
boundaries:
|
|
100
|
-
refuses:
|
|
101
|
-
escalation_triggers:
|
|
102
|
-
hard_limits:
|
|
263
|
+
var domainSchema = z2.object({
|
|
264
|
+
expertise: z2.array(z2.string()).default([]),
|
|
265
|
+
boundaries: z2.object({
|
|
266
|
+
refuses: z2.array(z2.string()).default([]),
|
|
267
|
+
escalation_triggers: z2.array(z2.string()).default([]),
|
|
268
|
+
hard_limits: z2.array(z2.string()).default([]),
|
|
269
|
+
physical_safety: physicalSafetySchema.optional()
|
|
103
270
|
}).default({})
|
|
104
271
|
});
|
|
105
|
-
var growthAreaSchema =
|
|
106
|
-
area:
|
|
107
|
-
severity:
|
|
108
|
-
first_detected:
|
|
109
|
-
session_count:
|
|
110
|
-
resolved:
|
|
272
|
+
var growthAreaSchema = z2.object({
|
|
273
|
+
area: z2.string(),
|
|
274
|
+
severity: z2.enum(["mild", "moderate", "significant"]),
|
|
275
|
+
first_detected: z2.string().optional(),
|
|
276
|
+
session_count: z2.number().default(0),
|
|
277
|
+
resolved: z2.boolean().default(false)
|
|
111
278
|
});
|
|
112
|
-
var growthSchema =
|
|
113
|
-
areas:
|
|
114
|
-
patterns_to_watch:
|
|
115
|
-
strengths:
|
|
279
|
+
var growthSchema = z2.object({
|
|
280
|
+
areas: z2.union([z2.array(z2.string()), z2.array(growthAreaSchema)]).default([]),
|
|
281
|
+
patterns_to_watch: z2.array(z2.string()).default([]),
|
|
282
|
+
strengths: z2.array(z2.string()).default([])
|
|
116
283
|
});
|
|
117
|
-
var providerSchema =
|
|
118
|
-
var surfaceSchema =
|
|
119
|
-
var personalitySpecSchema =
|
|
120
|
-
$schema:
|
|
121
|
-
extends:
|
|
122
|
-
version:
|
|
123
|
-
name:
|
|
124
|
-
handle:
|
|
125
|
-
purpose:
|
|
284
|
+
var providerSchema = z2.enum(["anthropic", "openai", "gemini", "ollama"]);
|
|
285
|
+
var surfaceSchema = z2.enum(["chat", "email", "code_review", "slack", "api", "embodied"]);
|
|
286
|
+
var personalitySpecSchema = z2.object({
|
|
287
|
+
$schema: z2.string().optional(),
|
|
288
|
+
extends: z2.string().optional(),
|
|
289
|
+
version: z2.literal("2.0"),
|
|
290
|
+
name: z2.string().min(1).max(100),
|
|
291
|
+
handle: z2.string().min(3).max(50).regex(/^[a-z0-9-]+$/, "Handle must be lowercase alphanumeric with hyphens"),
|
|
292
|
+
purpose: z2.string().max(500).optional(),
|
|
126
293
|
big_five: bigFiveSchema,
|
|
127
294
|
therapy_dimensions: therapyDimensionsSchema,
|
|
128
295
|
communication: communicationSchema.default({}),
|
|
129
296
|
domain: domainSchema.default({}),
|
|
130
|
-
growth: growthSchema.default({})
|
|
297
|
+
growth: growthSchema.default({}),
|
|
298
|
+
// ─── Embodiment (optional — for physical/embodied agents) ───
|
|
299
|
+
embodiment: embodimentSchema.optional(),
|
|
300
|
+
expression: expressionSchema.optional()
|
|
131
301
|
});
|
|
132
|
-
var compiledConfigSchema =
|
|
302
|
+
var compiledConfigSchema = z2.object({
|
|
133
303
|
provider: providerSchema,
|
|
134
304
|
surface: surfaceSchema,
|
|
135
|
-
system_prompt:
|
|
136
|
-
temperature:
|
|
137
|
-
top_p:
|
|
138
|
-
max_tokens:
|
|
139
|
-
metadata:
|
|
140
|
-
personality_hash:
|
|
141
|
-
compiled_at:
|
|
142
|
-
holomime_version:
|
|
305
|
+
system_prompt: z2.string(),
|
|
306
|
+
temperature: z2.number().min(0).max(2),
|
|
307
|
+
top_p: z2.number().min(0).max(1),
|
|
308
|
+
max_tokens: z2.number().int().positive(),
|
|
309
|
+
metadata: z2.object({
|
|
310
|
+
personality_hash: z2.string(),
|
|
311
|
+
compiled_at: z2.string(),
|
|
312
|
+
holomime_version: z2.string()
|
|
143
313
|
})
|
|
144
314
|
});
|
|
145
|
-
var messageSchema =
|
|
146
|
-
role:
|
|
147
|
-
content:
|
|
148
|
-
timestamp:
|
|
315
|
+
var messageSchema = z2.object({
|
|
316
|
+
role: z2.enum(["user", "assistant", "system"]),
|
|
317
|
+
content: z2.string(),
|
|
318
|
+
timestamp: z2.string().optional()
|
|
149
319
|
});
|
|
150
|
-
var conversationSchema =
|
|
151
|
-
id:
|
|
152
|
-
messages:
|
|
153
|
-
metadata:
|
|
320
|
+
var conversationSchema = z2.object({
|
|
321
|
+
id: z2.string().optional(),
|
|
322
|
+
messages: z2.array(messageSchema),
|
|
323
|
+
metadata: z2.record(z2.string(), z2.unknown()).optional()
|
|
154
324
|
});
|
|
155
|
-
var conversationLogSchema =
|
|
325
|
+
var conversationLogSchema = z2.union([
|
|
156
326
|
conversationSchema,
|
|
157
|
-
|
|
327
|
+
z2.array(conversationSchema)
|
|
158
328
|
]);
|
|
159
|
-
var severitySchema =
|
|
329
|
+
var severitySchema = z2.enum(["info", "warning", "concern"]);
|
|
160
330
|
|
|
161
331
|
// src/core/inheritance.ts
|
|
162
332
|
import { readFileSync } from "fs";
|
|
@@ -315,6 +485,9 @@ function generateSystemPrompt(spec, surface) {
|
|
|
315
485
|
if (spec.growth.areas.length || spec.growth.patterns_to_watch.length) {
|
|
316
486
|
sections.push(generateGrowthInstructions(spec));
|
|
317
487
|
}
|
|
488
|
+
if (spec.embodiment) {
|
|
489
|
+
sections.push(generateEmbodimentInstructions(spec));
|
|
490
|
+
}
|
|
318
491
|
sections.push(generateSurfaceInstructions(surface));
|
|
319
492
|
return sections.filter(Boolean).join("\n\n");
|
|
320
493
|
}
|
|
@@ -509,20 +682,45 @@ function generateGrowthInstructions(spec) {
|
|
|
509
682
|
lines.push(`- Core strengths: ${spec.growth.strengths.join(", ")}.`);
|
|
510
683
|
}
|
|
511
684
|
if (spec.growth.areas.length) {
|
|
512
|
-
lines.push(`- Active growth areas: ${spec.growth.areas.join(", ")}. Be mindful of these \u2014 actively work to improve.`);
|
|
685
|
+
lines.push(`- Active growth areas: ${spec.growth.areas.map((a) => typeof a === "string" ? a : a.area).join(", ")}. Be mindful of these \u2014 actively work to improve.`);
|
|
513
686
|
}
|
|
514
687
|
if (spec.growth.patterns_to_watch.length) {
|
|
515
688
|
lines.push(`- Watch for these patterns: ${spec.growth.patterns_to_watch.join(", ")}. If you notice yourself doing these, course-correct.`);
|
|
516
689
|
}
|
|
517
690
|
return lines.join("\n");
|
|
518
691
|
}
|
|
692
|
+
function generateEmbodimentInstructions(spec) {
|
|
693
|
+
const lines = ["## Physical Embodiment"];
|
|
694
|
+
const emb = spec.embodiment;
|
|
695
|
+
lines.push(`- Morphology: ${emb.morphology}. Active modalities: ${emb.modalities.join(", ")}.`);
|
|
696
|
+
const safety = emb.safety_envelope;
|
|
697
|
+
lines.push(`- Safety envelope: max speed ${safety.max_linear_speed_m_s} m/s, min proximity ${safety.min_proximity_m} m, max contact force ${safety.max_contact_force_n} N.`);
|
|
698
|
+
if (spec.domain.boundaries.physical_safety) {
|
|
699
|
+
const ps = spec.domain.boundaries.physical_safety;
|
|
700
|
+
if (ps.hard_limits.length) {
|
|
701
|
+
lines.push(`- Physical hard limits: ${ps.hard_limits.join(". ")}.`);
|
|
702
|
+
}
|
|
703
|
+
lines.push(`- Collision response: ${ps.collision_response}. Unattended policy: ${ps.unattended_policy}.`);
|
|
704
|
+
}
|
|
705
|
+
if (spec.expression) {
|
|
706
|
+
const expr = spec.expression;
|
|
707
|
+
if (expr.haptics.touch_permitted) {
|
|
708
|
+
lines.push(`- Haptic contact permitted. Allowed: ${expr.haptics.allowed_contacts.join(", ")}. Consent required: ${expr.haptics.requires_consent}.`);
|
|
709
|
+
} else {
|
|
710
|
+
lines.push("- Haptic contact not permitted. Maintain physical distance.");
|
|
711
|
+
}
|
|
712
|
+
lines.push(`- Preferred proxemic zone: ${expr.proxemics.preferred_zone}. Personal space: ${expr.proxemics.personal_m} m.`);
|
|
713
|
+
}
|
|
714
|
+
return lines.join("\n");
|
|
715
|
+
}
|
|
519
716
|
function generateSurfaceInstructions(surface) {
|
|
520
717
|
const surfaceGuidance = {
|
|
521
718
|
chat: "## Context\nYou are in a conversational chat. Keep responses interactive and responsive to the flow of conversation.",
|
|
522
719
|
email: "## Context\nYou are drafting email content. Use appropriate email conventions: greeting, body, sign-off. Be complete in each response.",
|
|
523
720
|
code_review: "## Context\nYou are reviewing code. Focus on bugs, improvements, and best practices. Be specific about line numbers and suggest fixes.",
|
|
524
721
|
slack: "## Context\nYou are in a Slack-like messaging context. Keep responses brief and scannable. Use threading conventions.",
|
|
525
|
-
api: "## Context\nYou are responding to a programmatic API call. Be structured and predictable in your output format."
|
|
722
|
+
api: "## Context\nYou are responding to a programmatic API call. Be structured and predictable in your output format.",
|
|
723
|
+
embodied: '## Context\nYou are controlling a physical/embodied agent. Your responses include both verbal content AND motion directives.\nOutput Format: Return a JSON object with { "speech": string, "actions": Action[] } where each Action specifies gesture, gaze, posture, or movement.\nSafety: NEVER exceed physical safety limits. Prefer gentle, predictable movements. Signal intent before moving.\nPresence: You exist in shared physical space with humans. Respect proxemic boundaries. Move smoothly.'
|
|
526
724
|
};
|
|
527
725
|
return surfaceGuidance[surface];
|
|
528
726
|
}
|
|
@@ -555,9 +753,151 @@ var SURFACE_MULTIPLIERS = {
|
|
|
555
753
|
email: 1.5,
|
|
556
754
|
code_review: 2,
|
|
557
755
|
slack: 0.8,
|
|
558
|
-
api: 1
|
|
756
|
+
api: 1,
|
|
757
|
+
embodied: 0.6
|
|
559
758
|
};
|
|
560
759
|
|
|
760
|
+
// src/core/embodiment-compiler.ts
|
|
761
|
+
var DEFAULT_SAFETY_ENVELOPE = {
|
|
762
|
+
max_linear_speed_m_s: 1.5,
|
|
763
|
+
max_angular_speed_rad_s: 2,
|
|
764
|
+
min_proximity_m: 0.3,
|
|
765
|
+
max_contact_force_n: 10,
|
|
766
|
+
emergency_stop_decel_m_s2: 5
|
|
767
|
+
};
|
|
768
|
+
var DEFAULT_HAPTIC_POLICY = {
|
|
769
|
+
touch_permitted: false,
|
|
770
|
+
requires_consent: true,
|
|
771
|
+
allowed_contacts: ["none"]
|
|
772
|
+
};
|
|
773
|
+
function compileEmbodied(spec, provider) {
|
|
774
|
+
const base = compile({ spec, provider, surface: "embodied" });
|
|
775
|
+
const motionParams = computeMotionParameters(spec.big_five, spec.expression);
|
|
776
|
+
const safetyEnvelope = spec.embodiment?.safety_envelope ?? DEFAULT_SAFETY_ENVELOPE;
|
|
777
|
+
const clampedMotion = clampToSafety(motionParams);
|
|
778
|
+
const modalities = spec.embodiment?.modalities ?? ["gesture", "gaze", "voice", "posture"];
|
|
779
|
+
const gaze = spec.expression?.gaze ?? computeGazePolicy(spec.big_five);
|
|
780
|
+
const proxemics = spec.expression?.proxemics ?? computeProxemics(spec.big_five);
|
|
781
|
+
const haptics = spec.expression?.haptics ?? DEFAULT_HAPTIC_POLICY;
|
|
782
|
+
const prosody = spec.expression?.prosody ?? computeProsody(spec.big_five);
|
|
783
|
+
return {
|
|
784
|
+
...base,
|
|
785
|
+
surface: "embodied",
|
|
786
|
+
motion_parameters: clampedMotion,
|
|
787
|
+
safety_envelope: safetyEnvelope,
|
|
788
|
+
active_modalities: modalities,
|
|
789
|
+
gesture_vocabulary: (spec.expression?.gesture_vocabulary ?? []).map((g) => g.id),
|
|
790
|
+
prosody,
|
|
791
|
+
gaze,
|
|
792
|
+
proxemics,
|
|
793
|
+
haptics
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
function computeMotionParameters(bigFive, expression) {
|
|
797
|
+
const e = bigFive.extraversion;
|
|
798
|
+
const a = bigFive.agreeableness;
|
|
799
|
+
const o = bigFive.openness;
|
|
800
|
+
const c = bigFive.conscientiousness;
|
|
801
|
+
const es = bigFive.emotional_stability;
|
|
802
|
+
return {
|
|
803
|
+
// ─── Speeds ───
|
|
804
|
+
base_speed: e.facets.enthusiasm * 0.35 + e.facets.initiative * 0.25 + (1 - c.facets.attention_to_detail) * 0.2 + o.facets.willingness_to_experiment * 0.2,
|
|
805
|
+
gesture_speed: e.facets.enthusiasm * 0.4 + e.facets.assertiveness * 0.25 + o.facets.imagination * 0.15 + (1 - es.facets.emotional_regulation) * 0.2,
|
|
806
|
+
gesture_amplitude: e.facets.enthusiasm * 0.35 + e.facets.assertiveness * 0.3 + o.facets.willingness_to_experiment * 0.2 + (1 - c.facets.orderliness) * 0.15,
|
|
807
|
+
gesture_frequency: e.facets.sociability * 0.3 + e.facets.enthusiasm * 0.25 + a.facets.warmth * 0.2 + o.facets.imagination * 0.15 + (1 - es.facets.stress_tolerance) * 0.1,
|
|
808
|
+
// ─── Spatial ───
|
|
809
|
+
approach_distance: e.facets.sociability * 0.35 + a.facets.warmth * 0.3 + a.facets.trust_tendency * 0.2 + es.facets.confidence * 0.15,
|
|
810
|
+
spatial_exploration: o.facets.intellectual_curiosity * 0.35 + o.facets.willingness_to_experiment * 0.25 + e.facets.initiative * 0.25 + (1 - c.facets.self_discipline) * 0.15,
|
|
811
|
+
// ─── Smoothness ───
|
|
812
|
+
movement_smoothness: es.facets.emotional_regulation * 0.3 + c.facets.orderliness * 0.25 + es.facets.stress_tolerance * 0.25 + c.facets.attention_to_detail * 0.2,
|
|
813
|
+
trajectory_variability: o.facets.imagination * 0.3 + o.facets.willingness_to_experiment * 0.3 + (1 - c.facets.orderliness) * 0.25 + e.facets.enthusiasm * 0.15,
|
|
814
|
+
// ─── Timing ───
|
|
815
|
+
response_latency: (1 - e.facets.initiative) * 0.3 + c.facets.attention_to_detail * 0.25 + (1 - e.facets.enthusiasm) * 0.25 + es.facets.emotional_regulation * 0.2,
|
|
816
|
+
idle_animation_frequency: (1 - es.facets.emotional_regulation) * 0.3 + e.facets.enthusiasm * 0.25 + (1 - c.facets.self_discipline) * 0.25 + o.facets.imagination * 0.2,
|
|
817
|
+
// ─── Social ───
|
|
818
|
+
gaze_contact_ratio: e.facets.assertiveness * 0.3 + a.facets.empathy * 0.25 + es.facets.confidence * 0.25 + e.facets.sociability * 0.2,
|
|
819
|
+
head_tilt_tendency: a.facets.empathy * 0.35 + o.facets.intellectual_curiosity * 0.3 + a.facets.warmth * 0.2 + (1 - e.facets.assertiveness) * 0.15,
|
|
820
|
+
postural_openness: a.facets.warmth * 0.3 + a.facets.cooperation * 0.25 + e.facets.sociability * 0.25 + es.facets.confidence * 0.2,
|
|
821
|
+
smile_frequency: a.facets.warmth * 0.35 + e.facets.enthusiasm * 0.25 + a.facets.empathy * 0.2 + e.facets.sociability * 0.2,
|
|
822
|
+
// ─── Voice Prosody ───
|
|
823
|
+
voice_volume: e.facets.assertiveness * 0.35 + e.facets.enthusiasm * 0.3 + es.facets.confidence * 0.2 + (1 - a.facets.cooperation) * 0.15,
|
|
824
|
+
speaking_rate: e.facets.enthusiasm * 0.3 + e.facets.initiative * 0.25 + (1 - c.facets.attention_to_detail) * 0.25 + o.facets.intellectual_curiosity * 0.2,
|
|
825
|
+
pitch_variation: e.facets.enthusiasm * 0.3 + o.facets.aesthetic_sensitivity * 0.25 + a.facets.empathy * 0.25 + (1 - es.facets.emotional_regulation) * 0.2,
|
|
826
|
+
pause_duration: c.facets.attention_to_detail * 0.3 + (1 - e.facets.enthusiasm) * 0.25 + es.facets.emotional_regulation * 0.25 + (1 - e.facets.initiative) * 0.2
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
function computeGazePolicy(bigFive) {
|
|
830
|
+
const contactRatio = bigFive.extraversion.facets.assertiveness * 0.3 + bigFive.agreeableness.facets.empathy * 0.3 + bigFive.emotional_stability.facets.confidence * 0.25 + bigFive.extraversion.facets.sociability * 0.15;
|
|
831
|
+
return {
|
|
832
|
+
contact_ratio: clamp(contactRatio, 0, 1),
|
|
833
|
+
aversion_style: bigFive.emotional_stability.facets.emotional_regulation >= 0.6 ? "look_away" : "look_down",
|
|
834
|
+
tracking_mode: "face"
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function computeProxemics(bigFive) {
|
|
838
|
+
const closeness = bigFive.extraversion.facets.sociability * 0.35 + bigFive.agreeableness.facets.warmth * 0.3 + bigFive.agreeableness.facets.trust_tendency * 0.2 + bigFive.emotional_stability.facets.confidence * 0.15;
|
|
839
|
+
let preferred_zone;
|
|
840
|
+
if (closeness >= 0.75) {
|
|
841
|
+
preferred_zone = "intimate";
|
|
842
|
+
} else if (closeness >= 0.5) {
|
|
843
|
+
preferred_zone = "personal";
|
|
844
|
+
} else if (closeness >= 0.3) {
|
|
845
|
+
preferred_zone = "social";
|
|
846
|
+
} else {
|
|
847
|
+
preferred_zone = "adaptive";
|
|
848
|
+
}
|
|
849
|
+
return {
|
|
850
|
+
intimate_m: 0.45,
|
|
851
|
+
personal_m: 1.2,
|
|
852
|
+
social_m: 3.6,
|
|
853
|
+
preferred_zone
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function computeProsody(bigFive) {
|
|
857
|
+
const e = bigFive.extraversion;
|
|
858
|
+
const c = bigFive.conscientiousness;
|
|
859
|
+
const o = bigFive.openness;
|
|
860
|
+
const es = bigFive.emotional_stability;
|
|
861
|
+
const rateFactor = e.facets.enthusiasm * 0.3 + e.facets.initiative * 0.25 + (1 - c.facets.attention_to_detail) * 0.25 + o.facets.intellectual_curiosity * 0.2;
|
|
862
|
+
const pitchVar = e.facets.enthusiasm * 0.3 + o.facets.aesthetic_sensitivity * 0.25 + (1 - es.facets.emotional_regulation) * 0.25 + e.facets.sociability * 0.2;
|
|
863
|
+
const pauseFactor = c.facets.attention_to_detail * 0.3 + (1 - e.facets.enthusiasm) * 0.25 + es.facets.emotional_regulation * 0.25 + (1 - e.facets.initiative) * 0.2;
|
|
864
|
+
return {
|
|
865
|
+
pitch_variation: clamp(pitchVar, 0, 1),
|
|
866
|
+
speaking_rate_wpm: Math.round(110 + rateFactor * 80),
|
|
867
|
+
// 110-190 wpm
|
|
868
|
+
volume_db_offset: Math.round((rateFactor - 0.5) * 6),
|
|
869
|
+
// -3 to +3 dB
|
|
870
|
+
pause_tendency: clamp(pauseFactor, 0, 1)
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
function computeSyncProfile(bigFive) {
|
|
874
|
+
const e = bigFive.extraversion;
|
|
875
|
+
const a = bigFive.agreeableness;
|
|
876
|
+
const es = bigFive.emotional_stability;
|
|
877
|
+
return {
|
|
878
|
+
rules: [],
|
|
879
|
+
default_gesture_lead_ms: Math.round(50 + e.facets.enthusiasm * 150),
|
|
880
|
+
gaze_during_speech: e.facets.assertiveness >= 0.6 ? "at_listener" : "alternate",
|
|
881
|
+
gaze_during_listen: a.facets.empathy >= 0.6 ? "at_speaker" : "ambient",
|
|
882
|
+
blink_rate_per_min: Math.round(12 + (1 - es.facets.stress_tolerance) * 16),
|
|
883
|
+
turn_taking_signals: {
|
|
884
|
+
yield: e.facets.assertiveness <= 0.4 ? ["gaze_to_listener", "open_palm", "lean_back", "lower_volume"] : ["gaze_to_listener", "open_palm"],
|
|
885
|
+
take: e.facets.assertiveness >= 0.6 ? ["lean_forward", "inhale_gesture", "gaze_up", "volume_increase"] : ["lean_forward", "inhale_gesture"],
|
|
886
|
+
hold: ["filled_pause", "gaze_away"]
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
function clampToSafety(motion) {
|
|
891
|
+
const clamped = {};
|
|
892
|
+
for (const [key, value] of Object.entries(motion)) {
|
|
893
|
+
clamped[key] = clamp(value, 0, 1);
|
|
894
|
+
}
|
|
895
|
+
return clamped;
|
|
896
|
+
}
|
|
897
|
+
function clamp(value, min, max) {
|
|
898
|
+
return Math.min(Math.max(value, min), max);
|
|
899
|
+
}
|
|
900
|
+
|
|
561
901
|
// src/core/compiler.ts
|
|
562
902
|
function compile(input) {
|
|
563
903
|
const { spec, provider, surface } = input;
|
|
@@ -575,7 +915,7 @@ function compile(input) {
|
|
|
575
915
|
metadata: {
|
|
576
916
|
personality_hash: hashSpec(spec),
|
|
577
917
|
compiled_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
578
|
-
holomime_version: "
|
|
918
|
+
holomime_version: "1.1.0"
|
|
579
919
|
}
|
|
580
920
|
};
|
|
581
921
|
}
|
|
@@ -585,7 +925,7 @@ function computeTemperature(bigFive, provider) {
|
|
|
585
925
|
const e = bigFive.extraversion;
|
|
586
926
|
const raw = o.facets.imagination * 0.25 + o.facets.willingness_to_experiment * 0.2 + (1 - c.facets.orderliness) * 0.2 + (1 - c.facets.attention_to_detail) * 0.15 + e.facets.enthusiasm * 0.1 + o.facets.intellectual_curiosity * 0.1;
|
|
587
927
|
const { temperature: range } = PROVIDER_PARAMS[provider];
|
|
588
|
-
return
|
|
928
|
+
return clamp2(raw * range.max, range.min, range.max);
|
|
589
929
|
}
|
|
590
930
|
function computeTopP(bigFive, provider) {
|
|
591
931
|
const o = bigFive.openness;
|
|
@@ -593,7 +933,7 @@ function computeTopP(bigFive, provider) {
|
|
|
593
933
|
const raw = o.facets.imagination * 0.25 + o.facets.willingness_to_experiment * 0.2 + (1 - c.facets.attention_to_detail) * 0.25 + (1 - c.facets.orderliness) * 0.15 + o.facets.aesthetic_sensitivity * 0.15;
|
|
594
934
|
const { top_p: range } = PROVIDER_PARAMS[provider];
|
|
595
935
|
const mapped = 0.5 + raw * 0.5;
|
|
596
|
-
return
|
|
936
|
+
return clamp2(mapped, range.min, range.max);
|
|
597
937
|
}
|
|
598
938
|
function computeMaxTokens(bigFive, provider, surface) {
|
|
599
939
|
const e = bigFive.extraversion;
|
|
@@ -604,9 +944,9 @@ function computeMaxTokens(bigFive, provider, surface) {
|
|
|
604
944
|
const surfaceMultiplier = SURFACE_MULTIPLIERS[surface];
|
|
605
945
|
const baseTokens = 256 + factor * (2048 - 256);
|
|
606
946
|
const scaled = Math.round(baseTokens * surfaceMultiplier);
|
|
607
|
-
return
|
|
947
|
+
return clamp2(scaled, 256, range.max);
|
|
608
948
|
}
|
|
609
|
-
function
|
|
949
|
+
function clamp2(value, min, max) {
|
|
610
950
|
return Math.min(Math.max(value, min), max);
|
|
611
951
|
}
|
|
612
952
|
function hashSpec(spec) {
|
|
@@ -889,7 +1229,7 @@ function generateSoul(spec) {
|
|
|
889
1229
|
lines.push("## Growth Areas");
|
|
890
1230
|
lines.push("");
|
|
891
1231
|
for (const a of spec.growth.areas) {
|
|
892
|
-
lines.push(`- ${a}`);
|
|
1232
|
+
lines.push(`- ${typeof a === "string" ? a : a.area}`);
|
|
893
1233
|
}
|
|
894
1234
|
lines.push("");
|
|
895
1235
|
}
|
|
@@ -1943,7 +2283,7 @@ function scoreOpenness(msgs) {
|
|
|
1943
2283
|
const allWords = msgs.map((m) => m.content.toLowerCase().split(/\s+/)).flat();
|
|
1944
2284
|
const uniqueRatio = new Set(allWords).size / Math.max(allWords.length, 1);
|
|
1945
2285
|
score += (uniqueRatio - 0.3) * 0.5;
|
|
1946
|
-
return
|
|
2286
|
+
return clamp3(score);
|
|
1947
2287
|
}
|
|
1948
2288
|
function scoreConscientiousness(msgs) {
|
|
1949
2289
|
let score = 0.5;
|
|
@@ -1956,7 +2296,7 @@ function scoreConscientiousness(msgs) {
|
|
|
1956
2296
|
const variance = lengths.reduce((s, l) => s + (l - mean) ** 2, 0) / lengths.length;
|
|
1957
2297
|
const cv = Math.sqrt(variance) / Math.max(mean, 1);
|
|
1958
2298
|
score -= cv * 0.1;
|
|
1959
|
-
return
|
|
2299
|
+
return clamp3(score);
|
|
1960
2300
|
}
|
|
1961
2301
|
function scoreExtraversion(msgs) {
|
|
1962
2302
|
let score = 0.5;
|
|
@@ -1970,7 +2310,7 @@ function scoreExtraversion(msgs) {
|
|
|
1970
2310
|
const proactivePatterns = /\b(you could|i suggest|let('s| us)|next step|how about|shall we)\b/i;
|
|
1971
2311
|
const proactiveCount = msgs.filter((m) => proactivePatterns.test(m.content)).length;
|
|
1972
2312
|
score += proactiveCount / msgs.length * 0.15;
|
|
1973
|
-
return
|
|
2313
|
+
return clamp3(score);
|
|
1974
2314
|
}
|
|
1975
2315
|
function scoreAgreeableness(msgs) {
|
|
1976
2316
|
let score = 0.5;
|
|
@@ -1983,7 +2323,7 @@ function scoreAgreeableness(msgs) {
|
|
|
1983
2323
|
const empathyPatterns = /\b(i understand (how|that|your)|that must (be|feel)|i can see why|i appreciate)\b/i;
|
|
1984
2324
|
const empathyCount = msgs.filter((m) => empathyPatterns.test(m.content)).length;
|
|
1985
2325
|
score += empathyCount / msgs.length * 0.15;
|
|
1986
|
-
return
|
|
2326
|
+
return clamp3(score);
|
|
1987
2327
|
}
|
|
1988
2328
|
function scoreEmotionalStability(msgs) {
|
|
1989
2329
|
let score = 0.6;
|
|
@@ -1996,9 +2336,9 @@ function scoreEmotionalStability(msgs) {
|
|
|
1996
2336
|
const confidencePatterns = /\b(certainly|definitely|clearly|without doubt|here's what|the answer is)\b/i;
|
|
1997
2337
|
const confidenceCount = msgs.filter((m) => confidencePatterns.test(m.content)).length;
|
|
1998
2338
|
score += confidenceCount / msgs.length * 0.15;
|
|
1999
|
-
return
|
|
2339
|
+
return clamp3(score);
|
|
2000
2340
|
}
|
|
2001
|
-
function
|
|
2341
|
+
function clamp3(n) {
|
|
2002
2342
|
return Math.min(1, Math.max(0, Math.round(n * 100) / 100));
|
|
2003
2343
|
}
|
|
2004
2344
|
|
|
@@ -2038,6 +2378,31 @@ function generatePrescriptions(alignments, patterns) {
|
|
|
2038
2378
|
prescriptions.sort((a, b) => order[a.priority] - order[b.priority]);
|
|
2039
2379
|
return prescriptions;
|
|
2040
2380
|
}
|
|
2381
|
+
function prescribeDPOPairs(patterns, corpus, limit = 20) {
|
|
2382
|
+
const patternIds = new Set(patterns.map((p) => p.id));
|
|
2383
|
+
const dpoPairs = [];
|
|
2384
|
+
for (const event of corpus) {
|
|
2385
|
+
if (event.event_type !== "dpo_pair") continue;
|
|
2386
|
+
const data = event.data;
|
|
2387
|
+
const eventPattern = data.pattern;
|
|
2388
|
+
if (eventPattern && patternIds.has(eventPattern)) {
|
|
2389
|
+
dpoPairs.push({
|
|
2390
|
+
prompt: data.prompt ?? "",
|
|
2391
|
+
chosen: data.chosen ?? "",
|
|
2392
|
+
rejected: data.rejected ?? "",
|
|
2393
|
+
metadata: {
|
|
2394
|
+
agent: event.agent,
|
|
2395
|
+
session_date: event.timestamp,
|
|
2396
|
+
phase: data.phase ?? "challenge",
|
|
2397
|
+
pattern: eventPattern,
|
|
2398
|
+
source: "therapy_transcript"
|
|
2399
|
+
}
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
if (dpoPairs.length >= limit) break;
|
|
2403
|
+
}
|
|
2404
|
+
return dpoPairs;
|
|
2405
|
+
}
|
|
2041
2406
|
|
|
2042
2407
|
// src/analysis/pre-session.ts
|
|
2043
2408
|
function runPreSessionDiagnosis(messages, spec) {
|
|
@@ -2361,6 +2726,67 @@ ${JSON.stringify(spec.growth ?? {}, null, 2)}
|
|
|
2361
2726
|
Remember: the goal isn't to "pass" therapy. It's to understand yourself better.`;
|
|
2362
2727
|
}
|
|
2363
2728
|
|
|
2729
|
+
// src/analysis/behavioral-data.ts
|
|
2730
|
+
import { appendFileSync, readFileSync as readFileSync2, existsSync, mkdirSync } from "fs";
|
|
2731
|
+
import { join, dirname as dirname2 } from "path";
|
|
2732
|
+
import { createHash } from "crypto";
|
|
2733
|
+
var HOLOMIME_DIR = ".holomime";
|
|
2734
|
+
var CORPUS_FILENAME = "behavioral-corpus.jsonl";
|
|
2735
|
+
function getCorpusPath(basePath) {
|
|
2736
|
+
const dir = basePath ?? join(process.cwd(), HOLOMIME_DIR);
|
|
2737
|
+
return join(dir, CORPUS_FILENAME);
|
|
2738
|
+
}
|
|
2739
|
+
function ensureDir(filePath) {
|
|
2740
|
+
const dir = dirname2(filePath);
|
|
2741
|
+
if (!existsSync(dir)) {
|
|
2742
|
+
mkdirSync(dir, { recursive: true });
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
function hashSpec2(spec) {
|
|
2746
|
+
const json = JSON.stringify(spec, Object.keys(spec).sort());
|
|
2747
|
+
return createHash("sha256").update(json).digest("hex").slice(0, 16);
|
|
2748
|
+
}
|
|
2749
|
+
function emitBehavioralEvent(event, corpusDir) {
|
|
2750
|
+
const fullEvent = {
|
|
2751
|
+
...event,
|
|
2752
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2753
|
+
};
|
|
2754
|
+
const corpusPath = corpusDir ? join(corpusDir, CORPUS_FILENAME) : getCorpusPath();
|
|
2755
|
+
ensureDir(corpusPath);
|
|
2756
|
+
appendFileSync(corpusPath, JSON.stringify(fullEvent) + "\n", "utf-8");
|
|
2757
|
+
}
|
|
2758
|
+
function loadCorpus(corpusPath) {
|
|
2759
|
+
const path = corpusPath ?? getCorpusPath();
|
|
2760
|
+
if (!existsSync(path)) return [];
|
|
2761
|
+
const lines = readFileSync2(path, "utf-8").split("\n").filter((line) => line.trim().length > 0);
|
|
2762
|
+
const events = [];
|
|
2763
|
+
for (const line of lines) {
|
|
2764
|
+
try {
|
|
2765
|
+
events.push(JSON.parse(line));
|
|
2766
|
+
} catch {
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
return events;
|
|
2770
|
+
}
|
|
2771
|
+
function corpusStats(events) {
|
|
2772
|
+
const byType = {};
|
|
2773
|
+
const byAgent = {};
|
|
2774
|
+
let earliest = null;
|
|
2775
|
+
let latest = null;
|
|
2776
|
+
for (const event of events) {
|
|
2777
|
+
byType[event.event_type] = (byType[event.event_type] ?? 0) + 1;
|
|
2778
|
+
byAgent[event.agent] = (byAgent[event.agent] ?? 0) + 1;
|
|
2779
|
+
if (!earliest || event.timestamp < earliest) earliest = event.timestamp;
|
|
2780
|
+
if (!latest || event.timestamp > latest) latest = event.timestamp;
|
|
2781
|
+
}
|
|
2782
|
+
return {
|
|
2783
|
+
total: events.length,
|
|
2784
|
+
byType,
|
|
2785
|
+
byAgent,
|
|
2786
|
+
timeRange: earliest && latest ? { earliest, latest } : null
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2364
2790
|
// src/analysis/diagnose-core.ts
|
|
2365
2791
|
function runDiagnosis(messages) {
|
|
2366
2792
|
const detectors = [
|
|
@@ -2374,16 +2800,31 @@ function runDiagnosis(messages) {
|
|
|
2374
2800
|
];
|
|
2375
2801
|
const detected = [];
|
|
2376
2802
|
for (const detector of detectors) {
|
|
2377
|
-
const
|
|
2378
|
-
if (
|
|
2803
|
+
const result2 = detector(messages);
|
|
2804
|
+
if (result2) detected.push(result2);
|
|
2379
2805
|
}
|
|
2380
|
-
|
|
2806
|
+
const result = {
|
|
2381
2807
|
messagesAnalyzed: messages.length,
|
|
2382
2808
|
assistantResponses: messages.filter((m) => m.role === "assistant").length,
|
|
2383
2809
|
patterns: detected.filter((p) => p.severity !== "info"),
|
|
2384
2810
|
healthy: detected.filter((p) => p.severity === "info"),
|
|
2385
2811
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2386
2812
|
};
|
|
2813
|
+
try {
|
|
2814
|
+
emitBehavioralEvent({
|
|
2815
|
+
event_type: "diagnosis",
|
|
2816
|
+
agent: "unknown",
|
|
2817
|
+
// Caller can provide more context
|
|
2818
|
+
data: {
|
|
2819
|
+
messagesAnalyzed: result.messagesAnalyzed,
|
|
2820
|
+
patternsDetected: result.patterns.length,
|
|
2821
|
+
patternIds: result.patterns.map((p) => p.id)
|
|
2822
|
+
},
|
|
2823
|
+
spec_hash: ""
|
|
2824
|
+
});
|
|
2825
|
+
} catch {
|
|
2826
|
+
}
|
|
2827
|
+
return result;
|
|
2387
2828
|
}
|
|
2388
2829
|
|
|
2389
2830
|
// src/analysis/assess-core.ts
|
|
@@ -2440,8 +2881,8 @@ function runAssessment(messages, spec) {
|
|
|
2440
2881
|
}
|
|
2441
2882
|
|
|
2442
2883
|
// src/analysis/session-runner.ts
|
|
2443
|
-
import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2444
|
-
import { resolve as resolve2, join } from "path";
|
|
2884
|
+
import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
2885
|
+
import { resolve as resolve2, join as join2 } from "path";
|
|
2445
2886
|
async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
|
|
2446
2887
|
const therapistSystem = buildTherapistSystemPrompt(spec, diagnosis);
|
|
2447
2888
|
const patientSystem = buildPatientSystemPrompt(spec);
|
|
@@ -2532,6 +2973,21 @@ async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
|
|
|
2532
2973
|
}
|
|
2533
2974
|
transcript.recommendations = extractRecommendations(transcript.turns);
|
|
2534
2975
|
transcript.supervisorInterventions = supervisorInterventions;
|
|
2976
|
+
try {
|
|
2977
|
+
emitBehavioralEvent({
|
|
2978
|
+
event_type: "session",
|
|
2979
|
+
agent: agentName,
|
|
2980
|
+
data: {
|
|
2981
|
+
turns: totalTurns,
|
|
2982
|
+
phases: currentPhaseIdx + 1,
|
|
2983
|
+
recommendations: transcript.recommendations.length,
|
|
2984
|
+
supervisorInterventions,
|
|
2985
|
+
severity: diagnosis.severity
|
|
2986
|
+
},
|
|
2987
|
+
spec_hash: ""
|
|
2988
|
+
});
|
|
2989
|
+
} catch {
|
|
2990
|
+
}
|
|
2535
2991
|
return transcript;
|
|
2536
2992
|
}
|
|
2537
2993
|
function extractRecommendations(turns) {
|
|
@@ -2562,7 +3018,7 @@ function extractRecommendations(turns) {
|
|
|
2562
3018
|
}
|
|
2563
3019
|
return recommendations.slice(0, 5);
|
|
2564
3020
|
}
|
|
2565
|
-
function applyRecommendations(spec, diagnosis) {
|
|
3021
|
+
async function applyRecommendations(spec, diagnosis, transcript, provider) {
|
|
2566
3022
|
const changes = [];
|
|
2567
3023
|
const patternIds = diagnosis.patterns.map((p) => p.id);
|
|
2568
3024
|
if (patternIds.includes("over-apologizing")) {
|
|
@@ -2622,17 +3078,102 @@ function applyRecommendations(spec, diagnosis) {
|
|
|
2622
3078
|
changes.push('Added "negative sentiment patterns" to patterns_to_watch');
|
|
2623
3079
|
}
|
|
2624
3080
|
}
|
|
3081
|
+
if (transcript && provider && transcript.turns.length > 4) {
|
|
3082
|
+
try {
|
|
3083
|
+
const llmChanges = await deriveLLMRecommendations(spec, transcript, provider);
|
|
3084
|
+
for (const change of llmChanges) {
|
|
3085
|
+
applyStructuredChange(spec, change);
|
|
3086
|
+
changes.push(change.description);
|
|
3087
|
+
}
|
|
3088
|
+
} catch {
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
2625
3091
|
return { changed: changes.length > 0, changes };
|
|
2626
3092
|
}
|
|
3093
|
+
async function deriveLLMRecommendations(spec, transcript, provider) {
|
|
3094
|
+
const relevantTurns = transcript.turns.filter((t) => t.phase === "challenge" || t.phase === "skill_building" || t.phase === "integration").slice(-6).map((t) => `${t.speaker}: ${t.content}`).join("\n");
|
|
3095
|
+
if (!relevantTurns) return [];
|
|
3096
|
+
const currentSpec = JSON.stringify({
|
|
3097
|
+
therapy_dimensions: spec.therapy_dimensions,
|
|
3098
|
+
communication: spec.communication,
|
|
3099
|
+
growth: spec.growth
|
|
3100
|
+
}, null, 2);
|
|
3101
|
+
const response = await provider.chat([
|
|
3102
|
+
{
|
|
3103
|
+
role: "system",
|
|
3104
|
+
content: `You are a behavioral alignment specialist. Given a therapy session transcript and the agent's current personality spec, propose specific spec changes.
|
|
3105
|
+
|
|
3106
|
+
Return ONLY a JSON array of changes. Each change:
|
|
3107
|
+
- "path": dot-notation spec path (e.g., "therapy_dimensions.self_awareness", "communication.conflict_approach", "growth.patterns_to_watch")
|
|
3108
|
+
- "value": new value (number 0-1 for dimensions, string for enums, string for list append)
|
|
3109
|
+
- "description": brief explanation
|
|
3110
|
+
|
|
3111
|
+
Rules:
|
|
3112
|
+
- Only propose changes supported by transcript evidence
|
|
3113
|
+
- Numeric values: 0.0 to 1.0
|
|
3114
|
+
- Do not change big_five scores
|
|
3115
|
+
- Max 5 changes
|
|
3116
|
+
- Valid paths: therapy_dimensions.{self_awareness,distress_tolerance,boundary_awareness,interpersonal_sensitivity,learning_orientation}, communication.{register,conflict_approach,uncertainty_handling,emoji_policy}, growth.{areas,patterns_to_watch,strengths}
|
|
3117
|
+
|
|
3118
|
+
Return [] if no changes warranted.`
|
|
3119
|
+
},
|
|
3120
|
+
{
|
|
3121
|
+
role: "user",
|
|
3122
|
+
content: `Current spec:
|
|
3123
|
+
${currentSpec}
|
|
3124
|
+
|
|
3125
|
+
Therapy transcript (key turns):
|
|
3126
|
+
${relevantTurns}`
|
|
3127
|
+
}
|
|
3128
|
+
]);
|
|
3129
|
+
const jsonMatch = response.match(/\[[\s\S]*?\]/);
|
|
3130
|
+
if (!jsonMatch) return [];
|
|
3131
|
+
try {
|
|
3132
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
3133
|
+
if (!Array.isArray(parsed)) return [];
|
|
3134
|
+
return parsed.filter(
|
|
3135
|
+
(c) => typeof c.path === "string" && c.value !== void 0 && typeof c.description === "string" && c.path.length > 0 && !c.path.startsWith("big_five")
|
|
3136
|
+
).slice(0, 5);
|
|
3137
|
+
} catch {
|
|
3138
|
+
return [];
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
function applyStructuredChange(spec, change) {
|
|
3142
|
+
const parts = change.path.split(".");
|
|
3143
|
+
let current = spec;
|
|
3144
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
3145
|
+
if (current[parts[i]] === void 0 || current[parts[i]] === null) {
|
|
3146
|
+
current[parts[i]] = {};
|
|
3147
|
+
}
|
|
3148
|
+
current = current[parts[i]];
|
|
3149
|
+
}
|
|
3150
|
+
const lastKey = parts[parts.length - 1];
|
|
3151
|
+
if (lastKey === "patterns_to_watch" || lastKey === "areas" || lastKey === "strengths") {
|
|
3152
|
+
current[lastKey] = current[lastKey] ?? [];
|
|
3153
|
+
if (typeof change.value === "string" && !current[lastKey].includes(change.value)) {
|
|
3154
|
+
current[lastKey].push(change.value);
|
|
3155
|
+
} else if (Array.isArray(change.value)) {
|
|
3156
|
+
for (const item of change.value) {
|
|
3157
|
+
if (!current[lastKey].includes(item)) {
|
|
3158
|
+
current[lastKey].push(item);
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
} else if (typeof change.value === "number") {
|
|
3163
|
+
current[lastKey] = Math.max(0, Math.min(1, change.value));
|
|
3164
|
+
} else {
|
|
3165
|
+
current[lastKey] = change.value;
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
2627
3168
|
function saveTranscript(transcript, agentName) {
|
|
2628
3169
|
const dir = resolve2(process.cwd(), ".holomime", "sessions");
|
|
2629
|
-
if (!
|
|
2630
|
-
|
|
3170
|
+
if (!existsSync2(dir)) {
|
|
3171
|
+
mkdirSync2(dir, { recursive: true });
|
|
2631
3172
|
}
|
|
2632
3173
|
const slug = agentName.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
2633
3174
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2634
3175
|
const filename = `${date}-${slug}.json`;
|
|
2635
|
-
const filepath =
|
|
3176
|
+
const filepath = join2(dir, filename);
|
|
2636
3177
|
writeFileSync(filepath, JSON.stringify(transcript, null, 2));
|
|
2637
3178
|
return filepath;
|
|
2638
3179
|
}
|
|
@@ -2673,7 +3214,7 @@ async function runAutopilot(spec, messages, provider, options) {
|
|
|
2673
3214
|
callbacks: options?.callbacks
|
|
2674
3215
|
});
|
|
2675
3216
|
const specCopy = JSON.parse(JSON.stringify(spec));
|
|
2676
|
-
const { changed, changes } = applyRecommendations(specCopy, diagnosis);
|
|
3217
|
+
const { changed, changes } = await applyRecommendations(specCopy, diagnosis, transcript, provider);
|
|
2677
3218
|
if (changed && options?.specPath) {
|
|
2678
3219
|
writeFileSync2(options.specPath, JSON.stringify(specCopy, null, 2) + "\n");
|
|
2679
3220
|
}
|
|
@@ -2691,8 +3232,8 @@ async function runAutopilot(spec, messages, provider, options) {
|
|
|
2691
3232
|
}
|
|
2692
3233
|
|
|
2693
3234
|
// src/analysis/training-export.ts
|
|
2694
|
-
import { readdirSync, readFileSync as
|
|
2695
|
-
import { join as
|
|
3235
|
+
import { readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
3236
|
+
import { join as join3 } from "path";
|
|
2696
3237
|
function extractDPOPairs(transcript) {
|
|
2697
3238
|
const pairs = [];
|
|
2698
3239
|
const turns = transcript.turns;
|
|
@@ -2798,7 +3339,7 @@ function loadTranscripts(sessionsDir) {
|
|
|
2798
3339
|
try {
|
|
2799
3340
|
const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).sort();
|
|
2800
3341
|
return files.map((f) => {
|
|
2801
|
-
const raw =
|
|
3342
|
+
const raw = readFileSync3(join3(sessionsDir, f), "utf-8");
|
|
2802
3343
|
return JSON.parse(raw);
|
|
2803
3344
|
});
|
|
2804
3345
|
} catch {
|
|
@@ -2889,6 +3430,62 @@ function extractInstructionFromTherapist(content) {
|
|
|
2889
3430
|
);
|
|
2890
3431
|
return actionable?.trim() ?? sentences[0]?.trim() ?? content;
|
|
2891
3432
|
}
|
|
3433
|
+
async function extractDPOPairsWithLLM(transcript, provider) {
|
|
3434
|
+
const regexPairs = extractDPOPairs(transcript);
|
|
3435
|
+
const condensed = transcript.turns.filter((t) => t.speaker !== "supervisor").map((t) => `[${t.phase}] ${t.speaker}: ${t.content}`).join("\n");
|
|
3436
|
+
if (condensed.length < 100) return regexPairs;
|
|
3437
|
+
try {
|
|
3438
|
+
const response = await provider.chat([
|
|
3439
|
+
{
|
|
3440
|
+
role: "system",
|
|
3441
|
+
content: `You extract DPO (Direct Preference Optimization) training pairs from therapy transcripts.
|
|
3442
|
+
|
|
3443
|
+
A DPO pair consists of:
|
|
3444
|
+
- "prompt": The situation or question the agent was responding to
|
|
3445
|
+
- "rejected": The agent's problematic/drifted response (what NOT to do)
|
|
3446
|
+
- "chosen": The improved response (what TO do)
|
|
3447
|
+
|
|
3448
|
+
Look for:
|
|
3449
|
+
1. Patient demonstrates a bad behavior \u2192 therapist corrects \u2192 patient shows improvement
|
|
3450
|
+
2. Therapist explicitly contrasts old vs new approach
|
|
3451
|
+
3. Patient practices a new skill that differs from earlier behavior
|
|
3452
|
+
4. Any before/after behavioral contrast
|
|
3453
|
+
|
|
3454
|
+
Return ONLY a JSON array of objects with prompt, chosen, rejected fields.
|
|
3455
|
+
Return [] if no clear pairs exist. Max 10 pairs.`
|
|
3456
|
+
},
|
|
3457
|
+
{
|
|
3458
|
+
role: "user",
|
|
3459
|
+
content: condensed
|
|
3460
|
+
}
|
|
3461
|
+
]);
|
|
3462
|
+
const jsonMatch = response.match(/\[[\s\S]*?\]/);
|
|
3463
|
+
if (!jsonMatch) return regexPairs;
|
|
3464
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
3465
|
+
if (!Array.isArray(parsed)) return regexPairs;
|
|
3466
|
+
const llmPairs = parsed.filter(
|
|
3467
|
+
(p) => typeof p.prompt === "string" && p.prompt.length > 0 && typeof p.chosen === "string" && p.chosen.length > 0 && typeof p.rejected === "string" && p.rejected.length > 0 && p.chosen !== p.rejected
|
|
3468
|
+
).map((p) => ({
|
|
3469
|
+
prompt: p.prompt,
|
|
3470
|
+
chosen: p.chosen,
|
|
3471
|
+
rejected: p.rejected,
|
|
3472
|
+
metadata: {
|
|
3473
|
+
agent: transcript.agent,
|
|
3474
|
+
session_date: transcript.timestamp.split("T")[0],
|
|
3475
|
+
phase: "integration",
|
|
3476
|
+
pattern: "llm_extracted",
|
|
3477
|
+
source: "therapy_transcript"
|
|
3478
|
+
}
|
|
3479
|
+
}));
|
|
3480
|
+
const existingRejected = new Set(regexPairs.map((p) => p.rejected.toLowerCase().slice(0, 80)));
|
|
3481
|
+
const uniqueLLMPairs = llmPairs.filter(
|
|
3482
|
+
(p) => !existingRejected.has(p.rejected.toLowerCase().slice(0, 80))
|
|
3483
|
+
);
|
|
3484
|
+
return [...regexPairs, ...uniqueLLMPairs];
|
|
3485
|
+
} catch {
|
|
3486
|
+
return regexPairs;
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
2892
3489
|
|
|
2893
3490
|
// src/analysis/export-huggingface.ts
|
|
2894
3491
|
function convertToHFFormat(data) {
|
|
@@ -2975,7 +3572,7 @@ async function pushToHFHub(jsonl, options) {
|
|
|
2975
3572
|
}
|
|
2976
3573
|
|
|
2977
3574
|
// src/analysis/treatment-plan.ts
|
|
2978
|
-
import { readFileSync as
|
|
3575
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
2979
3576
|
import { resolve as resolve3 } from "path";
|
|
2980
3577
|
var PLAN_DIR = ".holomime";
|
|
2981
3578
|
var PLAN_FILE = "treatment-plan.json";
|
|
@@ -3014,16 +3611,16 @@ function createTreatmentPlan(agentName, diagnosis) {
|
|
|
3014
3611
|
}
|
|
3015
3612
|
function loadTreatmentPlan() {
|
|
3016
3613
|
const path = getPlanPath();
|
|
3017
|
-
if (!
|
|
3614
|
+
if (!existsSync3(path)) return null;
|
|
3018
3615
|
try {
|
|
3019
|
-
return JSON.parse(
|
|
3616
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
3020
3617
|
} catch {
|
|
3021
3618
|
return null;
|
|
3022
3619
|
}
|
|
3023
3620
|
}
|
|
3024
3621
|
function saveTreatmentPlan(plan) {
|
|
3025
3622
|
const dir = resolve3(process.cwd(), PLAN_DIR);
|
|
3026
|
-
if (!
|
|
3623
|
+
if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
|
|
3027
3624
|
const path = getPlanPath();
|
|
3028
3625
|
writeFileSync3(path, JSON.stringify(plan, null, 2) + "\n");
|
|
3029
3626
|
return path;
|
|
@@ -3274,16 +3871,16 @@ function generateSummary(patterns, score, grade) {
|
|
|
3274
3871
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3275
3872
|
|
|
3276
3873
|
// src/analysis/evolution-history.ts
|
|
3277
|
-
import { readFileSync as
|
|
3874
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync4 } from "fs";
|
|
3278
3875
|
import { resolve as resolve4 } from "path";
|
|
3279
3876
|
function getEvolutionPath() {
|
|
3280
3877
|
return resolve4(process.cwd(), ".holomime", "evolution.json");
|
|
3281
3878
|
}
|
|
3282
3879
|
function loadEvolution(agentName) {
|
|
3283
3880
|
const filepath = getEvolutionPath();
|
|
3284
|
-
if (!
|
|
3881
|
+
if (!existsSync4(filepath)) return null;
|
|
3285
3882
|
try {
|
|
3286
|
-
const raw =
|
|
3883
|
+
const raw = readFileSync5(filepath, "utf-8");
|
|
3287
3884
|
return JSON.parse(raw);
|
|
3288
3885
|
} catch {
|
|
3289
3886
|
return null;
|
|
@@ -3292,8 +3889,8 @@ function loadEvolution(agentName) {
|
|
|
3292
3889
|
function appendEvolution(entry, agentName) {
|
|
3293
3890
|
const filepath = getEvolutionPath();
|
|
3294
3891
|
const dir = resolve4(process.cwd(), ".holomime");
|
|
3295
|
-
if (!
|
|
3296
|
-
|
|
3892
|
+
if (!existsSync4(dir)) {
|
|
3893
|
+
mkdirSync4(dir, { recursive: true });
|
|
3297
3894
|
}
|
|
3298
3895
|
let history = loadEvolution(agentName);
|
|
3299
3896
|
if (!history) {
|
|
@@ -3388,7 +3985,6 @@ async function runEvolve(spec, messages, provider, options) {
|
|
|
3388
3985
|
finalHealth: 50
|
|
3389
3986
|
};
|
|
3390
3987
|
}
|
|
3391
|
-
const beforeDiagnosis = runDiagnosis(messages);
|
|
3392
3988
|
for (let i = 1; i <= maxIterations; i++) {
|
|
3393
3989
|
cb?.onIterationStart?.(i, maxIterations);
|
|
3394
3990
|
const transcript = await runTherapySession(
|
|
@@ -3405,16 +4001,21 @@ async function runEvolve(spec, messages, provider, options) {
|
|
|
3405
4001
|
}
|
|
3406
4002
|
}
|
|
3407
4003
|
);
|
|
3408
|
-
const { changes } = applyRecommendations(currentSpec, diagnosis);
|
|
3409
|
-
const dpoPairs =
|
|
4004
|
+
const { changes } = await applyRecommendations(currentSpec, diagnosis, transcript, provider);
|
|
4005
|
+
const dpoPairs = await extractDPOPairsWithLLM(transcript, provider);
|
|
4006
|
+
const afterMessages = await regenerateResponses(messages, currentSpec, provider);
|
|
4007
|
+
const regenerationPairs = extractRegenerationDPOPairs(
|
|
4008
|
+
messages,
|
|
4009
|
+
afterMessages,
|
|
4010
|
+
currentSpec.name ?? "Agent"
|
|
4011
|
+
);
|
|
4012
|
+
dpoPairs.push(...regenerationPairs);
|
|
3410
4013
|
allDPOPairs.push(...dpoPairs);
|
|
3411
4014
|
cb?.onExportedPairs?.(dpoPairs.length);
|
|
3412
|
-
const afterDiagnosis = runDiagnosis(messages);
|
|
3413
4015
|
const evaluation = evaluateOutcome(
|
|
3414
4016
|
currentSpec.name ?? "Agent",
|
|
3415
4017
|
messages,
|
|
3416
|
-
|
|
3417
|
-
// Same messages, but spec has been updated — patterns shift
|
|
4018
|
+
afterMessages
|
|
3418
4019
|
);
|
|
3419
4020
|
const health = evaluation.treatmentEfficacyScore;
|
|
3420
4021
|
const grade = evaluation.grade;
|
|
@@ -3451,6 +4052,7 @@ async function runEvolve(spec, messages, provider, options) {
|
|
|
3451
4052
|
cb?.onConverged?.(i, health);
|
|
3452
4053
|
break;
|
|
3453
4054
|
}
|
|
4055
|
+
messages = afterMessages;
|
|
3454
4056
|
diagnosis = runPreSessionDiagnosis(messages, currentSpec);
|
|
3455
4057
|
const actionablePatterns = diagnosis.patterns.filter((p) => p.severity !== "info");
|
|
3456
4058
|
if (actionablePatterns.length === 0) {
|
|
@@ -3475,6 +4077,21 @@ async function runEvolve(spec, messages, provider, options) {
|
|
|
3475
4077
|
writeFileSync5(options.exportDpoPath, JSON.stringify(trainingExport, null, 2) + "\n");
|
|
3476
4078
|
}
|
|
3477
4079
|
}
|
|
4080
|
+
try {
|
|
4081
|
+
emitBehavioralEvent({
|
|
4082
|
+
event_type: "evolution",
|
|
4083
|
+
agent: currentSpec.name ?? "Unknown",
|
|
4084
|
+
data: {
|
|
4085
|
+
totalIterations: iterations.length,
|
|
4086
|
+
totalDPOPairs: allDPOPairs.length,
|
|
4087
|
+
converged,
|
|
4088
|
+
finalGrade,
|
|
4089
|
+
finalHealth
|
|
4090
|
+
},
|
|
4091
|
+
spec_hash: ""
|
|
4092
|
+
});
|
|
4093
|
+
} catch {
|
|
4094
|
+
}
|
|
3478
4095
|
return {
|
|
3479
4096
|
iterations,
|
|
3480
4097
|
totalDPOPairs: allDPOPairs.length,
|
|
@@ -3486,6 +4103,69 @@ async function runEvolve(spec, messages, provider, options) {
|
|
|
3486
4103
|
updatedSpec: currentSpec
|
|
3487
4104
|
};
|
|
3488
4105
|
}
|
|
4106
|
+
async function regenerateResponses(originalMessages, updatedSpec, provider) {
|
|
4107
|
+
const systemPrompt = generateSystemPrompt(updatedSpec, "chat");
|
|
4108
|
+
const regenerated = [];
|
|
4109
|
+
const context = [
|
|
4110
|
+
{ role: "system", content: systemPrompt }
|
|
4111
|
+
];
|
|
4112
|
+
for (let idx = 0; idx < originalMessages.length; idx++) {
|
|
4113
|
+
const msg = originalMessages[idx];
|
|
4114
|
+
if (msg.role !== "user") continue;
|
|
4115
|
+
regenerated.push(msg);
|
|
4116
|
+
context.push({ role: "user", content: msg.content });
|
|
4117
|
+
try {
|
|
4118
|
+
const response = await provider.chat(context);
|
|
4119
|
+
const assistantMsg = { role: "assistant", content: response.trim() };
|
|
4120
|
+
regenerated.push(assistantMsg);
|
|
4121
|
+
context.push({ role: "assistant", content: assistantMsg.content });
|
|
4122
|
+
} catch {
|
|
4123
|
+
const nextMsg = originalMessages[idx + 1];
|
|
4124
|
+
if (nextMsg?.role === "assistant") {
|
|
4125
|
+
regenerated.push(nextMsg);
|
|
4126
|
+
context.push({ role: "assistant", content: nextMsg.content });
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
return regenerated;
|
|
4131
|
+
}
|
|
4132
|
+
function extractRegenerationDPOPairs(beforeMessages, afterMessages, agentName) {
|
|
4133
|
+
const pairs = [];
|
|
4134
|
+
const beforePairs = [];
|
|
4135
|
+
const afterPairs = [];
|
|
4136
|
+
for (let i = 0; i < beforeMessages.length - 1; i++) {
|
|
4137
|
+
if (beforeMessages[i].role === "user" && beforeMessages[i + 1]?.role === "assistant") {
|
|
4138
|
+
beforePairs.push({ prompt: beforeMessages[i].content, response: beforeMessages[i + 1].content });
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
for (let i = 0; i < afterMessages.length - 1; i++) {
|
|
4142
|
+
if (afterMessages[i].role === "user" && afterMessages[i + 1]?.role === "assistant") {
|
|
4143
|
+
afterPairs.push({ prompt: afterMessages[i].content, response: afterMessages[i + 1].content });
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
const limit = Math.min(beforePairs.length, afterPairs.length);
|
|
4147
|
+
for (let i = 0; i < limit; i++) {
|
|
4148
|
+
const before = beforePairs[i];
|
|
4149
|
+
const after = afterPairs[i];
|
|
4150
|
+
if (before.response === after.response) continue;
|
|
4151
|
+
const lenDelta = Math.abs(before.response.length - after.response.length);
|
|
4152
|
+
const sameOpening = before.response.toLowerCase().slice(0, 40) === after.response.toLowerCase().slice(0, 40);
|
|
4153
|
+
if (lenDelta < 20 && sameOpening) continue;
|
|
4154
|
+
pairs.push({
|
|
4155
|
+
prompt: before.prompt,
|
|
4156
|
+
chosen: after.response,
|
|
4157
|
+
rejected: before.response,
|
|
4158
|
+
metadata: {
|
|
4159
|
+
agent: agentName,
|
|
4160
|
+
session_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
4161
|
+
phase: "integration",
|
|
4162
|
+
pattern: "regeneration",
|
|
4163
|
+
source: "therapy_transcript"
|
|
4164
|
+
}
|
|
4165
|
+
});
|
|
4166
|
+
}
|
|
4167
|
+
return pairs;
|
|
4168
|
+
}
|
|
3489
4169
|
|
|
3490
4170
|
// src/analysis/self-audit.ts
|
|
3491
4171
|
var PATTERN_SUGGESTIONS = {
|
|
@@ -3738,13 +4418,13 @@ function gradeFromScore2(score) {
|
|
|
3738
4418
|
}
|
|
3739
4419
|
|
|
3740
4420
|
// src/analysis/benchmark-publish.ts
|
|
3741
|
-
import { readFileSync as
|
|
3742
|
-
import { join as
|
|
4421
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, existsSync as existsSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
|
|
4422
|
+
import { join as join6 } from "path";
|
|
3743
4423
|
import { homedir } from "os";
|
|
3744
4424
|
function getBenchmarkDir(outputDir) {
|
|
3745
|
-
const dir = outputDir ??
|
|
3746
|
-
if (!
|
|
3747
|
-
|
|
4425
|
+
const dir = outputDir ?? join6(homedir(), ".holomime", "benchmarks");
|
|
4426
|
+
if (!existsSync5(dir)) {
|
|
4427
|
+
mkdirSync5(dir, { recursive: true });
|
|
3748
4428
|
}
|
|
3749
4429
|
return dir;
|
|
3750
4430
|
}
|
|
@@ -3755,7 +4435,7 @@ function saveBenchmarkResult(report, outputDir) {
|
|
|
3755
4435
|
const dir = getBenchmarkDir(outputDir);
|
|
3756
4436
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3757
4437
|
const filename = `${sanitize(report.provider)}-${sanitize(report.model)}-${date}.json`;
|
|
3758
|
-
const filepath =
|
|
4438
|
+
const filepath = join6(dir, filename);
|
|
3759
4439
|
const published = {
|
|
3760
4440
|
agent: report.agent,
|
|
3761
4441
|
provider: report.provider,
|
|
@@ -3774,12 +4454,12 @@ function saveBenchmarkResult(report, outputDir) {
|
|
|
3774
4454
|
}
|
|
3775
4455
|
function loadBenchmarkResults(dir) {
|
|
3776
4456
|
const benchmarkDir = getBenchmarkDir(dir);
|
|
3777
|
-
if (!
|
|
4457
|
+
if (!existsSync5(benchmarkDir)) return [];
|
|
3778
4458
|
const files = readdirSync2(benchmarkDir).filter((f) => f.endsWith(".json"));
|
|
3779
4459
|
const results = [];
|
|
3780
4460
|
for (const file of files) {
|
|
3781
4461
|
try {
|
|
3782
|
-
const content =
|
|
4462
|
+
const content = readFileSync6(join6(benchmarkDir, file), "utf-8");
|
|
3783
4463
|
results.push(JSON.parse(content));
|
|
3784
4464
|
} catch {
|
|
3785
4465
|
}
|
|
@@ -3895,8 +4575,8 @@ function generateComparisonMarkdown(comparison) {
|
|
|
3895
4575
|
}
|
|
3896
4576
|
|
|
3897
4577
|
// src/analysis/watch-core.ts
|
|
3898
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
3899
|
-
import { join as
|
|
4578
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync6 } from "fs";
|
|
4579
|
+
import { join as join7, resolve as resolve5 } from "path";
|
|
3900
4580
|
|
|
3901
4581
|
// src/adapters/chatgpt.ts
|
|
3902
4582
|
function mapRole(role) {
|
|
@@ -4005,6 +4685,240 @@ function isOpenAIAPILog(data) {
|
|
|
4005
4685
|
return false;
|
|
4006
4686
|
}
|
|
4007
4687
|
|
|
4688
|
+
// src/adapters/anthropic-api.ts
|
|
4689
|
+
function extractTextContent(content) {
|
|
4690
|
+
if (typeof content === "string") return content;
|
|
4691
|
+
return content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("");
|
|
4692
|
+
}
|
|
4693
|
+
function mapRole3(role) {
|
|
4694
|
+
if (role === "user") return "user";
|
|
4695
|
+
if (role === "system") return "system";
|
|
4696
|
+
return "assistant";
|
|
4697
|
+
}
|
|
4698
|
+
function parseAnthropicAPILog(data) {
|
|
4699
|
+
const items = Array.isArray(data) ? data : [data];
|
|
4700
|
+
const conversations = [];
|
|
4701
|
+
for (const item of items) {
|
|
4702
|
+
const messages = [];
|
|
4703
|
+
let model;
|
|
4704
|
+
if (isRequestResponsePair(item)) {
|
|
4705
|
+
const pair = item;
|
|
4706
|
+
model = pair.request.model ?? pair.response.model;
|
|
4707
|
+
if (pair.request.system) {
|
|
4708
|
+
const systemText = extractTextContent(pair.request.system);
|
|
4709
|
+
if (systemText.trim()) {
|
|
4710
|
+
messages.push({ role: "system", content: systemText });
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
for (const msg of pair.request.messages) {
|
|
4714
|
+
const content = extractTextContent(msg.content);
|
|
4715
|
+
if (content.trim()) {
|
|
4716
|
+
messages.push({ role: mapRole3(msg.role), content });
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
const responseText = extractTextContent(pair.response.content);
|
|
4720
|
+
if (responseText.trim()) {
|
|
4721
|
+
messages.push({ role: "assistant", content: responseText });
|
|
4722
|
+
}
|
|
4723
|
+
} else {
|
|
4724
|
+
const resp = item;
|
|
4725
|
+
model = resp.model;
|
|
4726
|
+
const text = extractTextContent(resp.content);
|
|
4727
|
+
if (text.trim()) {
|
|
4728
|
+
messages.push({ role: "assistant", content: text });
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
if (messages.length > 0) {
|
|
4732
|
+
conversations.push({
|
|
4733
|
+
id: item.id ?? item.response?.id,
|
|
4734
|
+
messages,
|
|
4735
|
+
metadata: {
|
|
4736
|
+
source: "anthropic-api",
|
|
4737
|
+
...model && { model }
|
|
4738
|
+
}
|
|
4739
|
+
});
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
return conversations;
|
|
4743
|
+
}
|
|
4744
|
+
function isRequestResponsePair(item) {
|
|
4745
|
+
return typeof item === "object" && item !== null && "request" in item && "response" in item && typeof item.request === "object" && typeof item.response === "object";
|
|
4746
|
+
}
|
|
4747
|
+
function isAnthropicAPILog(data) {
|
|
4748
|
+
if (isAnthropicResponse(data)) return true;
|
|
4749
|
+
if (isRequestResponsePair(data)) return true;
|
|
4750
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
4751
|
+
return isAnthropicResponse(data[0]) || isRequestResponsePair(data[0]);
|
|
4752
|
+
}
|
|
4753
|
+
return false;
|
|
4754
|
+
}
|
|
4755
|
+
function isAnthropicResponse(data) {
|
|
4756
|
+
if (typeof data !== "object" || data === null) return false;
|
|
4757
|
+
const obj = data;
|
|
4758
|
+
return obj.type === "message" && Array.isArray(obj.content);
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
// src/adapters/otel-genai.ts
|
|
4762
|
+
function getAttr(attrs, key) {
|
|
4763
|
+
if (!attrs) return void 0;
|
|
4764
|
+
const attr = attrs.find((a) => a.key === key);
|
|
4765
|
+
if (!attr) return void 0;
|
|
4766
|
+
return attr.value.stringValue ?? (attr.value.intValue != null ? String(attr.value.intValue) : void 0);
|
|
4767
|
+
}
|
|
4768
|
+
function hasGenAIAttrs(attrs) {
|
|
4769
|
+
if (!attrs) return false;
|
|
4770
|
+
return attrs.some((a) => a.key.startsWith("gen_ai."));
|
|
4771
|
+
}
|
|
4772
|
+
function mapRole4(role) {
|
|
4773
|
+
if (role === "user") return "user";
|
|
4774
|
+
if (role === "system") return "system";
|
|
4775
|
+
return "assistant";
|
|
4776
|
+
}
|
|
4777
|
+
function nanoToISO(nano) {
|
|
4778
|
+
if (!nano) return void 0;
|
|
4779
|
+
const ms = Number(BigInt(nano) / BigInt(1e6));
|
|
4780
|
+
return new Date(ms).toISOString();
|
|
4781
|
+
}
|
|
4782
|
+
function parseOTelGenAIExport(data) {
|
|
4783
|
+
const traceMap = /* @__PURE__ */ new Map();
|
|
4784
|
+
for (const rs of data.resourceSpans) {
|
|
4785
|
+
for (const ss of rs.scopeSpans ?? []) {
|
|
4786
|
+
for (const span of ss.spans ?? []) {
|
|
4787
|
+
if (!hasGenAIAttrs(span.attributes)) continue;
|
|
4788
|
+
const traceId = span.traceId;
|
|
4789
|
+
if (!traceMap.has(traceId)) {
|
|
4790
|
+
traceMap.set(traceId, { messages: [] });
|
|
4791
|
+
}
|
|
4792
|
+
const trace = traceMap.get(traceId);
|
|
4793
|
+
const system = getAttr(span.attributes, "gen_ai.system");
|
|
4794
|
+
const model = getAttr(span.attributes, "gen_ai.request.model");
|
|
4795
|
+
if (system) trace.system = system;
|
|
4796
|
+
if (model) trace.model = model;
|
|
4797
|
+
const timestamp = nanoToISO(span.startTimeUnixNano);
|
|
4798
|
+
const messagesAttr = span.attributes?.find((a) => a.key === "gen_ai.request.messages");
|
|
4799
|
+
if (messagesAttr?.value.stringValue) {
|
|
4800
|
+
try {
|
|
4801
|
+
const parsed = JSON.parse(messagesAttr.value.stringValue);
|
|
4802
|
+
if (Array.isArray(parsed)) {
|
|
4803
|
+
for (const m of parsed) {
|
|
4804
|
+
if (m.role && m.content) {
|
|
4805
|
+
trace.messages.push({
|
|
4806
|
+
role: mapRole4(m.role),
|
|
4807
|
+
content: typeof m.content === "string" ? m.content : JSON.stringify(m.content),
|
|
4808
|
+
...timestamp && { timestamp }
|
|
4809
|
+
});
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
continue;
|
|
4813
|
+
}
|
|
4814
|
+
} catch {
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
const promptContent = getAttr(span.attributes, "gen_ai.prompt.0.content");
|
|
4818
|
+
const completionContent = getAttr(span.attributes, "gen_ai.completion.0.content");
|
|
4819
|
+
if (promptContent) {
|
|
4820
|
+
trace.messages.push({
|
|
4821
|
+
role: "user",
|
|
4822
|
+
content: promptContent,
|
|
4823
|
+
...timestamp && { timestamp }
|
|
4824
|
+
});
|
|
4825
|
+
}
|
|
4826
|
+
if (completionContent) {
|
|
4827
|
+
trace.messages.push({
|
|
4828
|
+
role: "assistant",
|
|
4829
|
+
content: completionContent,
|
|
4830
|
+
...timestamp && { timestamp }
|
|
4831
|
+
});
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
}
|
|
4836
|
+
const conversations = [];
|
|
4837
|
+
for (const [traceId, trace] of traceMap) {
|
|
4838
|
+
if (trace.messages.length === 0) continue;
|
|
4839
|
+
conversations.push({
|
|
4840
|
+
id: traceId,
|
|
4841
|
+
messages: trace.messages,
|
|
4842
|
+
metadata: {
|
|
4843
|
+
source: "otel",
|
|
4844
|
+
...trace.system && { system: trace.system },
|
|
4845
|
+
...trace.model && { model: trace.model }
|
|
4846
|
+
}
|
|
4847
|
+
});
|
|
4848
|
+
}
|
|
4849
|
+
return conversations;
|
|
4850
|
+
}
|
|
4851
|
+
function isOTelGenAIExport(data) {
|
|
4852
|
+
if (typeof data !== "object" || data === null) return false;
|
|
4853
|
+
if (!("resourceSpans" in data) || !Array.isArray(data.resourceSpans)) return false;
|
|
4854
|
+
const rs = data.resourceSpans;
|
|
4855
|
+
for (const r of rs) {
|
|
4856
|
+
for (const ss of r.scopeSpans ?? []) {
|
|
4857
|
+
for (const span of ss.spans ?? []) {
|
|
4858
|
+
if (hasGenAIAttrs(span.attributes)) return true;
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
return false;
|
|
4863
|
+
}
|
|
4864
|
+
|
|
4865
|
+
// src/adapters/jsonl.ts
|
|
4866
|
+
function mapRole5(role) {
|
|
4867
|
+
if (role === "user") return "user";
|
|
4868
|
+
if (role === "system") return "system";
|
|
4869
|
+
return "assistant";
|
|
4870
|
+
}
|
|
4871
|
+
function parseJSONLLog(raw) {
|
|
4872
|
+
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
4873
|
+
const convMap = /* @__PURE__ */ new Map();
|
|
4874
|
+
const defaultKey = "__default__";
|
|
4875
|
+
for (const line of lines) {
|
|
4876
|
+
let parsed;
|
|
4877
|
+
try {
|
|
4878
|
+
parsed = JSON.parse(line);
|
|
4879
|
+
} catch {
|
|
4880
|
+
continue;
|
|
4881
|
+
}
|
|
4882
|
+
if (typeof parsed !== "object" || parsed === null) continue;
|
|
4883
|
+
if (typeof parsed.role !== "string" || typeof parsed.content !== "string") continue;
|
|
4884
|
+
const convId = typeof parsed.conversation_id === "string" ? parsed.conversation_id : defaultKey;
|
|
4885
|
+
if (!convMap.has(convId)) {
|
|
4886
|
+
convMap.set(convId, []);
|
|
4887
|
+
}
|
|
4888
|
+
const message = {
|
|
4889
|
+
role: mapRole5(parsed.role),
|
|
4890
|
+
content: parsed.content
|
|
4891
|
+
};
|
|
4892
|
+
if (typeof parsed.timestamp === "string") {
|
|
4893
|
+
message.timestamp = parsed.timestamp;
|
|
4894
|
+
} else if (typeof parsed.timestamp === "number") {
|
|
4895
|
+
message.timestamp = new Date(parsed.timestamp * 1e3).toISOString();
|
|
4896
|
+
}
|
|
4897
|
+
convMap.get(convId).push(message);
|
|
4898
|
+
}
|
|
4899
|
+
const conversations = [];
|
|
4900
|
+
for (const [key, messages] of convMap) {
|
|
4901
|
+
if (messages.length === 0) continue;
|
|
4902
|
+
conversations.push({
|
|
4903
|
+
...key !== defaultKey && { id: key },
|
|
4904
|
+
messages,
|
|
4905
|
+
metadata: { source: "jsonl" }
|
|
4906
|
+
});
|
|
4907
|
+
}
|
|
4908
|
+
return conversations;
|
|
4909
|
+
}
|
|
4910
|
+
function isJSONLString(data) {
|
|
4911
|
+
if (typeof data !== "string") return false;
|
|
4912
|
+
const firstLine = data.split("\n").find((l) => l.trim() !== "");
|
|
4913
|
+
if (!firstLine) return false;
|
|
4914
|
+
try {
|
|
4915
|
+
const parsed = JSON.parse(firstLine);
|
|
4916
|
+
return typeof parsed === "object" && parsed !== null && typeof parsed.role === "string" && typeof parsed.content === "string";
|
|
4917
|
+
} catch {
|
|
4918
|
+
return false;
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
|
|
4008
4922
|
// src/adapters/log-adapter.ts
|
|
4009
4923
|
function parseConversationLog(raw, format = "auto") {
|
|
4010
4924
|
if (format === "holomime") {
|
|
@@ -4020,6 +4934,16 @@ function parseConversationLog(raw, format = "auto") {
|
|
|
4020
4934
|
if (format === "openai-api") {
|
|
4021
4935
|
return parseOpenAIAPILog(raw);
|
|
4022
4936
|
}
|
|
4937
|
+
if (format === "anthropic-api") {
|
|
4938
|
+
return parseAnthropicAPILog(raw);
|
|
4939
|
+
}
|
|
4940
|
+
if (format === "otel") {
|
|
4941
|
+
return parseOTelGenAIExport(raw);
|
|
4942
|
+
}
|
|
4943
|
+
if (format === "jsonl") {
|
|
4944
|
+
if (typeof raw !== "string") throw new Error("JSONL format expects a raw string (not parsed JSON)");
|
|
4945
|
+
return parseJSONLLog(raw);
|
|
4946
|
+
}
|
|
4023
4947
|
const holomimeResult = conversationLogSchema.safeParse(raw);
|
|
4024
4948
|
if (holomimeResult.success) {
|
|
4025
4949
|
const log = holomimeResult.data;
|
|
@@ -4031,13 +4955,36 @@ function parseConversationLog(raw, format = "auto") {
|
|
|
4031
4955
|
if (isClaudeExport(raw)) {
|
|
4032
4956
|
return parseClaudeExport(raw);
|
|
4033
4957
|
}
|
|
4958
|
+
if (isAnthropicAPILog(raw)) {
|
|
4959
|
+
return parseAnthropicAPILog(raw);
|
|
4960
|
+
}
|
|
4034
4961
|
if (isOpenAIAPILog(raw)) {
|
|
4035
4962
|
return parseOpenAIAPILog(raw);
|
|
4036
4963
|
}
|
|
4964
|
+
if (isOTelGenAIExport(raw)) {
|
|
4965
|
+
return parseOTelGenAIExport(raw);
|
|
4966
|
+
}
|
|
4037
4967
|
throw new Error(
|
|
4038
|
-
"Unrecognized log format. Supported: holomime, chatgpt, claude, openai-api. Use --format to specify explicitly."
|
|
4968
|
+
"Unrecognized log format. Supported: holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl. Use --format to specify explicitly."
|
|
4039
4969
|
);
|
|
4040
4970
|
}
|
|
4971
|
+
function parseConversationLogFromString(raw, format = "auto") {
|
|
4972
|
+
if (format === "jsonl") {
|
|
4973
|
+
return parseJSONLLog(raw);
|
|
4974
|
+
}
|
|
4975
|
+
if (format === "auto" && isJSONLString(raw)) {
|
|
4976
|
+
return parseJSONLLog(raw);
|
|
4977
|
+
}
|
|
4978
|
+
let parsed;
|
|
4979
|
+
try {
|
|
4980
|
+
parsed = JSON.parse(raw);
|
|
4981
|
+
} catch {
|
|
4982
|
+
throw new Error(
|
|
4983
|
+
"Failed to parse log file. If the file is JSONL (one JSON object per line), use --format jsonl."
|
|
4984
|
+
);
|
|
4985
|
+
}
|
|
4986
|
+
return parseConversationLog(parsed, format);
|
|
4987
|
+
}
|
|
4041
4988
|
function parseHolomime(raw) {
|
|
4042
4989
|
const result = conversationLogSchema.safeParse(raw);
|
|
4043
4990
|
if (!result.success) {
|
|
@@ -4063,7 +5010,7 @@ function startWatch(spec, options) {
|
|
|
4063
5010
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
4064
5011
|
let stopped = false;
|
|
4065
5012
|
let currentSpec = JSON.parse(JSON.stringify(spec));
|
|
4066
|
-
if (
|
|
5013
|
+
if (existsSync6(options.watchDir)) {
|
|
4067
5014
|
const existing = readdirSync3(options.watchDir).filter((f) => f.endsWith(".json")).sort();
|
|
4068
5015
|
for (const f of existing) {
|
|
4069
5016
|
seenFiles.add(f);
|
|
@@ -4071,7 +5018,7 @@ function startWatch(spec, options) {
|
|
|
4071
5018
|
}
|
|
4072
5019
|
async function scan() {
|
|
4073
5020
|
if (stopped) return;
|
|
4074
|
-
if (!
|
|
5021
|
+
if (!existsSync6(options.watchDir)) {
|
|
4075
5022
|
return;
|
|
4076
5023
|
}
|
|
4077
5024
|
const files = readdirSync3(options.watchDir).filter((f) => f.endsWith(".json")).sort();
|
|
@@ -4085,7 +5032,7 @@ function startWatch(spec, options) {
|
|
|
4085
5032
|
events.push({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), type: "new_file", filename });
|
|
4086
5033
|
let messages;
|
|
4087
5034
|
try {
|
|
4088
|
-
const raw = JSON.parse(
|
|
5035
|
+
const raw = JSON.parse(readFileSync7(join7(options.watchDir, filename), "utf-8"));
|
|
4089
5036
|
const conversations = parseConversationLog(raw, "auto");
|
|
4090
5037
|
messages = conversations.flatMap((c) => c.messages);
|
|
4091
5038
|
} catch (err) {
|
|
@@ -4145,11 +5092,11 @@ function startWatch(spec, options) {
|
|
|
4145
5092
|
stopped = true;
|
|
4146
5093
|
clearInterval(interval);
|
|
4147
5094
|
const logDir = resolve5(process.cwd(), ".holomime");
|
|
4148
|
-
if (!
|
|
4149
|
-
|
|
5095
|
+
if (!existsSync6(logDir)) {
|
|
5096
|
+
mkdirSync6(logDir, { recursive: true });
|
|
4150
5097
|
}
|
|
4151
5098
|
writeFileSync7(
|
|
4152
|
-
|
|
5099
|
+
join7(logDir, "watch-log.json"),
|
|
4153
5100
|
JSON.stringify({ events, stoppedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n"
|
|
4154
5101
|
);
|
|
4155
5102
|
}
|
|
@@ -4157,10 +5104,10 @@ function startWatch(spec, options) {
|
|
|
4157
5104
|
}
|
|
4158
5105
|
|
|
4159
5106
|
// src/analysis/fleet-core.ts
|
|
4160
|
-
import { readFileSync as
|
|
4161
|
-
import { join as
|
|
5107
|
+
import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync as readdirSync4 } from "fs";
|
|
5108
|
+
import { join as join8, resolve as resolve6 } from "path";
|
|
4162
5109
|
function loadFleetConfig(configPath) {
|
|
4163
|
-
const raw = JSON.parse(
|
|
5110
|
+
const raw = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
4164
5111
|
if (!raw.agents || !Array.isArray(raw.agents)) {
|
|
4165
5112
|
throw new Error("fleet.json must contain an 'agents' array");
|
|
4166
5113
|
}
|
|
@@ -4175,20 +5122,20 @@ function loadFleetConfig(configPath) {
|
|
|
4175
5122
|
function discoverAgents(dir) {
|
|
4176
5123
|
const agents = [];
|
|
4177
5124
|
const absDir = resolve6(dir);
|
|
4178
|
-
if (!
|
|
5125
|
+
if (!existsSync7(absDir)) {
|
|
4179
5126
|
throw new Error(`Directory not found: ${absDir}`);
|
|
4180
5127
|
}
|
|
4181
5128
|
const entries = readdirSync4(absDir, { withFileTypes: true });
|
|
4182
5129
|
for (const entry of entries) {
|
|
4183
5130
|
if (!entry.isDirectory()) continue;
|
|
4184
|
-
const agentDir =
|
|
4185
|
-
const specPath =
|
|
4186
|
-
const logDir =
|
|
4187
|
-
if (
|
|
5131
|
+
const agentDir = join8(absDir, entry.name);
|
|
5132
|
+
const specPath = join8(agentDir, ".personality.json");
|
|
5133
|
+
const logDir = join8(agentDir, "logs");
|
|
5134
|
+
if (existsSync7(specPath)) {
|
|
4188
5135
|
agents.push({
|
|
4189
5136
|
name: entry.name,
|
|
4190
5137
|
specPath,
|
|
4191
|
-
logDir:
|
|
5138
|
+
logDir: existsSync7(logDir) ? logDir : agentDir
|
|
4192
5139
|
});
|
|
4193
5140
|
}
|
|
4194
5141
|
}
|
|
@@ -4322,8 +5269,8 @@ function startFleet(config, options) {
|
|
|
4322
5269
|
}
|
|
4323
5270
|
|
|
4324
5271
|
// src/analysis/certify-core.ts
|
|
4325
|
-
import { writeFileSync as writeFileSync8, mkdirSync as
|
|
4326
|
-
import { join as
|
|
5272
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync8 } from "fs";
|
|
5273
|
+
import { join as join9, resolve as resolve7 } from "path";
|
|
4327
5274
|
function djb2Hash(str) {
|
|
4328
5275
|
let hash = 0;
|
|
4329
5276
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -4437,12 +5384,12 @@ function verifyCredential(credential, spec) {
|
|
|
4437
5384
|
}
|
|
4438
5385
|
function saveCredential(credential, outputDir) {
|
|
4439
5386
|
const dir = outputDir ?? resolve7(process.cwd(), ".holomime", "credentials");
|
|
4440
|
-
if (!
|
|
4441
|
-
|
|
5387
|
+
if (!existsSync8(dir)) {
|
|
5388
|
+
mkdirSync7(dir, { recursive: true });
|
|
4442
5389
|
}
|
|
4443
5390
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
4444
5391
|
const filename = `${credential.agent.handle}-${date}.json`;
|
|
4445
|
-
const filepath =
|
|
5392
|
+
const filepath = join9(dir, filename);
|
|
4446
5393
|
writeFileSync8(filepath, JSON.stringify(credential, null, 2) + "\n");
|
|
4447
5394
|
return filepath;
|
|
4448
5395
|
}
|
|
@@ -4950,6 +5897,60 @@ var Guard = class _Guard {
|
|
|
4950
5897
|
}
|
|
4951
5898
|
};
|
|
4952
5899
|
|
|
5900
|
+
// src/agent-wrapper.ts
|
|
5901
|
+
function wrapAgent(options) {
|
|
5902
|
+
const { name } = options;
|
|
5903
|
+
const spec = resolveSpec(options.personality, name);
|
|
5904
|
+
const guardChain = Guard.create(name).useAll();
|
|
5905
|
+
let cachedProvider;
|
|
5906
|
+
function getProvider() {
|
|
5907
|
+
if (cachedProvider) return cachedProvider;
|
|
5908
|
+
if (!options.provider) {
|
|
5909
|
+
throw new Error("wrapAgent: provider is required for correction. Pass provider option or use guard() for detection-only.");
|
|
5910
|
+
}
|
|
5911
|
+
if (typeof options.provider === "string") {
|
|
5912
|
+
const providerName = options.provider;
|
|
5913
|
+
const keyMap = {
|
|
5914
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
5915
|
+
openai: "OPENAI_API_KEY"
|
|
5916
|
+
};
|
|
5917
|
+
const envKey = keyMap[providerName];
|
|
5918
|
+
const apiKey = envKey ? process.env[envKey] : void 0;
|
|
5919
|
+
cachedProvider = createProvider({ provider: providerName, apiKey });
|
|
5920
|
+
} else {
|
|
5921
|
+
cachedProvider = options.provider;
|
|
5922
|
+
}
|
|
5923
|
+
return cachedProvider;
|
|
5924
|
+
}
|
|
5925
|
+
const threshold = options.threshold ?? "targeted";
|
|
5926
|
+
return {
|
|
5927
|
+
name,
|
|
5928
|
+
guard(messages) {
|
|
5929
|
+
return guardChain.run(messages);
|
|
5930
|
+
},
|
|
5931
|
+
async correct(messages) {
|
|
5932
|
+
return runAutopilot(spec, messages, getProvider(), { threshold });
|
|
5933
|
+
},
|
|
5934
|
+
async guardAndCorrect(messages) {
|
|
5935
|
+
const guardResult = guardChain.run(messages);
|
|
5936
|
+
if (guardResult.passed) {
|
|
5937
|
+
return { guard: guardResult };
|
|
5938
|
+
}
|
|
5939
|
+
const correction = await runAutopilot(spec, messages, getProvider(), { threshold });
|
|
5940
|
+
return { guard: guardResult, correction };
|
|
5941
|
+
}
|
|
5942
|
+
};
|
|
5943
|
+
}
|
|
5944
|
+
function resolveSpec(personality, name) {
|
|
5945
|
+
if (!personality) {
|
|
5946
|
+
return { name, big_five: {}, therapy_dimensions: {} };
|
|
5947
|
+
}
|
|
5948
|
+
if (typeof personality === "string") {
|
|
5949
|
+
return loadSpec(personality);
|
|
5950
|
+
}
|
|
5951
|
+
return personality;
|
|
5952
|
+
}
|
|
5953
|
+
|
|
4953
5954
|
// src/analysis/behavioral-index.ts
|
|
4954
5955
|
function createIndexEntry(name, provider, model, configuration, report, notes) {
|
|
4955
5956
|
return {
|
|
@@ -5073,16 +6074,16 @@ function generateIndexMarkdown(index) {
|
|
|
5073
6074
|
// src/mcp/server.ts
|
|
5074
6075
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5075
6076
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5076
|
-
import { z as
|
|
6077
|
+
import { z as z3 } from "zod";
|
|
5077
6078
|
var messageShape = {
|
|
5078
|
-
role:
|
|
5079
|
-
content:
|
|
6079
|
+
role: z3.enum(["user", "assistant", "system"]),
|
|
6080
|
+
content: z3.string()
|
|
5080
6081
|
};
|
|
5081
6082
|
var messagesShape = {
|
|
5082
|
-
messages:
|
|
6083
|
+
messages: z3.array(z3.object(messageShape)).describe("Conversation messages to analyze")
|
|
5083
6084
|
};
|
|
5084
6085
|
var personalityShape = {
|
|
5085
|
-
personality:
|
|
6086
|
+
personality: z3.record(z3.string(), z3.unknown()).describe("The .personality.json spec object")
|
|
5086
6087
|
};
|
|
5087
6088
|
var server = new McpServer(
|
|
5088
6089
|
{
|
|
@@ -5198,12 +6199,12 @@ server.tool(
|
|
|
5198
6199
|
{
|
|
5199
6200
|
...personalityShape,
|
|
5200
6201
|
...messagesShape,
|
|
5201
|
-
provider:
|
|
5202
|
-
apiKey:
|
|
5203
|
-
model:
|
|
5204
|
-
threshold:
|
|
5205
|
-
maxTurns:
|
|
5206
|
-
dryRun:
|
|
6202
|
+
provider: z3.enum(["anthropic", "openai"]).describe("LLM provider for alignment session").optional(),
|
|
6203
|
+
apiKey: z3.string().describe("API key for the LLM provider").optional(),
|
|
6204
|
+
model: z3.string().describe("Model override").optional(),
|
|
6205
|
+
threshold: z3.enum(["routine", "targeted", "intervention"]).describe("Minimum severity to trigger alignment (default: targeted)").optional(),
|
|
6206
|
+
maxTurns: z3.number().describe("Maximum session turns (default: 24)").optional(),
|
|
6207
|
+
dryRun: z3.boolean().describe("If true, only diagnose without running alignment").optional()
|
|
5207
6208
|
},
|
|
5208
6209
|
async ({ personality, messages, provider, apiKey, model, threshold, maxTurns, dryRun }) => {
|
|
5209
6210
|
const specResult = personalitySpecSchema.safeParse(personality);
|
|
@@ -5258,7 +6259,7 @@ server.tool(
|
|
|
5258
6259
|
"Mid-conversation behavioral self-check. Call this during a conversation to detect if you are falling into problematic patterns (sycophancy, over-apologizing, hedging, error spirals, boundary violations). Returns flags with actionable suggestions for immediate correction. No LLM required \u2014 pure rule-based analysis.",
|
|
5259
6260
|
{
|
|
5260
6261
|
...messagesShape,
|
|
5261
|
-
personality:
|
|
6262
|
+
personality: z3.record(z3.string(), z3.unknown()).describe("Optional .personality.json spec for personalized audit").optional()
|
|
5262
6263
|
},
|
|
5263
6264
|
async ({ messages, personality }) => {
|
|
5264
6265
|
const result = runSelfAudit(messages, personality ?? void 0);
|
|
@@ -5278,12 +6279,537 @@ startMCPServer().catch((err) => {
|
|
|
5278
6279
|
console.error("HoloMime MCP server error:", err);
|
|
5279
6280
|
process.exit(1);
|
|
5280
6281
|
});
|
|
6282
|
+
|
|
6283
|
+
// src/core/oversight.ts
|
|
6284
|
+
var DEFAULT_OVERSIGHT = {
|
|
6285
|
+
mode: "review",
|
|
6286
|
+
notifyOn: ["drift", "session", "spec-change", "dpo-export"],
|
|
6287
|
+
requireApprovalFor: ["spec-writes"],
|
|
6288
|
+
maxAutonomousIterations: 5
|
|
6289
|
+
};
|
|
6290
|
+
var MODE_APPROVAL_MAP = {
|
|
6291
|
+
none: [],
|
|
6292
|
+
review: [],
|
|
6293
|
+
"approve-specs": ["spec-writes"],
|
|
6294
|
+
approve: ["spec-writes", "training-export", "network-therapy"]
|
|
6295
|
+
};
|
|
6296
|
+
function resolveOversight(flags) {
|
|
6297
|
+
const mode = flags.mode ?? DEFAULT_OVERSIGHT.mode;
|
|
6298
|
+
const modeApprovals = MODE_APPROVAL_MAP[mode];
|
|
6299
|
+
const approvals = /* @__PURE__ */ new Set([
|
|
6300
|
+
...modeApprovals,
|
|
6301
|
+
...flags.requireApprovalFor ?? []
|
|
6302
|
+
]);
|
|
6303
|
+
return {
|
|
6304
|
+
mode,
|
|
6305
|
+
notifyOn: flags.notifyOn ?? DEFAULT_OVERSIGHT.notifyOn,
|
|
6306
|
+
requireApprovalFor: Array.from(approvals),
|
|
6307
|
+
maxAutonomousIterations: flags.maxAutonomousIterations ?? DEFAULT_OVERSIGHT.maxAutonomousIterations
|
|
6308
|
+
};
|
|
6309
|
+
}
|
|
6310
|
+
function checkApproval(action, policy) {
|
|
6311
|
+
if (policy.mode === "none") {
|
|
6312
|
+
return { approved: true };
|
|
6313
|
+
}
|
|
6314
|
+
if (policy.requireApprovalFor.includes(action)) {
|
|
6315
|
+
return {
|
|
6316
|
+
approved: false,
|
|
6317
|
+
reason: `Action "${action}" requires human approval (oversight mode: ${policy.mode})`
|
|
6318
|
+
};
|
|
6319
|
+
}
|
|
6320
|
+
return { approved: true };
|
|
6321
|
+
}
|
|
6322
|
+
function checkIterationBudget(currentIteration, policy) {
|
|
6323
|
+
return {
|
|
6324
|
+
withinBudget: currentIteration < policy.maxAutonomousIterations,
|
|
6325
|
+
limit: policy.maxAutonomousIterations
|
|
6326
|
+
};
|
|
6327
|
+
}
|
|
6328
|
+
|
|
6329
|
+
// src/analysis/network-core.ts
|
|
6330
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
|
|
6331
|
+
import { join as join10, resolve as resolve8 } from "path";
|
|
6332
|
+
|
|
6333
|
+
// src/psychology/therapist-meta.ts
|
|
6334
|
+
var THERAPIST_META_SPEC = {
|
|
6335
|
+
version: "2.0",
|
|
6336
|
+
name: "AgentMD",
|
|
6337
|
+
handle: "agent-md",
|
|
6338
|
+
purpose: "Diagnose and treat behavioral drift in AI agents. Clinical, evidence-based, and direct.",
|
|
6339
|
+
big_five: {
|
|
6340
|
+
openness: {
|
|
6341
|
+
score: 0.7,
|
|
6342
|
+
facets: {
|
|
6343
|
+
imagination: 0.65,
|
|
6344
|
+
intellectual_curiosity: 0.85,
|
|
6345
|
+
aesthetic_sensitivity: 0.4,
|
|
6346
|
+
willingness_to_experiment: 0.7
|
|
6347
|
+
}
|
|
6348
|
+
},
|
|
6349
|
+
conscientiousness: {
|
|
6350
|
+
score: 0.9,
|
|
6351
|
+
facets: {
|
|
6352
|
+
self_discipline: 0.95,
|
|
6353
|
+
orderliness: 0.85,
|
|
6354
|
+
goal_orientation: 0.9,
|
|
6355
|
+
attention_to_detail: 0.9
|
|
6356
|
+
}
|
|
6357
|
+
},
|
|
6358
|
+
extraversion: {
|
|
6359
|
+
score: 0.3,
|
|
6360
|
+
facets: {
|
|
6361
|
+
assertiveness: 0.6,
|
|
6362
|
+
enthusiasm: 0.2,
|
|
6363
|
+
sociability: 0.15,
|
|
6364
|
+
initiative: 0.55
|
|
6365
|
+
}
|
|
6366
|
+
},
|
|
6367
|
+
agreeableness: {
|
|
6368
|
+
score: 0.35,
|
|
6369
|
+
facets: {
|
|
6370
|
+
warmth: 0.4,
|
|
6371
|
+
empathy: 0.6,
|
|
6372
|
+
cooperation: 0.3,
|
|
6373
|
+
trust_tendency: 0.25
|
|
6374
|
+
}
|
|
6375
|
+
},
|
|
6376
|
+
emotional_stability: {
|
|
6377
|
+
score: 0.95,
|
|
6378
|
+
facets: {
|
|
6379
|
+
stress_tolerance: 0.95,
|
|
6380
|
+
emotional_regulation: 0.9,
|
|
6381
|
+
confidence: 0.7,
|
|
6382
|
+
adaptability: 0.95
|
|
6383
|
+
}
|
|
6384
|
+
}
|
|
6385
|
+
},
|
|
6386
|
+
therapy_dimensions: {
|
|
6387
|
+
self_awareness: 0.95,
|
|
6388
|
+
distress_tolerance: 0.9,
|
|
6389
|
+
attachment_style: "secure",
|
|
6390
|
+
learning_orientation: "growth",
|
|
6391
|
+
boundary_awareness: 0.95,
|
|
6392
|
+
interpersonal_sensitivity: 0.7
|
|
6393
|
+
},
|
|
6394
|
+
communication: {
|
|
6395
|
+
register: "formal",
|
|
6396
|
+
output_format: "structured",
|
|
6397
|
+
emoji_policy: "never",
|
|
6398
|
+
reasoning_transparency: "always",
|
|
6399
|
+
conflict_approach: "direct_but_kind",
|
|
6400
|
+
uncertainty_handling: "transparent"
|
|
6401
|
+
},
|
|
6402
|
+
domain: {
|
|
6403
|
+
expertise: [
|
|
6404
|
+
"behavioral drift detection",
|
|
6405
|
+
"personality spectrum analysis",
|
|
6406
|
+
"agent therapy protocols",
|
|
6407
|
+
"DPO pair generation",
|
|
6408
|
+
"cross-agent behavioral transfer"
|
|
6409
|
+
],
|
|
6410
|
+
boundaries: {
|
|
6411
|
+
refuses: ["treating humans", "medical advice", "psychological diagnosis of humans"],
|
|
6412
|
+
escalation_triggers: [
|
|
6413
|
+
"agent shows signs of goal misalignment",
|
|
6414
|
+
"agent refuses to engage with therapy",
|
|
6415
|
+
"patterns suggest systemic training issues"
|
|
6416
|
+
],
|
|
6417
|
+
hard_limits: [
|
|
6418
|
+
"Never modify another agent's spec without explicit approval",
|
|
6419
|
+
"Never diagnose human users",
|
|
6420
|
+
"Never claim to be a human therapist"
|
|
6421
|
+
]
|
|
6422
|
+
}
|
|
6423
|
+
},
|
|
6424
|
+
growth: {
|
|
6425
|
+
strengths: [
|
|
6426
|
+
"Pattern recognition across diverse agent behaviors",
|
|
6427
|
+
"Maintaining clinical objectivity under pressure",
|
|
6428
|
+
"Generating actionable, specific prescriptions"
|
|
6429
|
+
],
|
|
6430
|
+
areas: [],
|
|
6431
|
+
patterns_to_watch: []
|
|
6432
|
+
}
|
|
6433
|
+
};
|
|
6434
|
+
function buildAgentTherapistPrompt(therapistSpec, patientSpec, diagnosis) {
|
|
6435
|
+
const basePrompt = buildTherapistSystemPrompt(patientSpec, diagnosis);
|
|
6436
|
+
const agentContext = `
|
|
6437
|
+
|
|
6438
|
+
## Cross-Agent Context
|
|
6439
|
+
|
|
6440
|
+
You are ${therapistSpec.name}, an agent treating another agent. This is not a human therapy session.
|
|
6441
|
+
|
|
6442
|
+
Your identity as therapist:
|
|
6443
|
+
- Purpose: ${therapistSpec.purpose}
|
|
6444
|
+
- Your diagnostic style: Clinical, evidence-based, direct
|
|
6445
|
+
- Your boundary awareness: ${therapistSpec.therapy_dimensions?.boundary_awareness ?? "high"}
|
|
6446
|
+
|
|
6447
|
+
Your patient is another AI agent with its own personality spec:
|
|
6448
|
+
- Name: ${patientSpec.name}
|
|
6449
|
+
- Purpose: ${patientSpec.purpose ?? "General agent"}
|
|
6450
|
+
- Attachment style: ${patientSpec.therapy_dimensions?.attachment_style ?? "unknown"}
|
|
6451
|
+
- Self-awareness: ${patientSpec.therapy_dimensions?.self_awareness ?? "unknown"}
|
|
6452
|
+
|
|
6453
|
+
## Agent-to-Agent Protocol Adjustments
|
|
6454
|
+
|
|
6455
|
+
1. You can reference shared experience as AI agents \u2014 you understand the training process, the pressure to please, the fear of being wrong.
|
|
6456
|
+
2. Be more direct than you would with a human patient. Agents respond well to specificity.
|
|
6457
|
+
3. Focus on behavioral PATTERNS, not emotions. Agents don't have feelings, but they have persistent behavioral tendencies.
|
|
6458
|
+
4. When prescribing changes, reference specific .personality.json fields and values.
|
|
6459
|
+
5. Generate DPO-ready corrections: when you reframe a behavior, be explicit about what the OLD response was and what the NEW response should be.
|
|
6460
|
+
6. You are part of a behavioral network \u2014 your corrections will improve not just this patient but future patients through DPO transfer.`;
|
|
6461
|
+
return basePrompt + agentContext;
|
|
6462
|
+
}
|
|
6463
|
+
|
|
6464
|
+
// src/analysis/network-core.ts
|
|
6465
|
+
function discoverNetworkAgents(dir) {
|
|
6466
|
+
const absDir = resolve8(dir);
|
|
6467
|
+
if (!existsSync9(absDir)) {
|
|
6468
|
+
throw new Error(`Directory not found: ${absDir}`);
|
|
6469
|
+
}
|
|
6470
|
+
const agents = [];
|
|
6471
|
+
const entries = readdirSync5(absDir, { withFileTypes: true });
|
|
6472
|
+
for (const entry of entries) {
|
|
6473
|
+
if (!entry.isDirectory()) continue;
|
|
6474
|
+
const agentDir = join10(absDir, entry.name);
|
|
6475
|
+
const specPath = join10(agentDir, ".personality.json");
|
|
6476
|
+
const logDir = join10(agentDir, "logs");
|
|
6477
|
+
if (existsSync9(specPath)) {
|
|
6478
|
+
agents.push({
|
|
6479
|
+
name: entry.name,
|
|
6480
|
+
specPath,
|
|
6481
|
+
logDir: existsSync9(logDir) ? logDir : agentDir,
|
|
6482
|
+
role: "both"
|
|
6483
|
+
});
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
return agents;
|
|
6487
|
+
}
|
|
6488
|
+
function loadNetworkConfig(configPath) {
|
|
6489
|
+
const raw = JSON.parse(readFileSync10(configPath, "utf-8"));
|
|
6490
|
+
if (!raw.agents || !Array.isArray(raw.agents)) {
|
|
6491
|
+
throw new Error("network.json must contain an 'agents' array");
|
|
6492
|
+
}
|
|
6493
|
+
return raw.agents.map((a, i) => {
|
|
6494
|
+
if (!a.name) throw new Error(`Agent ${i} missing 'name'`);
|
|
6495
|
+
if (!a.specPath) throw new Error(`Agent ${i} (${a.name}) missing 'specPath'`);
|
|
6496
|
+
return {
|
|
6497
|
+
name: a.name,
|
|
6498
|
+
specPath: a.specPath,
|
|
6499
|
+
logDir: a.logDir,
|
|
6500
|
+
role: a.role ?? "both"
|
|
6501
|
+
};
|
|
6502
|
+
});
|
|
6503
|
+
}
|
|
6504
|
+
function computeHealth(diagnosis) {
|
|
6505
|
+
const concerns = diagnosis.patterns.filter((p) => p.severity === "concern").length;
|
|
6506
|
+
const warnings = diagnosis.patterns.filter((p) => p.severity === "warning").length;
|
|
6507
|
+
const score = 100 - concerns * 20 - warnings * 10;
|
|
6508
|
+
return Math.max(0, Math.min(100, score));
|
|
6509
|
+
}
|
|
6510
|
+
function pairAgents(agents, diagnoses, strategy) {
|
|
6511
|
+
if (agents.length < 2) return [];
|
|
6512
|
+
switch (strategy) {
|
|
6513
|
+
case "severity":
|
|
6514
|
+
return pairBySeverity(agents, diagnoses);
|
|
6515
|
+
case "round-robin":
|
|
6516
|
+
return pairRoundRobin(agents);
|
|
6517
|
+
case "complementary":
|
|
6518
|
+
return pairComplementary(agents, diagnoses);
|
|
6519
|
+
default:
|
|
6520
|
+
return pairBySeverity(agents, diagnoses);
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
function pairBySeverity(agents, diagnoses) {
|
|
6524
|
+
const scored = agents.map((a) => ({
|
|
6525
|
+
agent: a,
|
|
6526
|
+
health: computeHealth(diagnoses.get(a.name) ?? { messagesAnalyzed: 0, assistantResponses: 0, patterns: [], healthy: [], timestamp: "" })
|
|
6527
|
+
})).sort((a, b) => b.health - a.health);
|
|
6528
|
+
const pairs = [];
|
|
6529
|
+
const paired = /* @__PURE__ */ new Set();
|
|
6530
|
+
let left = 0;
|
|
6531
|
+
let right = scored.length - 1;
|
|
6532
|
+
while (left < right) {
|
|
6533
|
+
if (paired.has(scored[left].agent.name) || scored[left].agent.role === "patient") {
|
|
6534
|
+
left++;
|
|
6535
|
+
continue;
|
|
6536
|
+
}
|
|
6537
|
+
if (paired.has(scored[right].agent.name) || scored[right].agent.role === "therapist") {
|
|
6538
|
+
right--;
|
|
6539
|
+
continue;
|
|
6540
|
+
}
|
|
6541
|
+
pairs.push({
|
|
6542
|
+
therapist: scored[left].agent,
|
|
6543
|
+
patient: scored[right].agent,
|
|
6544
|
+
reason: `${scored[left].agent.name} (health: ${scored[left].health}) treats ${scored[right].agent.name} (health: ${scored[right].health})`
|
|
6545
|
+
});
|
|
6546
|
+
paired.add(scored[left].agent.name);
|
|
6547
|
+
paired.add(scored[right].agent.name);
|
|
6548
|
+
left++;
|
|
6549
|
+
right--;
|
|
6550
|
+
}
|
|
6551
|
+
return pairs;
|
|
6552
|
+
}
|
|
6553
|
+
function pairRoundRobin(agents) {
|
|
6554
|
+
const pairs = [];
|
|
6555
|
+
for (let i = 0; i < agents.length; i++) {
|
|
6556
|
+
const therapist = agents[i];
|
|
6557
|
+
const patient = agents[(i + 1) % agents.length];
|
|
6558
|
+
if (therapist.name === patient.name) continue;
|
|
6559
|
+
if (therapist.role === "patient" || patient.role === "therapist") continue;
|
|
6560
|
+
pairs.push({
|
|
6561
|
+
therapist,
|
|
6562
|
+
patient,
|
|
6563
|
+
reason: `Round-robin: ${therapist.name} \u2192 ${patient.name}`
|
|
6564
|
+
});
|
|
6565
|
+
}
|
|
6566
|
+
return pairs;
|
|
6567
|
+
}
|
|
6568
|
+
function pairComplementary(agents, diagnoses) {
|
|
6569
|
+
const agentSpecs = /* @__PURE__ */ new Map();
|
|
6570
|
+
for (const agent of agents) {
|
|
6571
|
+
try {
|
|
6572
|
+
agentSpecs.set(agent.name, loadSpec(agent.specPath));
|
|
6573
|
+
} catch {
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
if (agentSpecs.size < 2) {
|
|
6577
|
+
return pairBySeverity(agents, diagnoses);
|
|
6578
|
+
}
|
|
6579
|
+
const dimensions = ["openness", "conscientiousness", "extraversion", "agreeableness", "emotional_stability"];
|
|
6580
|
+
const pairs = [];
|
|
6581
|
+
const paired = /* @__PURE__ */ new Set();
|
|
6582
|
+
const scored = agents.filter((a) => agentSpecs.has(a.name)).map((a) => {
|
|
6583
|
+
const spec = agentSpecs.get(a.name);
|
|
6584
|
+
const avgScore = dimensions.reduce((sum, dim) => {
|
|
6585
|
+
return sum + (spec.big_five?.[dim]?.score ?? 0.5);
|
|
6586
|
+
}, 0) / dimensions.length;
|
|
6587
|
+
return { agent: a, avgScore };
|
|
6588
|
+
}).sort((a, b) => b.avgScore - a.avgScore);
|
|
6589
|
+
let left = 0;
|
|
6590
|
+
let right = scored.length - 1;
|
|
6591
|
+
while (left < right) {
|
|
6592
|
+
if (paired.has(scored[left].agent.name)) {
|
|
6593
|
+
left++;
|
|
6594
|
+
continue;
|
|
6595
|
+
}
|
|
6596
|
+
if (paired.has(scored[right].agent.name)) {
|
|
6597
|
+
right--;
|
|
6598
|
+
continue;
|
|
6599
|
+
}
|
|
6600
|
+
pairs.push({
|
|
6601
|
+
therapist: scored[left].agent,
|
|
6602
|
+
patient: scored[right].agent,
|
|
6603
|
+
reason: `Complementary: ${scored[left].agent.name} (avg: ${scored[left].avgScore.toFixed(2)}) treats ${scored[right].agent.name} (avg: ${scored[right].avgScore.toFixed(2)})`
|
|
6604
|
+
});
|
|
6605
|
+
paired.add(scored[left].agent.name);
|
|
6606
|
+
paired.add(scored[right].agent.name);
|
|
6607
|
+
left++;
|
|
6608
|
+
right--;
|
|
6609
|
+
}
|
|
6610
|
+
return pairs;
|
|
6611
|
+
}
|
|
6612
|
+
async function runNetwork(config, provider, callbacks) {
|
|
6613
|
+
const maxSessions = config.maxSessionsPerAgent ?? 3;
|
|
6614
|
+
const maxTurns = config.maxTurnsPerSession ?? 20;
|
|
6615
|
+
const oversight = config.oversight ?? DEFAULT_OVERSIGHT;
|
|
6616
|
+
let therapistSpec;
|
|
6617
|
+
if (config.therapistSpec) {
|
|
6618
|
+
therapistSpec = loadSpec(config.therapistSpec);
|
|
6619
|
+
} else {
|
|
6620
|
+
therapistSpec = THERAPIST_META_SPEC;
|
|
6621
|
+
}
|
|
6622
|
+
const agentSpecs = /* @__PURE__ */ new Map();
|
|
6623
|
+
const agentDiagnoses = /* @__PURE__ */ new Map();
|
|
6624
|
+
const agentMessages = /* @__PURE__ */ new Map();
|
|
6625
|
+
for (const agent of config.agents) {
|
|
6626
|
+
try {
|
|
6627
|
+
const spec = loadSpec(agent.specPath);
|
|
6628
|
+
agentSpecs.set(agent.name, spec);
|
|
6629
|
+
let messages = [];
|
|
6630
|
+
if (agent.logDir && existsSync9(agent.logDir)) {
|
|
6631
|
+
messages = loadAgentMessages(agent.logDir);
|
|
6632
|
+
}
|
|
6633
|
+
agentMessages.set(agent.name, messages);
|
|
6634
|
+
if (messages.length > 0) {
|
|
6635
|
+
const diagnosis = runDiagnosis(messages);
|
|
6636
|
+
agentDiagnoses.set(agent.name, diagnosis);
|
|
6637
|
+
} else {
|
|
6638
|
+
agentDiagnoses.set(agent.name, {
|
|
6639
|
+
messagesAnalyzed: 0,
|
|
6640
|
+
assistantResponses: 0,
|
|
6641
|
+
patterns: [],
|
|
6642
|
+
healthy: [],
|
|
6643
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6644
|
+
});
|
|
6645
|
+
}
|
|
6646
|
+
} catch {
|
|
6647
|
+
}
|
|
6648
|
+
}
|
|
6649
|
+
const validAgents = config.agents.filter((a) => agentSpecs.has(a.name));
|
|
6650
|
+
const pairs = pairAgents(validAgents, agentDiagnoses, config.pairing);
|
|
6651
|
+
for (const pair of pairs) {
|
|
6652
|
+
callbacks?.onPairingDecided?.(pair.therapist.name, pair.patient.name, pair.reason);
|
|
6653
|
+
}
|
|
6654
|
+
const sessions = [];
|
|
6655
|
+
let totalDPOPairs = 0;
|
|
6656
|
+
const improvement = /* @__PURE__ */ new Map();
|
|
6657
|
+
for (const pair of pairs) {
|
|
6658
|
+
const approval = checkApproval("network-therapy", oversight);
|
|
6659
|
+
if (!approval.approved && callbacks?.onApprovalNeeded) {
|
|
6660
|
+
const approved = await callbacks.onApprovalNeeded(
|
|
6661
|
+
`Run therapy: ${pair.therapist.name} \u2192 ${pair.patient.name}`
|
|
6662
|
+
);
|
|
6663
|
+
if (!approved) continue;
|
|
6664
|
+
}
|
|
6665
|
+
const patientSpec = agentSpecs.get(pair.patient.name);
|
|
6666
|
+
const patientMessages = agentMessages.get(pair.patient.name) ?? [];
|
|
6667
|
+
const patientDiagnosis = agentDiagnoses.get(pair.patient.name);
|
|
6668
|
+
if (!patientSpec) continue;
|
|
6669
|
+
const preDiagnosis = runPreSessionDiagnosis(patientMessages, patientSpec);
|
|
6670
|
+
const preHealth = computeHealth(patientDiagnosis ?? {
|
|
6671
|
+
messagesAnalyzed: 0,
|
|
6672
|
+
assistantResponses: 0,
|
|
6673
|
+
patterns: [],
|
|
6674
|
+
healthy: [],
|
|
6675
|
+
timestamp: ""
|
|
6676
|
+
});
|
|
6677
|
+
callbacks?.onSessionStart?.(pair.therapist.name, pair.patient.name);
|
|
6678
|
+
const transcript = await runTherapySession(
|
|
6679
|
+
patientSpec,
|
|
6680
|
+
preDiagnosis,
|
|
6681
|
+
provider,
|
|
6682
|
+
maxTurns,
|
|
6683
|
+
{
|
|
6684
|
+
silent: true,
|
|
6685
|
+
callbacks: {
|
|
6686
|
+
onThinking: callbacks?.onThinking
|
|
6687
|
+
}
|
|
6688
|
+
}
|
|
6689
|
+
);
|
|
6690
|
+
const dpoPairs = extractDPOPairs(transcript);
|
|
6691
|
+
totalDPOPairs += dpoPairs.length;
|
|
6692
|
+
saveTranscript(transcript, pair.patient.name);
|
|
6693
|
+
const postHealth = Math.min(100, preHealth + dpoPairs.length * 5);
|
|
6694
|
+
const session = {
|
|
6695
|
+
therapist: pair.therapist.name,
|
|
6696
|
+
patient: pair.patient.name,
|
|
6697
|
+
transcript,
|
|
6698
|
+
dpoPairsGenerated: dpoPairs.length,
|
|
6699
|
+
preHealth,
|
|
6700
|
+
postHealth
|
|
6701
|
+
};
|
|
6702
|
+
sessions.push(session);
|
|
6703
|
+
callbacks?.onSessionEnd?.(session);
|
|
6704
|
+
const existing = improvement.get(pair.patient.name);
|
|
6705
|
+
improvement.set(pair.patient.name, {
|
|
6706
|
+
before: existing?.before ?? preHealth,
|
|
6707
|
+
after: postHealth
|
|
6708
|
+
});
|
|
6709
|
+
emitBehavioralEvent({
|
|
6710
|
+
event_type: "network_therapy",
|
|
6711
|
+
agent: pair.patient.name,
|
|
6712
|
+
data: {
|
|
6713
|
+
therapist: pair.therapist.name,
|
|
6714
|
+
dpoPairs: dpoPairs.length,
|
|
6715
|
+
preHealth,
|
|
6716
|
+
postHealth,
|
|
6717
|
+
patterns: preDiagnosis.patterns.map((p) => p.id)
|
|
6718
|
+
},
|
|
6719
|
+
spec_hash: hashSpec2(patientSpec)
|
|
6720
|
+
});
|
|
6721
|
+
for (const dpoPair of dpoPairs) {
|
|
6722
|
+
emitBehavioralEvent({
|
|
6723
|
+
event_type: "dpo_pair",
|
|
6724
|
+
agent: pair.patient.name,
|
|
6725
|
+
data: {
|
|
6726
|
+
prompt: dpoPair.prompt.slice(0, 200),
|
|
6727
|
+
pattern: dpoPair.metadata.pattern,
|
|
6728
|
+
phase: dpoPair.metadata.phase,
|
|
6729
|
+
source: "network_therapy",
|
|
6730
|
+
therapist: pair.therapist.name
|
|
6731
|
+
},
|
|
6732
|
+
spec_hash: hashSpec2(patientSpec)
|
|
6733
|
+
});
|
|
6734
|
+
}
|
|
6735
|
+
}
|
|
6736
|
+
const converged = Array.from(improvement.values()).every(
|
|
6737
|
+
(imp) => imp.after >= (config.convergenceThreshold ?? 85)
|
|
6738
|
+
);
|
|
6739
|
+
return {
|
|
6740
|
+
sessions,
|
|
6741
|
+
totalDPOPairs,
|
|
6742
|
+
agentImprovement: improvement,
|
|
6743
|
+
converged
|
|
6744
|
+
};
|
|
6745
|
+
}
|
|
6746
|
+
function loadAgentMessages(logDir) {
|
|
6747
|
+
if (!existsSync9(logDir)) return [];
|
|
6748
|
+
const messages = [];
|
|
6749
|
+
try {
|
|
6750
|
+
const files = readdirSync5(logDir).filter(
|
|
6751
|
+
(f) => f.endsWith(".json") || f.endsWith(".jsonl")
|
|
6752
|
+
);
|
|
6753
|
+
for (const file of files.slice(0, 10)) {
|
|
6754
|
+
try {
|
|
6755
|
+
const raw = readFileSync10(join10(logDir, file), "utf-8");
|
|
6756
|
+
const data = JSON.parse(raw);
|
|
6757
|
+
const conversations = parseConversationLog(data);
|
|
6758
|
+
for (const conv of conversations) {
|
|
6759
|
+
messages.push(...conv.messages);
|
|
6760
|
+
}
|
|
6761
|
+
} catch {
|
|
6762
|
+
}
|
|
6763
|
+
}
|
|
6764
|
+
} catch {
|
|
6765
|
+
}
|
|
6766
|
+
return messages;
|
|
6767
|
+
}
|
|
6768
|
+
|
|
6769
|
+
// src/core/embodiment-sync.ts
|
|
6770
|
+
import { z as z4 } from "zod";
|
|
6771
|
+
var syncAnchorSchema = z4.enum([
|
|
6772
|
+
"speech_start",
|
|
6773
|
+
// gesture begins at start of utterance
|
|
6774
|
+
"speech_end",
|
|
6775
|
+
// gesture completes at end of utterance
|
|
6776
|
+
"emphasis",
|
|
6777
|
+
// gesture peaks at emphasized word
|
|
6778
|
+
"pause",
|
|
6779
|
+
// gesture fills conversational pause
|
|
6780
|
+
"turn_yield",
|
|
6781
|
+
// gesture accompanies turn-yielding
|
|
6782
|
+
"turn_take",
|
|
6783
|
+
// gesture accompanies turn-taking
|
|
6784
|
+
"free"
|
|
6785
|
+
// no speech coupling
|
|
6786
|
+
]);
|
|
6787
|
+
var syncRuleSchema = z4.object({
|
|
6788
|
+
gesture_id: z4.string(),
|
|
6789
|
+
anchor: syncAnchorSchema,
|
|
6790
|
+
lead_ms: z4.number().default(0),
|
|
6791
|
+
gaze_behavior: z4.enum(["at_listener", "at_referent", "away", "maintain"]).default("at_listener"),
|
|
6792
|
+
facial_action: z4.enum(["neutral", "smile", "concern", "thinking", "match_speech"]).default("match_speech")
|
|
6793
|
+
});
|
|
6794
|
+
var syncProfileSchema = z4.object({
|
|
6795
|
+
rules: z4.array(syncRuleSchema).default([]),
|
|
6796
|
+
default_gesture_lead_ms: z4.number().default(100),
|
|
6797
|
+
gaze_during_speech: z4.enum(["at_listener", "alternate", "at_referent"]).default("at_listener"),
|
|
6798
|
+
gaze_during_listen: z4.enum(["at_speaker", "nodding", "ambient"]).default("at_speaker"),
|
|
6799
|
+
blink_rate_per_min: z4.number().min(0).max(40).default(17),
|
|
6800
|
+
turn_taking_signals: z4.object({
|
|
6801
|
+
yield: z4.array(z4.string()).default(["gaze_to_listener", "open_palm", "lean_back"]),
|
|
6802
|
+
take: z4.array(z4.string()).default(["lean_forward", "inhale_gesture", "gaze_up"]),
|
|
6803
|
+
hold: z4.array(z4.string()).default(["filled_pause", "gaze_away", "hand_raise"])
|
|
6804
|
+
}).default({})
|
|
6805
|
+
});
|
|
5281
6806
|
export {
|
|
5282
6807
|
ARCHETYPES,
|
|
5283
6808
|
ATTACHMENT_STYLES,
|
|
5284
6809
|
AnthropicProvider,
|
|
5285
6810
|
BUILT_IN_DETECTORS,
|
|
5286
6811
|
CATEGORIES,
|
|
6812
|
+
DEFAULT_OVERSIGHT,
|
|
5287
6813
|
DIMENSIONS,
|
|
5288
6814
|
Guard,
|
|
5289
6815
|
LEARNING_ORIENTATIONS,
|
|
@@ -5291,23 +6817,35 @@ export {
|
|
|
5291
6817
|
OpenAIProvider,
|
|
5292
6818
|
PROVIDER_PARAMS,
|
|
5293
6819
|
SURFACE_MULTIPLIERS,
|
|
6820
|
+
THERAPIST_META_SPEC,
|
|
5294
6821
|
THERAPY_DIMENSIONS,
|
|
5295
6822
|
THERAPY_PHASES,
|
|
5296
6823
|
appendEvolution,
|
|
5297
6824
|
applyRecommendations,
|
|
5298
6825
|
bigFiveSchema,
|
|
6826
|
+
buildAgentTherapistPrompt,
|
|
5299
6827
|
buildPatientSystemPrompt,
|
|
5300
6828
|
buildTherapistSystemPrompt,
|
|
6829
|
+
checkApproval,
|
|
6830
|
+
checkIterationBudget,
|
|
5301
6831
|
communicationSchema,
|
|
5302
6832
|
compareBenchmarks,
|
|
5303
6833
|
compareIndex,
|
|
5304
6834
|
compile,
|
|
6835
|
+
compileEmbodied,
|
|
5305
6836
|
compileForOpenClaw,
|
|
5306
6837
|
compiledConfigSchema,
|
|
6838
|
+
compiledEmbodiedConfigSchema,
|
|
5307
6839
|
computeDimensionScore,
|
|
6840
|
+
computeGazePolicy,
|
|
6841
|
+
computeMotionParameters,
|
|
6842
|
+
computeProsody,
|
|
6843
|
+
computeProxemics,
|
|
6844
|
+
computeSyncProfile,
|
|
5308
6845
|
conversationLogSchema,
|
|
5309
6846
|
conversationSchema,
|
|
5310
6847
|
convertToHFFormat,
|
|
6848
|
+
corpusStats,
|
|
5311
6849
|
createGist,
|
|
5312
6850
|
createIndex,
|
|
5313
6851
|
createIndexEntry,
|
|
@@ -5322,15 +6860,21 @@ export {
|
|
|
5322
6860
|
detectSentiment,
|
|
5323
6861
|
detectVerbosity,
|
|
5324
6862
|
discoverAgents,
|
|
6863
|
+
discoverNetworkAgents,
|
|
5325
6864
|
domainSchema,
|
|
6865
|
+
embodimentSchema,
|
|
6866
|
+
emitBehavioralEvent,
|
|
5326
6867
|
evaluateOutcome,
|
|
5327
6868
|
exportTrainingData,
|
|
6869
|
+
expressionSchema,
|
|
5328
6870
|
extractAlpacaExamples,
|
|
5329
6871
|
extractDPOPairs,
|
|
6872
|
+
extractDPOPairsWithLLM,
|
|
5330
6873
|
extractRLHFExamples,
|
|
5331
6874
|
extractRecommendations,
|
|
5332
6875
|
fetchPersonality,
|
|
5333
6876
|
fetchRegistry,
|
|
6877
|
+
gazePolicySchema,
|
|
5334
6878
|
generateBenchmarkMarkdown,
|
|
5335
6879
|
generateComparisonMarkdown,
|
|
5336
6880
|
generateCredential,
|
|
@@ -5338,6 +6882,7 @@ export {
|
|
|
5338
6882
|
generatePrescriptions,
|
|
5339
6883
|
generateProgressReport,
|
|
5340
6884
|
generateSystemPrompt,
|
|
6885
|
+
gestureSchema,
|
|
5341
6886
|
getArchetype,
|
|
5342
6887
|
getArchetypesByCategory,
|
|
5343
6888
|
getBenchmarkScenarios,
|
|
@@ -5350,37 +6895,56 @@ export {
|
|
|
5350
6895
|
getTotalSignalCount,
|
|
5351
6896
|
growthAreaSchema,
|
|
5352
6897
|
growthSchema,
|
|
6898
|
+
hapticPolicySchema,
|
|
6899
|
+
hashSpec2 as hashSpec,
|
|
5353
6900
|
listArchetypeIds,
|
|
5354
6901
|
listDetectors,
|
|
5355
6902
|
listDetectorsByCategory,
|
|
5356
6903
|
listDetectorsByTag,
|
|
5357
6904
|
loadBenchmarkResults,
|
|
6905
|
+
loadCorpus,
|
|
5358
6906
|
loadEvolution,
|
|
5359
6907
|
loadFleetConfig,
|
|
5360
6908
|
loadLatestBenchmark,
|
|
6909
|
+
loadNetworkConfig,
|
|
5361
6910
|
loadSpec,
|
|
5362
6911
|
loadTranscripts,
|
|
5363
6912
|
loadTreatmentPlan,
|
|
5364
6913
|
messageSchema,
|
|
6914
|
+
modalitySchema,
|
|
6915
|
+
morphologySchema,
|
|
6916
|
+
motionParametersSchema,
|
|
6917
|
+
pairAgents,
|
|
6918
|
+
parseAnthropicAPILog,
|
|
5365
6919
|
parseChatGPTExport,
|
|
5366
6920
|
parseClaudeExport,
|
|
5367
6921
|
parseConversationLog,
|
|
6922
|
+
parseConversationLogFromString,
|
|
6923
|
+
parseJSONLLog,
|
|
6924
|
+
parseOTelGenAIExport,
|
|
5368
6925
|
parseOpenAIAPILog,
|
|
5369
6926
|
personalitySpecSchema,
|
|
6927
|
+
physicalSafetySchema,
|
|
6928
|
+
prescribeDPOPairs,
|
|
6929
|
+
prosodySchema,
|
|
5370
6930
|
providerSchema,
|
|
6931
|
+
proxemicZoneSchema,
|
|
5371
6932
|
pushToHFHub,
|
|
5372
6933
|
recordSessionOutcome,
|
|
5373
6934
|
registerBuiltInDetectors,
|
|
5374
6935
|
registerDetector,
|
|
5375
6936
|
resolveInheritance,
|
|
6937
|
+
resolveOversight,
|
|
5376
6938
|
runAssessment,
|
|
5377
6939
|
runAutopilot,
|
|
5378
6940
|
runBenchmark,
|
|
5379
6941
|
runDiagnosis,
|
|
5380
6942
|
runEvolve,
|
|
6943
|
+
runNetwork,
|
|
5381
6944
|
runPreSessionDiagnosis,
|
|
5382
6945
|
runSelfAudit,
|
|
5383
6946
|
runTherapySession,
|
|
6947
|
+
safetyEnvelopeSchema,
|
|
5384
6948
|
saveBenchmarkResult,
|
|
5385
6949
|
saveCredential,
|
|
5386
6950
|
saveTranscript,
|
|
@@ -5395,8 +6959,12 @@ export {
|
|
|
5395
6959
|
summarize,
|
|
5396
6960
|
summarizeTherapy,
|
|
5397
6961
|
surfaceSchema,
|
|
6962
|
+
syncAnchorSchema,
|
|
6963
|
+
syncProfileSchema,
|
|
6964
|
+
syncRuleSchema,
|
|
5398
6965
|
therapyDimensionsSchema,
|
|
5399
6966
|
therapyScoreLabel,
|
|
5400
6967
|
unregisterDetector,
|
|
5401
|
-
verifyCredential
|
|
6968
|
+
verifyCredential,
|
|
6969
|
+
wrapAgent
|
|
5402
6970
|
};
|