Ctrl K
ComunidadGuías…

profile-language.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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(' ');
}