UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

90 lines • 3.79 kB
import { fillTemplate, readPath } from './phrasing.js'; function isRecord(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } function toText(value) { if (value === null || value === undefined) return '—'; if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return String(value); } if (Array.isArray(value)) return value.map(toText).join(', '); return '—'; } /** * A view for an output whose tool declared none, from its shape: an array of flat records is a * table, an array of strings a log, a flat record a set of readings. `undefined` when nothing fits — * a serialized payload is what a person-facing surface exists to avoid, so failing to infer must not * fall back to one. */ export function inferResultView(output) { if (!isRecord(output)) return undefined; for (const [key, value] of Object.entries(output)) { if (!Array.isArray(value) || value.length === 0) continue; if (value.every((entry) => typeof entry === 'string')) { return { kind: 'log', lines: key }; } if (value.every(isRecord)) { const first = value[0]; return { kind: 'table', rows: key, columns: Object.keys(first) .filter((column) => !isRecord(first[column])) .map((column) => ({ path: column, label: column })), }; } } const fields = Object.entries(output) .filter(([, value]) => ['string', 'number', 'boolean'].includes(typeof value)) .map(([key]) => ({ path: key, label: key })); return fields.length > 0 ? { kind: 'metrics', fields } : undefined; } /** * Read `output` through `view` (or one inferred from its shape when `view` is omitted and `infer` is * on). `null` when there is nothing to draw: an `elsewhere` view, an empty reading set, a missing * array. A table whose rows array is present but empty resolves with no rows and its `empty` line. */ export function resolveResultView(output, view, options = {}) { const resolved = view ?? (options.infer === true ? inferResultView(output) : undefined); if (resolved === undefined || resolved.kind === 'elsewhere') return null; switch (resolved.kind) { case 'note': { const text = fillTemplate(resolved.text, output); return text === '' ? null : { kind: 'note', text }; } case 'metrics': { const readings = resolved.fields .map((field) => ({ field, value: readPath(output, field.path) })) .filter((entry) => entry.value !== undefined && entry.value !== null) .map(({ field, value }) => ({ label: field.label, value: toText(value), unit: field.unit ?? null, })); return readings.length === 0 ? null : { kind: 'metrics', readings }; } case 'log': { const lines = readPath(output, resolved.lines); if (!Array.isArray(lines) || lines.length === 0) return null; return { kind: 'log', lines: lines.map(toText) }; } case 'table': { const rows = readPath(output, resolved.rows); if (!Array.isArray(rows)) return null; return { kind: 'table', columns: resolved.columns, rows: rows.map((row) => resolved.columns.map((column) => toText(readPath(row, column.path)))), empty: rows.length === 0 ? (resolved.empty ?? null) : null, }; } } } //# sourceMappingURL=result-view.js.map