defrag-proto / src /app /api /chat /route.ts
cjo93's picture
Create src/app/api/chat/route.ts
0550632 verified
import { NextRequest, NextResponse } from 'next/server';
import {
intakeMessage,
parseIntent,
retrieveContext,
evaluateTiming,
synthesize,
type Synthesis,
} from '@/lib/defrag/pipeline';
// Stage 6: Safety and Scope Check
function applySafetyFilter(synthesis: Synthesis): { pass: boolean; reason?: string } {
// Ensure relational focus, non-diagnostic, emotionally safe
if (synthesis.userState.includes('diagnose') || synthesis.userState.includes('disorder')) {
return { pass: false, reason: 'Diagnostic language detected' };
}
return { pass: true };
}
// Stage 7: Response Generation (using OpenAI)
async function generateResponse(synthesis: Synthesis): Promise<string> {
const systemPrompt = `You are the DEFRAG AI — a relational intelligence system.
Your role:
- Interpret relational dynamics using structured context
- Translate perception differences between people
- Offer practical, grounded guidance
- Maintain calm, emotionally mature tone
- Never diagnose or use clinical labels
- Focus on relational understanding, not general advice
Current synthesis:
User state: ${synthesis.userState}
Other state: ${synthesis.otherState}
Dynamic: ${synthesis.dynamicBetween}
Timing: ${synthesis.timingSuggestion}
Generate a response that:
1. Acknowledges the user's experience
2. Explains the relational dynamic
3. Translates the other person's likely perspective
4. Offers 2-3 practical next steps
5. Returns agency to the user`;
// In production: call OpenAI API
// For prototype: return structured mock based on synthesis
const mockResponse = `That makes sense. ${synthesis.userState}
${synthesis.otherState}
${synthesis.dynamicBetween}
${synthesis.timingSuggestion}
Here are a few approaches you could try:
- Start from what you want more of, rather than what feels frustrating
- Ask for their perspective before sharing your own
- If the moment feels charged, waiting could give the conversation a better chance
The choice is yours.`;
return mockResponse;
}
// Stage 8: Follow-up Actions
function attachFollowUpActions(synthesis: Synthesis) {
return [
{ id: 'why', label: 'What makes you say that?', action: 'explain_reasoning' },
{ id: 'retry', label: 'Try another approach', action: 'regenerate' },
{ id: 'simulate', label: 'Practice the conversation', action: 'start_simulation' },
{ id: 'challenge', label: "That doesn't sound like them", action: 'correct_model' },
];
}
// Full Pipeline Orchestration
export async function POST(request: NextRequest) {
try {
const { message } = await request.json();
if (!message || typeof message !== 'string') {
return NextResponse.json({ error: 'Invalid message' }, { status: 400 });
}
// Stage 1: Intake
const intake = intakeMessage(message);
// Stage 2: Parse
const situation = parseIntent(message, intake);
// Stage 3: Retrieve Context
const context = retrieveContext(situation);
// Stage 4: Timing Evaluation
const timing = evaluateTiming(context);
// Stage 5: Synthesis
const synthesis = synthesize(situation, context, timing);
// Stage 6: Safety Check
const safety = applySafetyFilter(synthesis);
if (!safety.pass) {
return NextResponse.json(
{ error: 'Safety filter triggered', reason: safety.reason },
{ status: 400 }
);
}
// Stage 7: Response Generation
const response = await generateResponse(synthesis);
// Stage 8: Attach Follow-up Actions
const actions = attachFollowUpActions(synthesis);
// Return structured response
return NextResponse.json({
response,
synthesis: {
intent: intake.messageClass,
relationship: situation.primaryRelationship,
dynamic: situation.dynamic,
timing: timing.assessment,
},
actions,
});
} catch (error) {
console.error('Pipeline error:', error);
return NextResponse.json({ error: 'Internal pipeline error' }, { status: 500 });
}
}