UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

161 lines • 7.21 kB
"use strict"; /** * locales — Message Catalog Pattern. * * The Block D piece. agentfootprint emits user-facing prose at two * audience levels: * * - **Commentary** — third-person prose for the bottom panel of any * viewer (Lens, CLI tail, log files). "The agent dispatched the * refund tool, which returned successfully." * - **Thinking** — first-person status for chat-bubble UIs. * "Looking up your order…" * * v2.4 shipped these as `defaultCommentaryTemplates` and * `defaultStatusTemplates` (flat `Record<string, string>` maps with * `{{var}}` substitution). The names worked but the framing was * generic — "templates" collides with TypeScript / templating-engine * terminology, and there was no first-class place to ship locale * packs. * * **Block D formalizes this as the Message Catalog Pattern:** * * - `defaultCommentaryMessages` / `defaultThinkingMessages` — * canonical English bundles. Aliases of the v2.4 names; symbol * identity preserved (`defaultCommentaryMessages === * defaultCommentaryTemplates`). * - `composeMessages(defaults, overrides)` — spread overrides on * top of defaults; missing keys fall back to the default bundle. * - `validateMessages(catalog, requiredKeys)` — assert every * required key is present (and non-empty). Catches drift between * a consumer's locale pack and the framework's required key set. * * The natural consumer pattern is to ship locale packs alongside the * agent code: * * import { defaultCommentaryMessages, composeMessages } from 'agentfootprint/observe'; * import { esCommentaryMessages } from './locales/es.js'; * * const merged = composeMessages(defaultCommentaryMessages, esCommentaryMessages); * * const agent = Agent.create({...}) * .commentaryTemplates(merged) * .build(); * * Pattern: i18n locale resolution (Resource Bundle, Fowler 2002) + * plain object merge for overrides. No catalog inheritance * chain — overrides win OR fall back to defaults. * * @example Locale pack drop-in * const esThinking = composeMessages(defaultThinkingMessages, { * idle: '{{appName}} está pensando…', * tool: 'Trabajando en `{{toolName}}`…', * }); * const agent = Agent.create({...}).thinkingTemplates(esThinking).build(); * * @example Validate a locale pack against the framework's required keys * import { defaultCommentaryMessages, composeMessages, validateMessages } from 'agentfootprint/observe'; * * const myCatalog = composeMessages(defaultCommentaryMessages, customOverrides); * validateMessages(myCatalog, Object.keys(defaultCommentaryMessages)); * // throws on first missing OR empty key — fail-fast at boot * * Not an import path of its own since 9.0.0. This is the implementation barrel * behind `agentfootprint/observe`, which re-exports every name here — same * symbols, one door. Import from the door. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.validateMessages = exports.composeMessages = exports.defaultTimeAskMessages = exports.defaultStatusTemplates = exports.defaultThinkingMessages = exports.defaultCommentaryMessages = void 0; const commentaryTemplates_js_1 = require("../recorders/observability/commentary/commentaryTemplates.js"); const statusTemplates_js_1 = require("../recorders/observability/status/statusTemplates.js"); Object.defineProperty(exports, "defaultStatusTemplates", { enumerable: true, get: function () { return statusTemplates_js_1.defaultStatusTemplates; } }); /** * Canonical English commentary bundle. Alias of v2.4's * `defaultCommentaryTemplates` — same symbol, friendlier framing. * * Keys mirror agentfootprint event types; values may contain * `{{var}}` placeholders for runtime substitution. */ exports.defaultCommentaryMessages = commentaryTemplates_js_1.defaultCommentaryTemplates; /** * Canonical English thinking bundle. Alias of v2.4's * `defaultStatusTemplates`. * * Keys mirror agentfootprint event types; values may contain * `{{var}}` placeholders for runtime substitution. */ exports.defaultThinkingMessages = statusTemplates_js_1.defaultStatusTemplates; /** * The time ask's sentences (the time layer, step T4) — a refused time * answer's reason, the ask's questions, the label on a reading to confirm. * Override keys through `.time({ messages })`. */ var timeAsk_js_1 = require("./timeAsk.js"); Object.defineProperty(exports, "defaultTimeAskMessages", { enumerable: true, get: function () { return timeAsk_js_1.defaultTimeAskMessages; } }); /** * Spread `overrides` on top of `defaults` so every key in `defaults` * has a value (the override or the original). The result is a fresh * object — neither input is mutated. * * Missing override keys fall back to the default; extra override * keys are preserved (forward-compat for consumer-defined keys). * * @example * const merged = composeMessages(defaultCommentaryMessages, { * 'stream.llm_start.iter1': 'My custom thinking line', * }); */ function composeMessages(defaults, overrides = {}) { return Object.freeze({ ...defaults, ...overrides }); } exports.composeMessages = composeMessages; /** * Assert that every key in `requiredKeys` is present in `catalog`. * Throws an Error listing every missing key — batched so consumers * fix all at once instead of error-by-error. * * Useful at boot to catch drift between a consumer's locale pack and * the framework's required key set. * * Empty-string values are VALID by default — the framework's default * catalogs use `''` to signal "render nothing for this event." * Pass `{ forbidEmpty: true }` to also reject empty values. * * @param catalog The (composed) message catalog to validate. * @param requiredKeys The keys consumers must define. Typically * `Object.keys(defaultCommentaryMessages)` or * `Object.keys(defaultThinkingMessages)`. * @param opts Optional `{ label, forbidEmpty }` (or a bare * string label for back-compat with simple use). * * @throws Error when any required key is missing (or empty under * `forbidEmpty`). */ function validateMessages(catalog, requiredKeys, opts = {}) { const resolved = typeof opts === 'string' ? { label: opts } : opts; const label = resolved.label ?? 'message catalog'; const forbidEmpty = resolved.forbidEmpty ?? false; const missing = []; const empty = []; for (const key of requiredKeys) { const value = catalog[key]; if (value === undefined) { missing.push(key); } else if (forbidEmpty && value.length === 0) { empty.push(key); } } if (missing.length === 0 && empty.length === 0) return; const parts = []; if (missing.length > 0) { parts.push(`missing keys: ${missing.join(', ')}`); } if (empty.length > 0) { parts.push(`empty values: ${empty.join(', ')}`); } throw new Error(`validateMessages(${label}): ${parts.join('; ')}.`); } exports.validateMessages = validateMessages; //# sourceMappingURL=index.js.map