profile-language.mjs
Rama main · réplica de lectura del repositorio original.
import { loadYaml } from './lib/yaml-document.mjs';
const DEFAULT_OUTPUT_LANGUAGE = 'en';
function normalizeOutputLanguage(value) {
if (typeof value !== 'string') return DEFAULT_OUTPUT_LANGUAGE;
const language = value.trim();
if (!language || language.length > 64 || /[\r\n\0]/.test(language)) {
return DEFAULT_OUTPUT_LANGUAGE;
}
return language;
}
/**
* language.output, plus WHY that is the answer.
*
* The catch below folds three different situations into `en`: no profile, no
* language key, and a profile that does not parse. The first two are correct —
* English is the documented default. The third is not something the caller
* should be unable to distinguish: a user who set `output: ja` and has a YAML
* typo elsewhere in the file gets every report, cover letter and outreach
* message in English, and the only signal is noticing the wrong language in
* finished work.
*
* `source` makes that inspectable without changing what any existing caller
* receives. `doctor.mjs` is the primary signal now (checkProfileShape reports
* an unparseable profile on the first message of every session); this is for a
* caller that wants to say so at generation time.
*
* @param {string} profileYaml
* @returns {{language: string, source: 'configured'|'default'|'unparseable'}}
*/
export function describeOutputLanguage(profileYaml) {
let profile;
try {
profile = loadYaml(String(profileYaml ?? '')) || {};
} catch {
return { language: DEFAULT_OUTPUT_LANGUAGE, source: 'unparseable' };
}
const raw = profile?.language?.output;
const language = normalizeOutputLanguage(raw);
// 'configured' only when the file actually asked for what it got — a value
// that normalizes away (too long, embedded newline) is a default, not a
// setting the user made.
const configured = typeof raw === 'string' && raw.trim() === language;
return { language, source: configured ? 'configured' : 'default' };
}
/**
* Parse language.output from profile YAML, falling back to English.
*
* Contract unchanged — returns the language string. Use describeOutputLanguage
* when the reason matters.
*/
export function parseOutputLanguage(profileYaml) {
return describeOutputLanguage(profileYaml).language;
}
/** Build the canonical output-language rule injected into every model prompt. */
export function outputLanguageInstruction(language) {
const outputLanguage = normalizeOutputLanguage(language);
return [
`Write all human-facing output in ${outputLanguage}, including the full A–G`,
`evaluation and the machine-readable summary's free-text fields, regardless`,
`of the language of these instructions or the job description. Keep`,
`market-specific terms when relevant, but explain them in ${outputLanguage}`,
`when needed. The configured language.output always wins over the job`,
`description's language.`,
].join(' ');
}