File size: 3,801 Bytes
cb5990d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * Metacognitive Prompts Configuration
 *
 * Parses environment variables for metacognitive prompt feature:
 * - METACOGNITIVE_FREQUENCIES: Comma-separated list of integers (e.g., "3,5,10")
 * - METACOGNITIVE_PROMPTS_COMPREHENSION: JSON array of prompt templates
 * - METACOGNITIVE_PROMPTS_PERSPECTIVE: JSON array of prompt templates with {{personaName}} placeholder
 */

import { config } from "./config";
import { logger } from "./logger";

export interface MetacognitiveConfig {
	frequencies: number[];
	comprehensionPrompts: string[];
	perspectivePrompts: string[];
	enabled: boolean;
}

const DEFAULT_FREQUENCIES = [5];
const DEFAULT_COMPREHENSION_PROMPTS = [
	"Is there anything in this response that you do not fully understand? If yes, try asking a follow-up question.",
];
const DEFAULT_PERSPECTIVE_PROMPTS = [
	"Want to know what {{personaName}} thinks about this?",
	"You've been talking with the same persona for a while. Maybe see what {{personaName}} would say?",
];

function parseFrequencies(value: string | undefined): number[] {
	if (!value || value.trim() === "") {
		return DEFAULT_FREQUENCIES;
	}

	try {
		const parsed = value
			.split(",")
			.map((s) => parseInt(s.trim(), 10))
			.filter((n) => !isNaN(n) && n > 0);

		if (parsed.length === 0) {
			logger.warn("METACOGNITIVE_FREQUENCIES parsed to empty array, using defaults");
			return DEFAULT_FREQUENCIES;
		}

		return parsed;
	} catch (e) {
		logger.error(e, "Failed to parse METACOGNITIVE_FREQUENCIES");
		return DEFAULT_FREQUENCIES;
	}
}

function parsePrompts(value: string | undefined, defaults: string[]): string[] {
	if (!value || value.trim() === "") {
		return defaults;
	}

	try {
		const parsed = JSON.parse(value);
		if (Array.isArray(parsed) && parsed.length > 0 && parsed.every((p) => typeof p === "string")) {
			return parsed;
		}
		logger.warn("Parsed prompts not a valid string array, using defaults");
		return defaults;
	} catch (e) {
		logger.error(e, "Failed to parse metacognitive prompts JSON");
		return defaults;
	}
}

let cachedConfig: MetacognitiveConfig | null = null;

export function getMetacognitiveConfig(): MetacognitiveConfig {
	if (cachedConfig) {
		return cachedConfig;
	}

	const frequencies = parseFrequencies(config.METACOGNITIVE_FREQUENCIES);
	const comprehensionPrompts = parsePrompts(
		config.METACOGNITIVE_PROMPTS_COMPREHENSION,
		DEFAULT_COMPREHENSION_PROMPTS
	);
	const perspectivePrompts = parsePrompts(
		config.METACOGNITIVE_PROMPTS_PERSPECTIVE,
		DEFAULT_PERSPECTIVE_PROMPTS
	);

	// Feature is enabled if frequencies are configured (even defaults)
	const enabled = frequencies.length > 0;

	cachedConfig = {
		frequencies,
		comprehensionPrompts,
		perspectivePrompts,
		enabled,
	};

	logger.info(
		{
			frequencies,
			comprehensionPromptsCount: comprehensionPrompts.length,
			perspectivePromptsCount: perspectivePrompts.length,
			enabled,
		},
		"Metacognitive config loaded"
	);

	return cachedConfig;
}

/**
 * Select a random frequency from the configured list
 */
export function selectRandomFrequency(): number {
	const { frequencies } = getMetacognitiveConfig();
	return frequencies[Math.floor(Math.random() * frequencies.length)];
}

/**
 * Select a random comprehension prompt
 */
export function selectComprehensionPrompt(): string {
	const { comprehensionPrompts } = getMetacognitiveConfig();
	return comprehensionPrompts[Math.floor(Math.random() * comprehensionPrompts.length)];
}

/**
 * Select a random perspective prompt and substitute the persona name
 */
export function selectPerspectivePrompt(personaName: string): string {
	const { perspectivePrompts } = getMetacognitiveConfig();
	const template = perspectivePrompts[Math.floor(Math.random() * perspectivePrompts.length)];
	return template.replace(/\{\{personaName\}\}/g, personaName);
}