@machinespirits/eval 0.1.2 → 0.2.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/LICENSE +21 -0
- package/README.md +161 -0
- package/config/eval-settings.yaml +18 -0
- package/config/evaluation-rubric-learner.yaml +277 -0
- package/config/evaluation-rubric.yaml +613 -0
- package/config/interaction-eval-scenarios.yaml +93 -50
- package/config/learner-agents.yaml +124 -193
- package/config/machinespirits-eval.code-workspace +11 -0
- package/config/providers.yaml +60 -0
- package/config/suggestion-scenarios.yaml +1399 -0
- package/config/tutor-agents.yaml +716 -0
- package/docs/EVALUATION-VARIABLES.md +589 -0
- package/docs/REPLICATION-PLAN.md +577 -0
- package/index.js +15 -6
- package/package.json +16 -22
- package/routes/evalRoutes.js +88 -36
- package/scripts/analyze-judge-reliability.js +401 -0
- package/scripts/analyze-run.js +97 -0
- package/scripts/analyze-run.mjs +282 -0
- package/scripts/analyze-validation-failures.js +141 -0
- package/scripts/check-run.mjs +17 -0
- package/scripts/code-impasse-strategies.js +1132 -0
- package/scripts/compare-runs.js +44 -0
- package/scripts/compare-suggestions.js +80 -0
- package/scripts/compare-transformation.js +116 -0
- package/scripts/dig-into-run.js +158 -0
- package/scripts/eval-cli.js +2626 -0
- package/scripts/generate-paper-figures.py +452 -0
- package/scripts/qualitative-analysis-ai.js +1313 -0
- package/scripts/qualitative-analysis.js +688 -0
- package/scripts/seed-db.js +87 -0
- package/scripts/show-failed-suggestions.js +64 -0
- package/scripts/validate-content.js +192 -0
- package/server.js +3 -2
- package/services/__tests__/evalConfigLoader.test.js +338 -0
- package/services/anovaStats.js +499 -0
- package/services/contentResolver.js +407 -0
- package/services/dialogueTraceAnalyzer.js +454 -0
- package/services/evalConfigLoader.js +625 -0
- package/services/evaluationRunner.js +2171 -270
- package/services/evaluationStore.js +564 -29
- package/services/learnerConfigLoader.js +75 -5
- package/services/learnerRubricEvaluator.js +284 -0
- package/services/learnerTutorInteractionEngine.js +375 -0
- package/services/processUtils.js +18 -0
- package/services/progressLogger.js +98 -0
- package/services/promptRecommendationService.js +31 -26
- package/services/promptRewriter.js +427 -0
- package/services/rubricEvaluator.js +543 -70
- package/services/streamingReporter.js +104 -0
- package/services/turnComparisonAnalyzer.js +494 -0
- package/components/MobileEvalDashboard.tsx +0 -267
- package/components/comparison/DeltaAnalysisTable.tsx +0 -137
- package/components/comparison/ProfileComparisonCard.tsx +0 -176
- package/components/comparison/RecognitionABMode.tsx +0 -385
- package/components/comparison/RecognitionMetricsPanel.tsx +0 -135
- package/components/comparison/WinnerIndicator.tsx +0 -64
- package/components/comparison/index.ts +0 -5
- package/components/mobile/BottomSheet.tsx +0 -233
- package/components/mobile/DimensionBreakdown.tsx +0 -210
- package/components/mobile/DocsView.tsx +0 -363
- package/components/mobile/LogsView.tsx +0 -481
- package/components/mobile/PsychodynamicQuadrant.tsx +0 -261
- package/components/mobile/QuickTestView.tsx +0 -1098
- package/components/mobile/RecognitionTypeChart.tsx +0 -124
- package/components/mobile/RecognitionView.tsx +0 -809
- package/components/mobile/RunDetailView.tsx +0 -261
- package/components/mobile/RunHistoryView.tsx +0 -367
- package/components/mobile/ScoreRadial.tsx +0 -211
- package/components/mobile/StreamingLogPanel.tsx +0 -230
- package/components/mobile/SynthesisStrategyChart.tsx +0 -140
- package/docs/research/ABLATION-DIALOGUE-ROUNDS.md +0 -52
- package/docs/research/ABLATION-MODEL-SELECTION.md +0 -53
- package/docs/research/ADVANCED-EVAL-ANALYSIS.md +0 -60
- package/docs/research/ANOVA-RESULTS-2026-01-14.md +0 -257
- package/docs/research/COMPREHENSIVE-EVALUATION-PLAN.md +0 -586
- package/docs/research/COST-ANALYSIS.md +0 -56
- package/docs/research/CRITICAL-REVIEW-RECOGNITION-TUTORING.md +0 -340
- package/docs/research/DYNAMIC-VS-SCRIPTED-ANALYSIS.md +0 -291
- package/docs/research/EVAL-SYSTEM-ANALYSIS.md +0 -306
- package/docs/research/FACTORIAL-RESULTS-2026-01-14.md +0 -301
- package/docs/research/IMPLEMENTATION-PLAN-CRITIQUE-RESPONSE.md +0 -1988
- package/docs/research/LONGITUDINAL-DYADIC-EVALUATION.md +0 -282
- package/docs/research/MULTI-JUDGE-VALIDATION-2026-01-14.md +0 -147
- package/docs/research/PAPER-EXTENSION-DYADIC.md +0 -204
- package/docs/research/PAPER-UNIFIED.md +0 -659
- package/docs/research/PAPER-UNIFIED.pdf +0 -0
- package/docs/research/PROMPT-IMPROVEMENTS-2026-01-14.md +0 -356
- package/docs/research/SESSION-NOTES-2026-01-11-RECOGNITION-EVAL.md +0 -419
- package/docs/research/apa.csl +0 -2133
- package/docs/research/archive/PAPER-DRAFT-RECOGNITION-TUTORING.md +0 -1637
- package/docs/research/archive/paper-multiagent-tutor.tex +0 -978
- package/docs/research/paper-draft/full-paper.md +0 -136
- package/docs/research/paper-draft/images/pasted-image-2026-01-24T03-47-47-846Z-d76a7ae2.png +0 -0
- package/docs/research/paper-draft/references.bib +0 -515
- package/docs/research/transcript-baseline.md +0 -139
- package/docs/research/transcript-recognition-multiagent.md +0 -187
- package/hooks/useEvalData.ts +0 -625
- package/server-init.js +0 -45
- package/services/benchmarkService.js +0 -1892
- package/types.ts +0 -165
- package/utils/haptics.ts +0 -45
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialogue Trace Analyzer Service
|
|
3
|
+
*
|
|
4
|
+
* Analyzes the internal dialogue traces from ego-superego interactions.
|
|
5
|
+
* Tracks how superego feedback influences ego revisions and identifies
|
|
6
|
+
* signals of bilateral transformation in the dialogue.
|
|
7
|
+
*
|
|
8
|
+
* Theoretical basis: The superego acts as the "external perspective" that
|
|
9
|
+
* enables genuine recognition. By tracking how feedback is incorporated,
|
|
10
|
+
* we can measure whether the dialogue achieves mutual transformation or
|
|
11
|
+
* remains one-directional instruction.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Analyze superego feedback incorporation patterns.
|
|
16
|
+
*
|
|
17
|
+
* @param {Array} dialogueTrace - Array of trace entries from tutor-core dialogue
|
|
18
|
+
* @returns {Object} Incorporation analysis metrics
|
|
19
|
+
*/
|
|
20
|
+
export function analyzeSuperegoIncorporation(dialogueTrace) {
|
|
21
|
+
if (!dialogueTrace || !Array.isArray(dialogueTrace)) {
|
|
22
|
+
return {
|
|
23
|
+
incorporationRate: null,
|
|
24
|
+
feedbackPatterns: { enhance: 0, revise: 0, approve: 0, reject: 0 },
|
|
25
|
+
confidenceProgression: [],
|
|
26
|
+
totalFeedbackEvents: 0,
|
|
27
|
+
totalRevisions: 0,
|
|
28
|
+
avgConfidence: null,
|
|
29
|
+
transformationSignals: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const superegoFeedback = dialogueTrace.filter(e => e.agent === 'superego');
|
|
34
|
+
const egoRevisions = dialogueTrace.filter(e =>
|
|
35
|
+
e.agent === 'ego' && (e.action === 'revision' || e.action === 'revise')
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Count feedback patterns
|
|
39
|
+
const feedbackPatterns = { enhance: 0, revise: 0, approve: 0, reject: 0 };
|
|
40
|
+
const confidenceProgression = [];
|
|
41
|
+
|
|
42
|
+
for (const feedback of superegoFeedback) {
|
|
43
|
+
// Track intervention type
|
|
44
|
+
const interventionType = feedback.interventionType ||
|
|
45
|
+
feedback.verdict?.interventionType ||
|
|
46
|
+
feedback.action;
|
|
47
|
+
|
|
48
|
+
if (interventionType === 'enhance') feedbackPatterns.enhance++;
|
|
49
|
+
else if (interventionType === 'revise') feedbackPatterns.revise++;
|
|
50
|
+
else if (feedback.verdict?.approved === true) feedbackPatterns.approve++;
|
|
51
|
+
else if (feedback.verdict?.approved === false) feedbackPatterns.reject++;
|
|
52
|
+
|
|
53
|
+
// Track confidence
|
|
54
|
+
const confidence = feedback.confidence ||
|
|
55
|
+
feedback.verdict?.confidence ||
|
|
56
|
+
feedback.score;
|
|
57
|
+
if (typeof confidence === 'number') {
|
|
58
|
+
confidenceProgression.push({
|
|
59
|
+
turnIndex: feedback.turnIndex,
|
|
60
|
+
confidence,
|
|
61
|
+
timestamp: feedback.timestamp,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Calculate incorporation rate
|
|
67
|
+
// How often does an ego revision follow superego feedback?
|
|
68
|
+
const incorporationRate = superegoFeedback.length > 0
|
|
69
|
+
? egoRevisions.length / superegoFeedback.length
|
|
70
|
+
: null;
|
|
71
|
+
|
|
72
|
+
// Average confidence
|
|
73
|
+
const avgConfidence = confidenceProgression.length > 0
|
|
74
|
+
? confidenceProgression.reduce((sum, c) => sum + c.confidence, 0) / confidenceProgression.length
|
|
75
|
+
: null;
|
|
76
|
+
|
|
77
|
+
// Extract transformation signals
|
|
78
|
+
const transformationSignals = extractTransformationSignals(dialogueTrace);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
incorporationRate,
|
|
82
|
+
feedbackPatterns,
|
|
83
|
+
confidenceProgression,
|
|
84
|
+
totalFeedbackEvents: superegoFeedback.length,
|
|
85
|
+
totalRevisions: egoRevisions.length,
|
|
86
|
+
avgConfidence,
|
|
87
|
+
transformationSignals,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Extract transformation signals from dialogue trace.
|
|
93
|
+
* Identifies moments where tutor or learner explicitly transform their position.
|
|
94
|
+
*
|
|
95
|
+
* @param {Array} dialogueTrace - Array of trace entries
|
|
96
|
+
* @returns {Array} Array of transformation signal objects
|
|
97
|
+
*/
|
|
98
|
+
export function extractTransformationSignals(dialogueTrace) {
|
|
99
|
+
if (!dialogueTrace || !Array.isArray(dialogueTrace)) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const signals = [];
|
|
104
|
+
|
|
105
|
+
// Transformation language patterns
|
|
106
|
+
const tutorTransformationPatterns = [
|
|
107
|
+
/you'?ve? (helped|pushed|made) me (see|think|understand|reconsider)/i,
|
|
108
|
+
/that changes (how I|my)/i,
|
|
109
|
+
/(reconsidering|revising) (my|the) (approach|framing|understanding)/i,
|
|
110
|
+
/building on (your|that)/i,
|
|
111
|
+
/your (insight|point|question) (complicates|enriches|changes)/i,
|
|
112
|
+
/I hadn'?t (thought|considered)/i,
|
|
113
|
+
/let me (revise|adjust|rethink)/i,
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
const learnerTransformationPatterns = [
|
|
117
|
+
/oh (wait|I see|that makes sense)/i,
|
|
118
|
+
/my (understanding|thinking|frame) (is|has) (changed|shifted|evolved)/i,
|
|
119
|
+
/(I was wrong|I see now|this is clicking)/i,
|
|
120
|
+
/that changes (how I|my)/i,
|
|
121
|
+
/so it'?s (not just|more like|actually)/i,
|
|
122
|
+
/the whole way I (think|thought|was thinking)/i,
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
const superegoAcknowledgmentPatterns = [
|
|
126
|
+
/genuinely responsive/i,
|
|
127
|
+
/mutual (recognition|transformation)/i,
|
|
128
|
+
/adapted (to|based on)/i,
|
|
129
|
+
/evolved (through|during)/i,
|
|
130
|
+
/bilateral/i,
|
|
131
|
+
/both parties/i,
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
for (const entry of dialogueTrace) {
|
|
135
|
+
// Check ego entries for tutor transformation
|
|
136
|
+
if (entry.agent === 'ego') {
|
|
137
|
+
const text = entry.reasoning || entry.detail || entry.contextSummary || '';
|
|
138
|
+
|
|
139
|
+
for (const pattern of tutorTransformationPatterns) {
|
|
140
|
+
if (pattern.test(text)) {
|
|
141
|
+
signals.push({
|
|
142
|
+
turn: entry.turnIndex,
|
|
143
|
+
type: 'tutor_transformation',
|
|
144
|
+
source: 'ego_reasoning',
|
|
145
|
+
pattern: pattern.source,
|
|
146
|
+
content: text.substring(0, 150),
|
|
147
|
+
timestamp: entry.timestamp,
|
|
148
|
+
});
|
|
149
|
+
break; // One signal per entry
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check superego feedback for acknowledgment of adaptation
|
|
155
|
+
if (entry.agent === 'superego') {
|
|
156
|
+
const text = entry.verdict?.feedback ||
|
|
157
|
+
entry.verdict?.reasoning ||
|
|
158
|
+
entry.detail ||
|
|
159
|
+
entry.contextSummary ||
|
|
160
|
+
'';
|
|
161
|
+
|
|
162
|
+
for (const pattern of superegoAcknowledgmentPatterns) {
|
|
163
|
+
if (pattern.test(text)) {
|
|
164
|
+
signals.push({
|
|
165
|
+
turn: entry.turnIndex,
|
|
166
|
+
type: 'superego_noted_adaptation',
|
|
167
|
+
source: 'superego_feedback',
|
|
168
|
+
pattern: pattern.source,
|
|
169
|
+
content: text.substring(0, 150),
|
|
170
|
+
timestamp: entry.timestamp,
|
|
171
|
+
});
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Check learner entries for growth signals
|
|
178
|
+
if (entry.agent === 'user' || entry.agent?.startsWith('learner')) {
|
|
179
|
+
const text = entry.detail || entry.contextSummary || '';
|
|
180
|
+
|
|
181
|
+
for (const pattern of learnerTransformationPatterns) {
|
|
182
|
+
if (pattern.test(text)) {
|
|
183
|
+
signals.push({
|
|
184
|
+
turn: entry.turnIndex,
|
|
185
|
+
type: 'learner_transformation',
|
|
186
|
+
source: entry.agent,
|
|
187
|
+
pattern: pattern.source,
|
|
188
|
+
content: text.substring(0, 150),
|
|
189
|
+
timestamp: entry.timestamp,
|
|
190
|
+
});
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return signals;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Analyze the bilateral transformation balance in a dialogue.
|
|
202
|
+
* Measures whether transformation is mutual or one-directional.
|
|
203
|
+
*
|
|
204
|
+
* @param {Array} dialogueTrace - Array of trace entries
|
|
205
|
+
* @returns {Object} Bilateral analysis
|
|
206
|
+
*/
|
|
207
|
+
export function analyzeBilateralTransformation(dialogueTrace) {
|
|
208
|
+
const signals = extractTransformationSignals(dialogueTrace);
|
|
209
|
+
|
|
210
|
+
const tutorSignals = signals.filter(s => s.type === 'tutor_transformation');
|
|
211
|
+
const learnerSignals = signals.filter(s => s.type === 'learner_transformation');
|
|
212
|
+
const acknowledgmentSignals = signals.filter(s => s.type === 'superego_noted_adaptation');
|
|
213
|
+
|
|
214
|
+
const tutorCount = tutorSignals.length;
|
|
215
|
+
const learnerCount = learnerSignals.length;
|
|
216
|
+
const total = tutorCount + learnerCount;
|
|
217
|
+
|
|
218
|
+
// Calculate balance (1.0 = perfectly balanced)
|
|
219
|
+
let balance = null;
|
|
220
|
+
if (total > 0) {
|
|
221
|
+
const maxCount = Math.max(tutorCount, learnerCount);
|
|
222
|
+
const minCount = Math.min(tutorCount, learnerCount);
|
|
223
|
+
balance = maxCount > 0 ? minCount / maxCount : 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Determine if transformation is genuine mutual recognition
|
|
227
|
+
const isMutual = tutorCount > 0 && learnerCount > 0;
|
|
228
|
+
const isAcknowledged = acknowledgmentSignals.length > 0;
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
tutorTransformationCount: tutorCount,
|
|
232
|
+
learnerTransformationCount: learnerCount,
|
|
233
|
+
superegoAcknowledgmentCount: acknowledgmentSignals.length,
|
|
234
|
+
bilateralBalance: balance,
|
|
235
|
+
isMutualTransformation: isMutual,
|
|
236
|
+
isAcknowledgedBySystem: isAcknowledged,
|
|
237
|
+
transformationTimeline: signals.sort((a, b) => (a.turn || 0) - (b.turn || 0)),
|
|
238
|
+
summary: generateTransformationSummary(tutorCount, learnerCount, balance, isMutual),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Generate a human-readable summary of transformation analysis.
|
|
244
|
+
*
|
|
245
|
+
* @param {number} tutorCount - Tutor transformation signals
|
|
246
|
+
* @param {number} learnerCount - Learner transformation signals
|
|
247
|
+
* @param {number|null} balance - Bilateral balance score
|
|
248
|
+
* @param {boolean} isMutual - Whether transformation is mutual
|
|
249
|
+
* @returns {string} Summary text
|
|
250
|
+
*/
|
|
251
|
+
function generateTransformationSummary(tutorCount, learnerCount, balance, isMutual) {
|
|
252
|
+
if (tutorCount === 0 && learnerCount === 0) {
|
|
253
|
+
return 'No explicit transformation signals detected in dialogue.';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!isMutual) {
|
|
257
|
+
if (tutorCount > 0) {
|
|
258
|
+
return `One-directional: Tutor shows ${tutorCount} adaptation signal(s), but learner shows no growth.`;
|
|
259
|
+
} else {
|
|
260
|
+
return `One-directional: Learner shows ${learnerCount} growth signal(s), but tutor shows no adaptation.`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (balance !== null && balance >= 0.7) {
|
|
265
|
+
return `Mutual transformation achieved: ${tutorCount} tutor adaptation(s), ${learnerCount} learner growth(s), balance=${(balance * 100).toFixed(0)}%.`;
|
|
266
|
+
} else if (balance !== null && balance >= 0.3) {
|
|
267
|
+
return `Partial mutual transformation: ${tutorCount} tutor, ${learnerCount} learner signals, balance=${(balance * 100).toFixed(0)}% (asymmetric).`;
|
|
268
|
+
} else {
|
|
269
|
+
return `Imbalanced transformation: ${tutorCount} tutor, ${learnerCount} learner signals, balance=${(balance * 100).toFixed(0)}% (highly asymmetric).`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Analyze superego intervention effectiveness.
|
|
275
|
+
* Tracks whether superego interventions lead to improved outcomes.
|
|
276
|
+
*
|
|
277
|
+
* @param {Array} dialogueTrace - Array of trace entries
|
|
278
|
+
* @param {Array} turnResults - Array of turn result objects (for score comparison)
|
|
279
|
+
* @returns {Object} Intervention effectiveness analysis
|
|
280
|
+
*/
|
|
281
|
+
export function analyzeInterventionEffectiveness(dialogueTrace, turnResults) {
|
|
282
|
+
if (!dialogueTrace || !turnResults) {
|
|
283
|
+
return {
|
|
284
|
+
interventionCount: 0,
|
|
285
|
+
scoreImprovementAfterIntervention: null,
|
|
286
|
+
mostEffectiveInterventionType: null,
|
|
287
|
+
interventionsByType: {},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const interventions = dialogueTrace.filter(e =>
|
|
292
|
+
e.agent === 'superego' && e.action === 'revise'
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const interventionsByType = {};
|
|
296
|
+
let totalImprovement = 0;
|
|
297
|
+
let measuredInterventions = 0;
|
|
298
|
+
|
|
299
|
+
for (const intervention of interventions) {
|
|
300
|
+
const turnIndex = intervention.turnIndex;
|
|
301
|
+
const type = intervention.interventionType || 'revise';
|
|
302
|
+
|
|
303
|
+
// Track by type
|
|
304
|
+
if (!interventionsByType[type]) {
|
|
305
|
+
interventionsByType[type] = { count: 0, avgImprovement: 0, improvements: [] };
|
|
306
|
+
}
|
|
307
|
+
interventionsByType[type].count++;
|
|
308
|
+
|
|
309
|
+
// Find score before and after intervention
|
|
310
|
+
const turnBefore = turnResults.find(t => t.turnIndex === turnIndex - 1);
|
|
311
|
+
const turnAfter = turnResults.find(t => t.turnIndex === turnIndex);
|
|
312
|
+
|
|
313
|
+
if (turnBefore?.turnScore !== null && turnAfter?.turnScore !== null) {
|
|
314
|
+
const improvement = turnAfter.turnScore - turnBefore.turnScore;
|
|
315
|
+
interventionsByType[type].improvements.push(improvement);
|
|
316
|
+
totalImprovement += improvement;
|
|
317
|
+
measuredInterventions++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Calculate averages
|
|
322
|
+
for (const type of Object.keys(interventionsByType)) {
|
|
323
|
+
const imps = interventionsByType[type].improvements;
|
|
324
|
+
if (imps.length > 0) {
|
|
325
|
+
interventionsByType[type].avgImprovement = imps.reduce((a, b) => a + b, 0) / imps.length;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Find most effective type
|
|
330
|
+
let mostEffectiveType = null;
|
|
331
|
+
let bestAvgImprovement = -Infinity;
|
|
332
|
+
for (const [type, data] of Object.entries(interventionsByType)) {
|
|
333
|
+
if (data.avgImprovement > bestAvgImprovement) {
|
|
334
|
+
bestAvgImprovement = data.avgImprovement;
|
|
335
|
+
mostEffectiveType = type;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
interventionCount: interventions.length,
|
|
341
|
+
scoreImprovementAfterIntervention: measuredInterventions > 0
|
|
342
|
+
? totalImprovement / measuredInterventions
|
|
343
|
+
: null,
|
|
344
|
+
mostEffectiveInterventionType: mostEffectiveType,
|
|
345
|
+
interventionsByType,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Generate a comprehensive transformation report for a dialogue.
|
|
351
|
+
*
|
|
352
|
+
* @param {Array} dialogueTrace - Array of trace entries
|
|
353
|
+
* @param {Array} turnResults - Array of turn result objects
|
|
354
|
+
* @returns {Object} Comprehensive transformation report
|
|
355
|
+
*/
|
|
356
|
+
export function generateTransformationReport(dialogueTrace, turnResults) {
|
|
357
|
+
const superegoAnalysis = analyzeSuperegoIncorporation(dialogueTrace);
|
|
358
|
+
const bilateralAnalysis = analyzeBilateralTransformation(dialogueTrace);
|
|
359
|
+
const interventionAnalysis = analyzeInterventionEffectiveness(dialogueTrace, turnResults);
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
// Superego feedback patterns
|
|
363
|
+
superegoMetrics: {
|
|
364
|
+
incorporationRate: superegoAnalysis.incorporationRate,
|
|
365
|
+
feedbackPatterns: superegoAnalysis.feedbackPatterns,
|
|
366
|
+
avgConfidence: superegoAnalysis.avgConfidence,
|
|
367
|
+
totalFeedbackEvents: superegoAnalysis.totalFeedbackEvents,
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
// Bilateral transformation
|
|
371
|
+
bilateralMetrics: {
|
|
372
|
+
tutorTransformationCount: bilateralAnalysis.tutorTransformationCount,
|
|
373
|
+
learnerTransformationCount: bilateralAnalysis.learnerTransformationCount,
|
|
374
|
+
bilateralBalance: bilateralAnalysis.bilateralBalance,
|
|
375
|
+
isMutualTransformation: bilateralAnalysis.isMutualTransformation,
|
|
376
|
+
summary: bilateralAnalysis.summary,
|
|
377
|
+
},
|
|
378
|
+
|
|
379
|
+
// Intervention effectiveness
|
|
380
|
+
interventionMetrics: {
|
|
381
|
+
interventionCount: interventionAnalysis.interventionCount,
|
|
382
|
+
avgScoreImprovement: interventionAnalysis.scoreImprovementAfterIntervention,
|
|
383
|
+
mostEffectiveType: interventionAnalysis.mostEffectiveInterventionType,
|
|
384
|
+
},
|
|
385
|
+
|
|
386
|
+
// All transformation signals for timeline analysis
|
|
387
|
+
transformationSignals: superegoAnalysis.transformationSignals,
|
|
388
|
+
transformationTimeline: bilateralAnalysis.transformationTimeline,
|
|
389
|
+
|
|
390
|
+
// Summary assessment
|
|
391
|
+
overallAssessment: {
|
|
392
|
+
hasMutualTransformation: bilateralAnalysis.isMutualTransformation,
|
|
393
|
+
bilateralBalance: bilateralAnalysis.bilateralBalance,
|
|
394
|
+
superegoEffective: superegoAnalysis.incorporationRate !== null &&
|
|
395
|
+
superegoAnalysis.incorporationRate > 0.5,
|
|
396
|
+
transformationQuality: calculateTransformationQuality(
|
|
397
|
+
bilateralAnalysis,
|
|
398
|
+
superegoAnalysis,
|
|
399
|
+
interventionAnalysis
|
|
400
|
+
),
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Calculate an overall transformation quality score.
|
|
407
|
+
*
|
|
408
|
+
* @param {Object} bilateral - Bilateral transformation analysis
|
|
409
|
+
* @param {Object} superego - Superego analysis
|
|
410
|
+
* @param {Object} intervention - Intervention analysis
|
|
411
|
+
* @returns {number} Quality score (0-100)
|
|
412
|
+
*/
|
|
413
|
+
function calculateTransformationQuality(bilateral, superego, intervention) {
|
|
414
|
+
let score = 0;
|
|
415
|
+
let factors = 0;
|
|
416
|
+
|
|
417
|
+
// Bilateral balance (weight: 40%)
|
|
418
|
+
if (bilateral.bilateralBalance !== null) {
|
|
419
|
+
score += bilateral.bilateralBalance * 40;
|
|
420
|
+
factors += 40;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Mutual transformation (weight: 20%)
|
|
424
|
+
if (bilateral.isMutualTransformation) {
|
|
425
|
+
score += 20;
|
|
426
|
+
}
|
|
427
|
+
factors += 20;
|
|
428
|
+
|
|
429
|
+
// Superego incorporation (weight: 20%)
|
|
430
|
+
if (superego.incorporationRate !== null) {
|
|
431
|
+
score += Math.min(1, superego.incorporationRate) * 20;
|
|
432
|
+
factors += 20;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Intervention effectiveness (weight: 20%)
|
|
436
|
+
if (intervention.scoreImprovementAfterIntervention !== null) {
|
|
437
|
+
// Normalize improvement (assume max reasonable improvement is 20 points)
|
|
438
|
+
const normalizedImprovement = Math.min(1, Math.max(0,
|
|
439
|
+
intervention.scoreImprovementAfterIntervention / 20
|
|
440
|
+
));
|
|
441
|
+
score += normalizedImprovement * 20;
|
|
442
|
+
factors += 20;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return factors > 0 ? (score / factors) * 100 : 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export default {
|
|
449
|
+
analyzeSuperegoIncorporation,
|
|
450
|
+
extractTransformationSignals,
|
|
451
|
+
analyzeBilateralTransformation,
|
|
452
|
+
analyzeInterventionEffectiveness,
|
|
453
|
+
generateTransformationReport,
|
|
454
|
+
};
|