@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
95 lines • 4.42 kB
JavaScript
/**
* `GET <base>/tools?agent=*`: every tool the actor reaches through ANY agent, each once — for a
* surface that shows several agents' conversations.
*/
export const ALL_AGENTS = '*';
/** Dotted-path read. `undefined` rather than a throw, so a template can outlive a field. */
export function readPresentationPath(value, path) {
return path.split('.').reduce((current, key) => {
if (current === null || typeof current !== 'object')
return undefined;
return current[key];
}, value);
}
function renderPresentationValue(value) {
if (value === null || value === undefined)
return '';
if (typeof value === 'string')
return value;
if (typeof value === 'number' || typeof value === 'boolean')
return String(value);
if (Array.isArray(value))
return value.map(renderPresentationValue).filter(Boolean).join(', ');
return '';
}
/**
* Fill `{dotted.path}` placeholders from `context`. A placeholder with nothing behind it collapses
* along with the whitespace in front of it, so "Reading {key}" degrades to "Reading" rather than
* printing braces at a person; a filled one keeps the whitespace the author wrote ("({n} files)").
* The one filler the server (approval prompts) and the React layer (activity lines) share.
*/
export function fillPresentationTemplate(template, context) {
return template
.replace(/(\s*)\{([\w.]+)\}/g, (_match, space, path) => {
const rendered = renderPresentationValue(readPresentationPath(context, path));
return rendered === '' ? '' : `${space}${rendered}`;
})
.replace(/\s{2,}/g, ' ')
.trim();
}
/**
* A tool's `confirm` templates filled from one call's input — the approval prompt a client shows
* ("Refund order #1002?"), resolved on the server so every transport (native, AG-UI, A2UI, A2A)
* carries the same words, not only a client that has the tool catalog.
*/
export function fillToolConfirmation(confirm, input) {
return {
title: fillPresentationTemplate(confirm.title, input),
verb: fillPresentationTemplate(confirm.verb, input),
...(confirm.detail !== undefined
? { detail: fillPresentationTemplate(confirm.detail, input) }
: {}),
...(confirm.link !== undefined ? { link: confirm.link } : {}),
};
}
/**
* The approve button's words when a tool declared no `confirm.verb`. English, like every other
* library default: a localized surface (a text channel's `texts.approve`) shows its own word
* instead whenever a confirmation carries exactly this one.
*/
export const DEFAULT_CONFIRM_VERB = 'Approve';
/**
* A tool identifier as words a person can read: `refund_order`, `refundOrder` and `refund-order`
* all become "Refund order". For the rare surface that has nothing better — a tool's own
* `presentation.label` (or its `confirm` templates) always wins, see {@link resolveToolConfirmation}.
*/
export function humanizeToolName(name) {
const words = name
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
.replace(/[_\-.:/\s]+/g, ' ')
.trim()
.toLowerCase();
return words.length === 0 ? '' : `${words.charAt(0).toUpperCase()}${words.slice(1)}`;
}
/**
* The approval prompt for one call of `toolName`, as every adapter (native stream, AG-UI, A2UI,
* text channels, OpenCode, A2A) shows it: the tool's `confirm` templates filled from `input` when it
* declared them; otherwise "<label>?" from its `presentation.label`, else "<humanized name>?" with
* {@link DEFAULT_CONFIRM_VERB} — never the raw identifier. The one place that fallback is worded.
*/
export function resolveToolConfirmation(toolName, input, presentation) {
const label = presentation?.label?.trim();
const subject = label !== undefined && label !== '' ? label : humanizeToolName(toolName);
const fallbackTitle = subject === '' ? `${DEFAULT_CONFIRM_VERB}?` : `${subject}?`;
const declared = presentation?.confirm;
if (declared === undefined)
return { title: fallbackTitle, verb: DEFAULT_CONFIRM_VERB };
const filled = fillToolConfirmation(declared, input);
return {
...filled,
title: filled.title === '' ? fallbackTitle : filled.title,
verb: filled.verb === '' ? DEFAULT_CONFIRM_VERB : filled.verb,
};
}
//# sourceMappingURL=tool-presentation.js.map