/**
* insight-layer-c.js
*
* Layer C – Response Writing
* ————————–
*
* Purpose:
* Express Layer B decisions as user-facing coaching responses.
*
* Layer C must NOT:
* – decide whether to reflect
* – decide whether to move step
* – decide whether to follow up
* – assess traits
* – extract evidence
* – write Insight reviews
* – save directly to the database
*/
(function () {
‘use strict’;
function clean(value) {
return String(value == null ? ” : value).trim();
}
/**
* C1 – Reflection Writer
*
* Writes a short reflection only when Layer B has already decided
* that a reflection is required.
*/
async function writeReflection(ctx, layerB) {
const config = ctx.config || {};
const reflection = layerB?.reflection || {};
if (!reflection.reflection_required) return ”;
if (!config.aiUrl) return clean(reflection.reflection_basis);
const payload = {
model: ‘gpt-4o’,
temperature: 0.3,
messages: [
{
role: ‘system’,
content:
`You are C1 Reflection Writer in a structured AI Coach system.
Your role:
Write a brief user-facing reflection based only on Layer B’s reflection basis.
Rules:
– Write 1–3 sentences.
– Stay close to the user’s evidence.
– Do not infer hidden motives.
– Do not diagnose.
– Do not praise.
– Do not introduce a new coaching direction.
– Do not ask a question.
– Use UK English.`
},
{
role: ‘user’,
content:
`REFLECTION BASIS:
${clean(reflection.reflection_basis)}
RELEVANT EVIDENCE:
${JSON.stringify(reflection.relevant_evidence || [])}
LATEST USER REPLY:
${clean(ctx.userText)}`
}
]
};
try {
const aiResult = await window.cpAiService.callText({
task: ‘layer_c_reflection_writer’,
responseId: ctx.responseId,
config,
payload
});
if (!aiResult.ok) {
throw new Error(
aiResult.error?.message ||
‘Layer C1 AI request failed.’
);
}
return clean(aiResult.data) ||
clean(reflection.reflection_basis);
} catch (err) {
console.log(‘LAYER C1 ERROR:’, err);
return clean(reflection.reflection_basis);
}
}
/**
* C2 – Question Writer
*
* Writes the next coaching question according to Layer B’s response strategy.
*
* Layer B decides:
* – next_step
* – follow_up
* – non_resonance
*
* Layer C only writes.
*/
async function writeQuestion(ctx, layerB, reflectionText) {
const config = ctx.config || {};
const strategy = layerB?.strategy || {};
const responseStrategy = clean(strategy.response_strategy);
if (!config.aiUrl) {
return clean(ctx.nextFrameworkStep || ctx.currentFrameworkStep || ctx.insightQuestion);
}
const targetStep =
responseStrategy === ‘next_step’
? clean(ctx.nextFrameworkStep || ctx.currentFrameworkStep)
: clean(ctx.currentFrameworkStep);
const payload = {
model: ‘gpt-4o’,
temperature: 0.4,
messages: [
{
role: ‘system’,
content:
`You are C2 Question Writer in a structured AI Coach system.
Your role:
Write the next user-facing coaching question.
Rules:
– Ask one question only.
– Use an open question unless the framework explicitly requires a closed question.
– Avoid questions that can be answered only with yes, no, or a single word.
– Prefer wording that invites the user to describe, explain, reflect, or give an example.
– Follow Layer B’s response strategy.
– If strategy is follow_up, stay on the current framework step.
– If strategy is next_step, ask the next framework step question.
– Do not make progression decisions.
– Do not assess whether the user has answered.
– Do not extract evidence.
– Do not assess traits.
– Do not introduce a new coaching direction.
– Stay aligned with the framework.
– Use UK English.
Style guidance:
${clean(ctx.coachStyle)}
Insight guidance:
${clean(ctx.aiStepPromptV3)}`
},
{
role: ‘user’,
content:
`RESPONSE STRATEGY:
${responseStrategy}
STRATEGY REASON:
${clean(strategy.reason)}
FOLLOW-UP GAP:
${clean(strategy.follow_up_gap)}
CURRENT FRAMEWORK STEP:
${clean(ctx.currentFrameworkStep)}
NEXT FRAMEWORK STEP:
${clean(ctx.nextFrameworkStep)}
TARGET STEP TO WRITE:
${targetStep}
REFLECTION ALREADY WRITTEN:
${clean(reflectionText)}
LATEST USER REPLY:
${clean(ctx.userText)}
INSIGHT SUMMARY:
${clean(ctx.insightSummary)}
INSIGHT QUESTION:
${clean(ctx.insightQuestion)}`
}
]
};
const fallback =
clean(ctx.nextFrameworkStep || ctx.currentFrameworkStep || ctx.insightQuestion);
try {
const aiResult = await window.cpAiService.callText({
task: ‘layer_c_question_writer’,
responseId: ctx.responseId,
config,
payload
});
if (!aiResult.ok) {
throw new Error(
aiResult.error?.message ||
‘Layer C2 AI request failed.’
);
}
return clean(aiResult.data) || fallback;
} catch (err) {
console.log(‘LAYER C2 ERROR:’, err);
return fallback;
}
}
/**
* C3 – Respectful Ending Writer
*
* Used only when Layer B has already decided non_resonance.
*/
async function writeRespectfulEnding(ctx, layerB) {
const config = ctx.config || {};
const strategy = layerB?.strategy || {};
const fallback =
“It sounds as though this Insight may not feel especially relevant for you right now. That’s fine — we can leave it here and move on.”;
if (!config.aiUrl) return fallback;
const payload = {
model: ‘gpt-4o’,
temperature: 0.3,
messages: [
{
role: ‘system’,
content:
`You are C3 Respectful Ending Writer.
Write a short ending message when an Insight is non-resonant.
Rules:
– Do not persuade.
– Do not challenge.
– Do not criticise.
– Preserve user agency.
– Keep it concise.
– Use UK English.`
},
{
role: ‘user’,
content:
`NON-RESONANCE REASON:
${clean(strategy.reason)}
LATEST USER REPLY:
${clean(ctx.userText)}
INSIGHT QUESTION:
${clean(ctx.insightQuestion)}`
}
]
};
try {
const aiResult = await window.cpAiService.callText({
task: ‘layer_c_respectful_ending’,
responseId: ctx.responseId,
config,
payload
});
if (!aiResult.ok) {
throw new Error(
aiResult.error?.message ||
‘Layer C3 AI request failed.’
);
}
return clean(aiResult.data) || fallback;
} catch (err) {
console.log(‘LAYER C3 ERROR:’, err);
return fallback;
} }
/**
* runLayerC()
*
* Main Layer C entry point.
*
* Returns:
* {
* reflection: “…”,
* question: “…”,
* ending: “”,
* response_type: “question|ending”
* }
*/
async function runLayerC(ctx, layerB) {
const strategy = clean(layerB?.strategy?.response_strategy);
if (strategy === ‘non_resonance’) {
const ending = await writeRespectfulEnding(ctx, layerB);
return {
reflection: ”,
question: ”,
ending,
response_type: ‘ending’
};
}
const reflection = await writeReflection(ctx, layerB);
const question = await writeQuestion(ctx, layerB, reflection);
return {
reflection,
question,
ending: ”,
response_type: ‘question’
};
}
window.cpInsightLayerC = {
runLayerC,
writeReflection,
writeQuestion,
writeRespectfulEnding
};
})();