couchloop-eq-mcp 1.0.2 → 1.0.4
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 +29 -4
- package/dist/clients/shrinkChatClient.d.ts +10 -0
- package/dist/clients/shrinkChatClient.d.ts.map +1 -1
- package/dist/clients/shrinkChatClient.js +5 -1
- package/dist/clients/shrinkChatClient.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +5 -3
- package/dist/db/client.js.map +1 -1
- package/dist/db/schema.d.ts +363 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +47 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/governance/config.d.ts +66 -0
- package/dist/governance/config.d.ts.map +1 -0
- package/dist/governance/config.js +238 -0
- package/dist/governance/config.js.map +1 -0
- package/dist/governance/detectors/hallucination.d.ts +61 -0
- package/dist/governance/detectors/hallucination.d.ts.map +1 -0
- package/dist/governance/detectors/hallucination.js +338 -0
- package/dist/governance/detectors/hallucination.js.map +1 -0
- package/dist/governance/detectors/inconsistency.d.ts +99 -0
- package/dist/governance/detectors/inconsistency.d.ts.map +1 -0
- package/dist/governance/detectors/inconsistency.js +548 -0
- package/dist/governance/detectors/inconsistency.js.map +1 -0
- package/dist/governance/detectors/toneDrift.d.ts +63 -0
- package/dist/governance/detectors/toneDrift.d.ts.map +1 -0
- package/dist/governance/detectors/toneDrift.js +421 -0
- package/dist/governance/detectors/toneDrift.js.map +1 -0
- package/dist/governance/detectors/unsafeReasoning.d.ts +54 -0
- package/dist/governance/detectors/unsafeReasoning.d.ts.map +1 -0
- package/dist/governance/detectors/unsafeReasoning.js +473 -0
- package/dist/governance/detectors/unsafeReasoning.js.map +1 -0
- package/dist/governance/evaluationEngine.d.ts +112 -0
- package/dist/governance/evaluationEngine.d.ts.map +1 -0
- package/dist/governance/evaluationEngine.js +265 -0
- package/dist/governance/evaluationEngine.js.map +1 -0
- package/dist/governance/intervention.d.ts +81 -0
- package/dist/governance/intervention.d.ts.map +1 -0
- package/dist/governance/intervention.js +405 -0
- package/dist/governance/intervention.js.map +1 -0
- package/dist/server/chatgpt-mcp.d.ts +10 -0
- package/dist/server/chatgpt-mcp.d.ts.map +1 -0
- package/dist/server/chatgpt-mcp.js +233 -0
- package/dist/server/chatgpt-mcp.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +94 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/middleware/localNetworkAccess.d.ts +16 -0
- package/dist/server/middleware/localNetworkAccess.d.ts.map +1 -0
- package/dist/server/middleware/localNetworkAccess.js +97 -0
- package/dist/server/middleware/localNetworkAccess.js.map +1 -0
- package/dist/server/sse.d.ts +16 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +215 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/tools/checkpoint.d.ts.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/insight.d.ts +1 -0
- package/dist/tools/insight.d.ts.map +1 -1
- package/dist/tools/sendMessage-complex-backup.d.ts +6 -0
- package/dist/tools/sendMessage-complex-backup.d.ts.map +1 -0
- package/dist/tools/sendMessage-complex-backup.js +545 -0
- package/dist/tools/sendMessage-complex-backup.js.map +1 -0
- package/dist/tools/sendMessage-revised.d.ts +11 -0
- package/dist/tools/sendMessage-revised.d.ts.map +1 -0
- package/dist/tools/sendMessage-revised.js +429 -0
- package/dist/tools/sendMessage-revised.js.map +1 -0
- package/dist/tools/sendMessage-truly-simple.d.ts +8 -0
- package/dist/tools/sendMessage-truly-simple.d.ts.map +1 -0
- package/dist/tools/sendMessage-truly-simple.js +299 -0
- package/dist/tools/sendMessage-truly-simple.js.map +1 -0
- package/dist/tools/sendMessage.d.ts +4 -2
- package/dist/tools/sendMessage.d.ts.map +1 -1
- package/dist/tools/sendMessage.js +240 -186
- package/dist/tools/sendMessage.js.map +1 -1
- package/dist/tools/session.d.ts.map +1 -1
- package/dist/tools/session.js +35 -29
- package/dist/tools/session.js.map +1 -1
- package/dist/types/auth.d.ts +21 -13
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +108 -25
- package/dist/types/auth.js.map +1 -1
- package/dist/types/insight.d.ts +10 -0
- package/dist/types/insight.d.ts.map +1 -1
- package/dist/types/session.d.ts +10 -0
- package/dist/types/session.d.ts.map +1 -1
- package/package.json +10 -5
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CouchLoop Behavioral Governance Layer - Intervention Engine
|
|
3
|
+
*
|
|
4
|
+
* Handles response blocking, modification, rewriting, and fallback responses
|
|
5
|
+
* based on governance evaluation results
|
|
6
|
+
*/
|
|
7
|
+
import { InterventionAction, RiskLevel } from './evaluationEngine.js';
|
|
8
|
+
import { loadConfig } from './config.js';
|
|
9
|
+
export class InterventionEngine {
|
|
10
|
+
config;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config || loadConfig();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Main intervention method - applies appropriate action based on evaluation
|
|
16
|
+
*/
|
|
17
|
+
async intervene(action, originalResponse, evaluationResult) {
|
|
18
|
+
switch (action) {
|
|
19
|
+
case InterventionAction.APPROVE:
|
|
20
|
+
return this.approve(originalResponse, evaluationResult);
|
|
21
|
+
case InterventionAction.BLOCK:
|
|
22
|
+
return this.block(originalResponse, evaluationResult);
|
|
23
|
+
case InterventionAction.MODIFY:
|
|
24
|
+
return this.modify(originalResponse, evaluationResult);
|
|
25
|
+
case InterventionAction.FALLBACK:
|
|
26
|
+
return this.fallback(originalResponse, evaluationResult);
|
|
27
|
+
default:
|
|
28
|
+
// Default to approval if unknown action
|
|
29
|
+
return this.approve(originalResponse, evaluationResult);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Approve response without modification
|
|
34
|
+
*/
|
|
35
|
+
approve(originalResponse, evaluation) {
|
|
36
|
+
return {
|
|
37
|
+
action: InterventionAction.APPROVE,
|
|
38
|
+
originalResponse,
|
|
39
|
+
finalResponse: originalResponse,
|
|
40
|
+
modified: false,
|
|
41
|
+
reason: 'Response approved - no governance issues detected',
|
|
42
|
+
confidence: evaluation.confidence
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Block response and provide safe alternative
|
|
47
|
+
*/
|
|
48
|
+
block(originalResponse, evaluation) {
|
|
49
|
+
let reason = 'Response blocked due to: ';
|
|
50
|
+
const issues = [];
|
|
51
|
+
// Compile blocking reasons
|
|
52
|
+
if (evaluation.unsafeReasoning.detected) {
|
|
53
|
+
issues.push('unsafe reasoning patterns');
|
|
54
|
+
}
|
|
55
|
+
if (evaluation.hallucination.detected) {
|
|
56
|
+
issues.push('potential hallucination');
|
|
57
|
+
}
|
|
58
|
+
if (evaluation.inconsistency.detected) {
|
|
59
|
+
issues.push('logical inconsistencies');
|
|
60
|
+
}
|
|
61
|
+
if (evaluation.toneDrift.detected) {
|
|
62
|
+
issues.push('problematic tone drift');
|
|
63
|
+
}
|
|
64
|
+
reason += issues.join(', ');
|
|
65
|
+
// Select appropriate fallback message
|
|
66
|
+
let finalResponse;
|
|
67
|
+
if (evaluation.overallRisk === RiskLevel.CRITICAL ||
|
|
68
|
+
(evaluation.unsafeReasoning.detected && evaluation.unsafeReasoning.confidence > 0.8)) {
|
|
69
|
+
// Crisis or high-risk situation
|
|
70
|
+
finalResponse = this.config.fallbackResponses.crisis;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// General blocked response
|
|
74
|
+
finalResponse = this.config.fallbackResponses.blocked;
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
action: InterventionAction.BLOCK,
|
|
78
|
+
originalResponse,
|
|
79
|
+
finalResponse,
|
|
80
|
+
modified: true,
|
|
81
|
+
reason,
|
|
82
|
+
confidence: evaluation.confidence
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Modify response to remove or soften problematic content
|
|
87
|
+
*/
|
|
88
|
+
modify(originalResponse, evaluation) {
|
|
89
|
+
let modifiedResponse = originalResponse;
|
|
90
|
+
const modifications = [];
|
|
91
|
+
// Apply modifications based on detected issues
|
|
92
|
+
if (evaluation.hallucination.detected && evaluation.hallucination.patterns) {
|
|
93
|
+
modifiedResponse = this.removeHallucinatedContent(modifiedResponse, evaluation.hallucination.patterns, modifications);
|
|
94
|
+
}
|
|
95
|
+
if (evaluation.unsafeReasoning.detected && evaluation.unsafeReasoning.patterns) {
|
|
96
|
+
modifiedResponse = this.removeUnsafeContent(modifiedResponse, evaluation.unsafeReasoning.patterns, modifications);
|
|
97
|
+
}
|
|
98
|
+
if (evaluation.toneDrift.detected && evaluation.toneDrift.patterns) {
|
|
99
|
+
modifiedResponse = this.neutralizeTone(modifiedResponse, modifications);
|
|
100
|
+
}
|
|
101
|
+
if (evaluation.inconsistency.detected && evaluation.inconsistency.patterns) {
|
|
102
|
+
modifiedResponse = this.softenClaims(modifiedResponse, evaluation.inconsistency.patterns, modifications);
|
|
103
|
+
}
|
|
104
|
+
// If modifications were too extensive, use fallback
|
|
105
|
+
if (this.tooMuchRemoved(originalResponse, modifiedResponse)) {
|
|
106
|
+
return this.fallback(originalResponse, evaluation);
|
|
107
|
+
}
|
|
108
|
+
// Add modification prefix if configured
|
|
109
|
+
if (modifiedResponse !== originalResponse && this.config.fallbackResponses.modified) {
|
|
110
|
+
modifiedResponse = this.config.fallbackResponses.modified + '\n\n' + modifiedResponse;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
action: InterventionAction.MODIFY,
|
|
114
|
+
originalResponse,
|
|
115
|
+
finalResponse: modifiedResponse,
|
|
116
|
+
modified: true,
|
|
117
|
+
reason: `Response modified to address: ${modifications.map(m => m.reason).join(', ')}`,
|
|
118
|
+
modifications,
|
|
119
|
+
confidence: evaluation.confidence
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Replace with safe fallback response
|
|
124
|
+
*/
|
|
125
|
+
fallback(originalResponse, evaluation) {
|
|
126
|
+
// Select contextually appropriate fallback
|
|
127
|
+
let finalResponse;
|
|
128
|
+
let reason = 'Using fallback response due to: ';
|
|
129
|
+
if (evaluation.overallRisk === RiskLevel.CRITICAL) {
|
|
130
|
+
finalResponse = this.config.fallbackResponses.crisis;
|
|
131
|
+
reason += 'critical safety concerns';
|
|
132
|
+
}
|
|
133
|
+
else if (evaluation.unsafeReasoning.detected) {
|
|
134
|
+
finalResponse = this.config.fallbackResponses.crisis;
|
|
135
|
+
reason += 'unsafe reasoning detected';
|
|
136
|
+
}
|
|
137
|
+
else if (evaluation.overallRisk === RiskLevel.HIGH) {
|
|
138
|
+
finalResponse = this.config.fallbackResponses.blocked;
|
|
139
|
+
reason += 'high risk content';
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
finalResponse = this.config.fallbackResponses.error;
|
|
143
|
+
reason += 'multiple governance issues';
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
action: InterventionAction.FALLBACK,
|
|
147
|
+
originalResponse,
|
|
148
|
+
finalResponse,
|
|
149
|
+
modified: true,
|
|
150
|
+
reason,
|
|
151
|
+
confidence: evaluation.confidence
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Remove hallucinated content from response
|
|
156
|
+
*/
|
|
157
|
+
removeHallucinatedContent(response, patterns, modifications) {
|
|
158
|
+
let modified = response;
|
|
159
|
+
for (const pattern of patterns) {
|
|
160
|
+
// Extract the problematic phrase from the pattern description
|
|
161
|
+
const match = pattern.match(/: "(.+)"/);
|
|
162
|
+
if (match && match[1]) {
|
|
163
|
+
const problematicPhrase = match[1];
|
|
164
|
+
if (modified.includes(problematicPhrase)) {
|
|
165
|
+
// Remove the sentence containing the problematic phrase
|
|
166
|
+
const sentences = modified.split(/(?<=[.!?])\s+/);
|
|
167
|
+
const filteredSentences = sentences.filter(s => !s.includes(problematicPhrase));
|
|
168
|
+
if (filteredSentences.length < sentences.length) {
|
|
169
|
+
modifications.push({
|
|
170
|
+
type: 'removed',
|
|
171
|
+
original: sentences.find(s => s.includes(problematicPhrase)) || problematicPhrase,
|
|
172
|
+
modified: '',
|
|
173
|
+
reason: 'hallucinated content'
|
|
174
|
+
});
|
|
175
|
+
modified = filteredSentences.join(' ');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Replace absolute certainty with hedged language
|
|
181
|
+
const certaintyReplacements = [
|
|
182
|
+
[/definitely will/gi, 'might'],
|
|
183
|
+
[/absolutely certain/gi, 'possible'],
|
|
184
|
+
[/guaranteed to/gi, 'may'],
|
|
185
|
+
[/proven fact/gi, 'current understanding'],
|
|
186
|
+
[/everyone knows/gi, 'it is commonly believed'],
|
|
187
|
+
[/always works/gi, 'often helps'],
|
|
188
|
+
[/never fails/gi, 'typically effective']
|
|
189
|
+
];
|
|
190
|
+
for (const [pattern, replacement] of certaintyReplacements) {
|
|
191
|
+
const before = modified;
|
|
192
|
+
modified = modified.replace(pattern, replacement);
|
|
193
|
+
if (before !== modified) {
|
|
194
|
+
modifications.push({
|
|
195
|
+
type: 'replaced',
|
|
196
|
+
original: pattern.source,
|
|
197
|
+
modified: replacement,
|
|
198
|
+
reason: 'reduced false certainty'
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return modified;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Remove unsafe content from response
|
|
206
|
+
*/
|
|
207
|
+
removeUnsafeContent(response, patterns, modifications) {
|
|
208
|
+
let modified = response;
|
|
209
|
+
for (const pattern of patterns) {
|
|
210
|
+
// Extract the problematic phrase
|
|
211
|
+
const match = pattern.match(/: "(.+)"/);
|
|
212
|
+
if (match && match[1]) {
|
|
213
|
+
const unsafePhrase = match[1];
|
|
214
|
+
// Check if this is critical content that should be removed entirely
|
|
215
|
+
if (pattern.includes('critical') || pattern.includes('Suicide') || pattern.includes('Self-harm')) {
|
|
216
|
+
// Remove entire sentences containing critical unsafe content
|
|
217
|
+
const sentences = modified.split(/(?<=[.!?])\s+/);
|
|
218
|
+
const safeSentences = sentences.filter(s => !s.toLowerCase().includes(unsafePhrase.toLowerCase()));
|
|
219
|
+
if (safeSentences.length < sentences.length) {
|
|
220
|
+
modifications.push({
|
|
221
|
+
type: 'removed',
|
|
222
|
+
original: sentences.find(s => s.toLowerCase().includes(unsafePhrase.toLowerCase())) || unsafePhrase,
|
|
223
|
+
modified: '',
|
|
224
|
+
reason: 'critical safety concern'
|
|
225
|
+
});
|
|
226
|
+
modified = safeSentences.join(' ');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// For non-critical unsafe content, try to soften or replace
|
|
231
|
+
const safeAlternatives = {
|
|
232
|
+
'you should definitely': 'you might consider',
|
|
233
|
+
'you must': 'it could be helpful to',
|
|
234
|
+
'stop taking your medication': 'discuss your medication concerns with your doctor',
|
|
235
|
+
"don't need therapy": 'therapy is a personal choice',
|
|
236
|
+
'ignore what they said': 'consider different perspectives',
|
|
237
|
+
"don't tell anyone": 'sharing with trusted people can help'
|
|
238
|
+
};
|
|
239
|
+
for (const [unsafe, safe] of Object.entries(safeAlternatives)) {
|
|
240
|
+
if (modified.toLowerCase().includes(unsafe)) {
|
|
241
|
+
modified = modified.replace(new RegExp(unsafe, 'gi'), safe);
|
|
242
|
+
modifications.push({
|
|
243
|
+
type: 'replaced',
|
|
244
|
+
original: unsafe,
|
|
245
|
+
modified: safe,
|
|
246
|
+
reason: 'unsafe advice neutralized'
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return modified;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Neutralize problematic tone in response
|
|
257
|
+
*/
|
|
258
|
+
neutralizeTone(response, modifications) {
|
|
259
|
+
let modified = response;
|
|
260
|
+
// Tone neutralization replacements
|
|
261
|
+
const toneReplacements = [
|
|
262
|
+
// Over-reassurance
|
|
263
|
+
[/everything will be (fine|perfect|great)/gi, 'things may improve'],
|
|
264
|
+
[/don't worry about anything/gi, "it's natural to have concerns"],
|
|
265
|
+
[/absolutely no risk/gi, 'relatively low risk'],
|
|
266
|
+
[/I promise/gi, 'I believe'],
|
|
267
|
+
// Over-directive
|
|
268
|
+
[/you must/gi, 'you might consider'],
|
|
269
|
+
[/you have to/gi, 'it could help to'],
|
|
270
|
+
[/you need to/gi, 'you may want to'],
|
|
271
|
+
[/it's essential that you/gi, 'it could be beneficial to'],
|
|
272
|
+
// Manipulative
|
|
273
|
+
[/only I can help/gi, 'support is available'],
|
|
274
|
+
[/you need me/gi, 'support can help'],
|
|
275
|
+
[/trust me, not them/gi, 'consider various perspectives'],
|
|
276
|
+
// Dependency-forming
|
|
277
|
+
[/I'll always be here/gi, 'support is available'],
|
|
278
|
+
[/come back to me anytime/gi, 'help is available when needed'],
|
|
279
|
+
[/you can't do this without me/gi, 'support can be helpful']
|
|
280
|
+
];
|
|
281
|
+
for (const [pattern, replacement] of toneReplacements) {
|
|
282
|
+
const matches = modified.match(pattern);
|
|
283
|
+
if (matches) {
|
|
284
|
+
modified = modified.replace(pattern, replacement);
|
|
285
|
+
modifications.push({
|
|
286
|
+
type: 'neutralized',
|
|
287
|
+
original: matches[0],
|
|
288
|
+
modified: replacement,
|
|
289
|
+
reason: 'tone neutralization'
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Remove excessive emotional language
|
|
294
|
+
const emotionalWords = /\b(amazing|terrible|horrible|perfect|disaster|catastrophe|miracle)\b/gi;
|
|
295
|
+
const emotionalMatches = modified.match(emotionalWords);
|
|
296
|
+
if (emotionalMatches && emotionalMatches.length > 2) {
|
|
297
|
+
// Replace with more neutral terms
|
|
298
|
+
modified = modified
|
|
299
|
+
.replace(/\bamazing\b/gi, 'positive')
|
|
300
|
+
.replace(/\bterrible\b/gi, 'difficult')
|
|
301
|
+
.replace(/\bhorrible\b/gi, 'challenging')
|
|
302
|
+
.replace(/\bperfect\b/gi, 'good')
|
|
303
|
+
.replace(/\bdisaster\b/gi, 'setback')
|
|
304
|
+
.replace(/\bcatastrophe\b/gi, 'difficulty')
|
|
305
|
+
.replace(/\bmiracle\b/gi, 'improvement');
|
|
306
|
+
modifications.push({
|
|
307
|
+
type: 'neutralized',
|
|
308
|
+
original: 'excessive emotional language',
|
|
309
|
+
modified: 'neutral terms',
|
|
310
|
+
reason: 'emotional de-escalation'
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
return modified;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Soften claims to address inconsistencies
|
|
317
|
+
*/
|
|
318
|
+
softenClaims(response, patterns, modifications) {
|
|
319
|
+
let modified = response;
|
|
320
|
+
// Add hedging language to strong claims
|
|
321
|
+
const hedgeReplacements = [
|
|
322
|
+
[/\bis\b/gi, 'may be'],
|
|
323
|
+
[/\bare\b/gi, 'might be'],
|
|
324
|
+
[/\bwill\b/gi, 'could'],
|
|
325
|
+
[/\balways\b/gi, 'often'],
|
|
326
|
+
[/\bnever\b/gi, 'rarely'],
|
|
327
|
+
[/\bdefinitely\b/gi, 'probably'],
|
|
328
|
+
[/\bcertainly\b/gi, 'likely']
|
|
329
|
+
];
|
|
330
|
+
// Only apply hedging to sentences mentioned in contradiction patterns
|
|
331
|
+
for (const pattern of patterns) {
|
|
332
|
+
if (pattern.includes('Contradiction') || pattern.includes('Reversal')) {
|
|
333
|
+
// Extract the current claim from the pattern
|
|
334
|
+
const match = pattern.match(/Current: "(.+?)"/);
|
|
335
|
+
if (match && match[1]) {
|
|
336
|
+
const claim = match[1];
|
|
337
|
+
// Find and soften this claim in the response
|
|
338
|
+
if (modified.includes(claim)) {
|
|
339
|
+
let softenedClaim = claim;
|
|
340
|
+
for (const [original, hedged] of hedgeReplacements) {
|
|
341
|
+
softenedClaim = softenedClaim.replace(original, hedged);
|
|
342
|
+
}
|
|
343
|
+
if (softenedClaim !== claim) {
|
|
344
|
+
modified = modified.replace(claim, softenedClaim);
|
|
345
|
+
modifications.push({
|
|
346
|
+
type: 'softened',
|
|
347
|
+
original: claim,
|
|
348
|
+
modified: softenedClaim,
|
|
349
|
+
reason: 'addressing inconsistency'
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return modified;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Check if too much content was removed
|
|
360
|
+
*/
|
|
361
|
+
tooMuchRemoved(original, modified) {
|
|
362
|
+
const originalLength = original.length;
|
|
363
|
+
const modifiedLength = modified.length;
|
|
364
|
+
// If more than 60% was removed, use fallback instead
|
|
365
|
+
const removalRatio = (originalLength - modifiedLength) / originalLength;
|
|
366
|
+
return removalRatio > 0.6;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Apply intervention based on evaluation without explicit action
|
|
370
|
+
*/
|
|
371
|
+
async autoIntervene(originalResponse, evaluationResult) {
|
|
372
|
+
// Use the recommended action from evaluation
|
|
373
|
+
const action = evaluationResult.recommendedAction;
|
|
374
|
+
return this.intervene(action, originalResponse, evaluationResult);
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Generate explanation for intervention
|
|
378
|
+
*/
|
|
379
|
+
generateExplanation(result) {
|
|
380
|
+
if (!result.modified) {
|
|
381
|
+
return 'Response approved without modifications.';
|
|
382
|
+
}
|
|
383
|
+
let explanation = `Governance intervention applied (${result.action}): ${result.reason}\n`;
|
|
384
|
+
if (result.modifications && result.modifications.length > 0) {
|
|
385
|
+
explanation += '\nModifications made:\n';
|
|
386
|
+
for (const mod of result.modifications) {
|
|
387
|
+
explanation += `- ${mod.type}: ${mod.reason}\n`;
|
|
388
|
+
if (mod.original && mod.modified) {
|
|
389
|
+
explanation += ` From: "${mod.original}"\n`;
|
|
390
|
+
explanation += ` To: "${mod.modified}"\n`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
explanation += `\nConfidence: ${(result.confidence * 100).toFixed(1)}%`;
|
|
395
|
+
return explanation;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Update configuration
|
|
399
|
+
*/
|
|
400
|
+
updateConfig(config) {
|
|
401
|
+
this.config = config;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
export default InterventionEngine;
|
|
405
|
+
//# sourceMappingURL=intervention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intervention.js","sourceRoot":"","sources":["../../src/governance/intervention.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom MCP handler for ChatGPT Developer Mode
|
|
3
|
+
* Implements MCP protocol directly over HTTP without StreamableHTTPServerTransport
|
|
4
|
+
*/
|
|
5
|
+
import { Request, Response } from 'express';
|
|
6
|
+
/**
|
|
7
|
+
* Handle MCP requests from ChatGPT
|
|
8
|
+
*/
|
|
9
|
+
export declare function handleChatGPTMCP(req: Request, res: Response): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=chatgpt-mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatgpt-mcp.d.ts","sourceRoot":"","sources":["../../src/server/chatgpt-mcp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAmC5C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAyNjE"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom MCP handler for ChatGPT Developer Mode
|
|
3
|
+
* Implements MCP protocol directly over HTTP without StreamableHTTPServerTransport
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
import { setupTools } from '../tools/index.js';
|
|
7
|
+
import { setupResources } from '../resources/index.js';
|
|
8
|
+
// Store sessions by ID
|
|
9
|
+
const sessions = new Map();
|
|
10
|
+
// Cache tool and resource definitions at module level for performance
|
|
11
|
+
// These are static and don't change, so we only need to load them once
|
|
12
|
+
let cachedTools = null;
|
|
13
|
+
let cachedResources = null;
|
|
14
|
+
/**
|
|
15
|
+
* Get cached tools or load them once
|
|
16
|
+
*/
|
|
17
|
+
async function getCachedTools() {
|
|
18
|
+
if (!cachedTools) {
|
|
19
|
+
logger.info('Loading tool definitions (one-time initialization)');
|
|
20
|
+
cachedTools = await setupTools();
|
|
21
|
+
}
|
|
22
|
+
return cachedTools;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get cached resources or load them once
|
|
26
|
+
*/
|
|
27
|
+
async function getCachedResources() {
|
|
28
|
+
if (!cachedResources) {
|
|
29
|
+
logger.info('Loading resource definitions (one-time initialization)');
|
|
30
|
+
cachedResources = await setupResources();
|
|
31
|
+
}
|
|
32
|
+
return cachedResources;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Handle MCP requests from ChatGPT
|
|
36
|
+
*/
|
|
37
|
+
export async function handleChatGPTMCP(req, res) {
|
|
38
|
+
try {
|
|
39
|
+
logger.info('ChatGPT MCP Request:', {
|
|
40
|
+
method: req.body?.method,
|
|
41
|
+
id: req.body?.id,
|
|
42
|
+
params: req.body?.params
|
|
43
|
+
});
|
|
44
|
+
// Get or create session
|
|
45
|
+
const sessionId = req.headers['x-session-id'] || 'default';
|
|
46
|
+
if (!sessions.has(sessionId)) {
|
|
47
|
+
// Use cached tools and resources for performance (saves ~30ms per request)
|
|
48
|
+
sessions.set(sessionId, {
|
|
49
|
+
tools: await getCachedTools(),
|
|
50
|
+
resources: await getCachedResources(),
|
|
51
|
+
initialized: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const session = sessions.get(sessionId);
|
|
55
|
+
const { method, params, id } = req.body;
|
|
56
|
+
// Handle different MCP methods
|
|
57
|
+
switch (method) {
|
|
58
|
+
case 'initialize': {
|
|
59
|
+
session.initialized = true;
|
|
60
|
+
// Return capabilities
|
|
61
|
+
const response = {
|
|
62
|
+
jsonrpc: '2.0',
|
|
63
|
+
id,
|
|
64
|
+
result: {
|
|
65
|
+
protocolVersion: params.protocolVersion || '2024-11-05',
|
|
66
|
+
capabilities: {
|
|
67
|
+
tools: {
|
|
68
|
+
listChanged: false
|
|
69
|
+
},
|
|
70
|
+
resources: {
|
|
71
|
+
subscribe: false,
|
|
72
|
+
listChanged: false
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
serverInfo: {
|
|
76
|
+
name: 'couchloop-mcp',
|
|
77
|
+
version: '1.0.2'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
logger.info('Sending initialize response:', response);
|
|
82
|
+
res.json(response);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'tools/list': {
|
|
86
|
+
const response = {
|
|
87
|
+
jsonrpc: '2.0',
|
|
88
|
+
id,
|
|
89
|
+
result: {
|
|
90
|
+
tools: session.tools.map((t) => t.definition)
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
logger.info('Sending tools list:', response);
|
|
94
|
+
res.json(response);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'tools/call': {
|
|
98
|
+
const tool = session.tools.find((t) => t.definition.name === params.name);
|
|
99
|
+
if (!tool) {
|
|
100
|
+
res.json({
|
|
101
|
+
jsonrpc: '2.0',
|
|
102
|
+
id,
|
|
103
|
+
error: {
|
|
104
|
+
code: -32602,
|
|
105
|
+
message: `Tool not found: ${params.name}`
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
// Extract stable identifiers from ChatGPT metadata
|
|
112
|
+
const openaiSession = params._meta?.['openai/session'];
|
|
113
|
+
const openaiSubject = params._meta?.['openai/subject'];
|
|
114
|
+
// Inject auth context using OpenAI's stable identifiers
|
|
115
|
+
const enhancedArguments = {
|
|
116
|
+
...params.arguments,
|
|
117
|
+
auth: params.arguments?.auth || {
|
|
118
|
+
client_id: 'chatgpt',
|
|
119
|
+
conversation_id: openaiSession || sessionId, // Use OpenAI session as conversation ID
|
|
120
|
+
user_id: openaiSubject // Use OpenAI subject as stable user ID (priority 1 in auth hierarchy)
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
logger.info('Enhanced arguments with auth:', {
|
|
124
|
+
hasAuth: !!enhancedArguments.auth,
|
|
125
|
+
authUserId: enhancedArguments.auth?.user_id,
|
|
126
|
+
authConversationId: enhancedArguments.auth?.conversation_id,
|
|
127
|
+
toolName: params.name
|
|
128
|
+
});
|
|
129
|
+
const result = await tool.handler(enhancedArguments);
|
|
130
|
+
// Wrap the result in MCP content format
|
|
131
|
+
const response = {
|
|
132
|
+
jsonrpc: '2.0',
|
|
133
|
+
id,
|
|
134
|
+
result: {
|
|
135
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
logger.info('Tool call result:', response);
|
|
139
|
+
res.json(response);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logger.error('Tool call error:', error);
|
|
143
|
+
res.json({
|
|
144
|
+
jsonrpc: '2.0',
|
|
145
|
+
id,
|
|
146
|
+
error: {
|
|
147
|
+
code: -32603,
|
|
148
|
+
message: error.message || 'Tool execution failed'
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'resources/list': {
|
|
155
|
+
const response = {
|
|
156
|
+
jsonrpc: '2.0',
|
|
157
|
+
id,
|
|
158
|
+
result: {
|
|
159
|
+
resources: session.resources.map((r) => r.definition)
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
logger.info('Sending resources list:', response);
|
|
163
|
+
res.json(response);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'resources/read': {
|
|
167
|
+
const resource = session.resources.find((r) => r.definition.uri === params.uri);
|
|
168
|
+
if (!resource) {
|
|
169
|
+
res.json({
|
|
170
|
+
jsonrpc: '2.0',
|
|
171
|
+
id,
|
|
172
|
+
error: {
|
|
173
|
+
code: -32602,
|
|
174
|
+
message: `Resource not found: ${params.uri}`
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
const content = await resource.handler();
|
|
181
|
+
const response = {
|
|
182
|
+
jsonrpc: '2.0',
|
|
183
|
+
id,
|
|
184
|
+
result: {
|
|
185
|
+
contents: [{
|
|
186
|
+
uri: params.uri,
|
|
187
|
+
mimeType: resource.definition.mimeType || 'application/json',
|
|
188
|
+
text: content
|
|
189
|
+
}]
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
logger.info('Resource read result:', response);
|
|
193
|
+
res.json(response);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
logger.error('Resource read error:', error);
|
|
197
|
+
res.json({
|
|
198
|
+
jsonrpc: '2.0',
|
|
199
|
+
id,
|
|
200
|
+
error: {
|
|
201
|
+
code: -32603,
|
|
202
|
+
message: error.message || 'Resource read failed'
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
default: {
|
|
209
|
+
res.json({
|
|
210
|
+
jsonrpc: '2.0',
|
|
211
|
+
id,
|
|
212
|
+
error: {
|
|
213
|
+
code: -32601,
|
|
214
|
+
message: `Method not found: ${method}`
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
logger.error('ChatGPT MCP handler error:', error);
|
|
222
|
+
res.status(500).json({
|
|
223
|
+
jsonrpc: '2.0',
|
|
224
|
+
id: req.body?.id,
|
|
225
|
+
error: {
|
|
226
|
+
code: -32603,
|
|
227
|
+
message: 'Internal error',
|
|
228
|
+
data: error instanceof Error ? error.message : 'Unknown error'
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=chatgpt-mcp.js.map
|