Skip to main content

Explanation Generation

Overview

The Explanation Generation step synthesizes findings from temporal, pattern, and correlation analysis into a coherent human-readable narrative.

File: steps/explanation.step.ts

What It Does

  1. Aggregates findings from all prior analysis steps
  2. Builds context including user notes (if available)
  3. Generates narrative using explanation agent (or template fallback)

Input

Requires outputs from prior steps:

{
objective: string,
temporal?: TemporalOutput,
pattern?: PatternOutput,
correlation?: CorrelationOutput,
domain?: DomainOutput,
// Extended context for richer explanations
compactedRows?: Array<{ Value?: string; Kind?: string }>,
selectedNotes?: Array<{ date: string; label: string; note: string }>,
weeklySummaries?: Array<WeeklySummary>
}

Output

{
explanation: {
narrative: string, // Main explanation text
keyPoints: string[] // Bullet-point highlights
}
}

Agent Payload

The explanation agent receives rich context:

const payload = {
objective: inputData.objective,
temporal: inputData.temporal,
pattern: inputData.pattern,
correlation: inputData.correlation,
domain: inputData.domain,
dataContext: {
dayCount: number,
datasetCount: number,
seriesCount: number,
hasUserNotes: boolean,
isLargeDataset: boolean
},
userNotes?: string[], // Up to 30 pre-selected notes
weeklySummaries?: object[] // Weekly aggregations
};

Fallback Generation

When no agent is available, template-based generation:

function buildFallbackExplanation(inputData): ExplanationOutput {
const narrativeParts: string[] = [
`Objective: ${inputData.objective}`
];

if (inputData.temporal?.summary) {
narrativeParts.push(`Temporal: ${inputData.temporal.summary}`);
}
if (inputData.pattern?.matches?.length) {
narrativeParts.push(`Patterns: ${inputData.pattern.matches.join('; ')}`);
}
if (inputData.correlation?.summary) {
narrativeParts.push(`Correlations: ${inputData.correlation.summary}`);
}

const keyPoints = [
...(inputData.temporal?.insights ?? []),
...(inputData.pattern?.detectedPatterns?.map(p => p.detail) ?? []),
...(inputData.correlation?.insights ?? [])
].slice(0, 8);

return { narrative: narrativeParts.join('\n'), keyPoints };
}

Example Output

{
"explanation": {
"narrative": "Over the past 30 days, your stress levels have shown a notable upward trend, increasing from an average of 2.5 to 4.1. This coincides with a moderate decline in sleep quality. The data reveals a strong negative correlation between stress and mood (r=-0.78), suggesting that managing stress could have positive effects on your overall emotional wellbeing.\n\nYour energy levels, while showing some day-to-day variation, appear closely tied to sleep quality (r=0.71). The patterns suggest that prioritizing consistent sleep could help stabilize both energy and mood.",
"keyPoints": [
"Stress increased 64% over the analysis period",
"Strong inverse relationship between stress and mood",
"Sleep quality directly impacts next-day energy",
"Weekend stress levels are notably lower than weekdays",
"Consider stress management as primary intervention"
]
}
}

Large Dataset Handling

For datasets with many check-ins, the step uses pre-processed data:

  • selectedNotes: High-value notes scored and deduplicated
  • weeklySummaries: Aggregated weekly metrics
  • Up to 30 notes included (vs 10 for standard datasets)

Skip Conditions

This step is skipped if:

  • stepPlan exists and doesn't include 'explanation'