UNPKG

@adonis-agora/agent

Version:

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

113 lines • 5.58 kB
import { snapshotActionProposal } from './action-proposal-transitions.js'; import { createUiCollector } from './tool-ui.js'; /** The adapter's choice limits a text channel stamped on the turn (`pageContext.channel.choices`). */ export function channelChoiceLimits(pageContext) { const channel = pageContext?.channel; const choices = channel?.choices; return typeof choices === 'object' && choices !== null && typeof choices.buttons === 'number' && typeof choices.lists === 'number' ? { buttons: choices.buttons, lists: choices.lists } : undefined; } /** The {@link ToolUiChannelGuide} of a genui setup with `channels`. */ export function createToolUiChannelGuide(options) { const resolved = async (scope) => { const channels = await import('./genui/channels.js'); const channel = channels.resolveGenuiChannel(options.base ?? {}, options.channels, scope.channel); return { channels, channel }; }; return { async prompt(scope) { const { channels, channel } = await resolved(scope); if (!channel.configured || !channel.messaging) return undefined; return channels.channelPrompt(await options.resolveCatalog(scope), channel); }, async delivered(scope, components, limits) { const { channels, channel } = await resolved(scope); if (!channel.configured || !channel.messaging || components.length === 0) return undefined; return channels.describeChannelComponents(await options.resolveCatalog(scope), components.map((component) => ({ id: component.id, name: component.component, props: component.props, ...(component.version !== undefined ? { version: component.version } : {}), ...(component.componentVersions !== undefined ? { componentVersions: component.componentVersions } : {}), ...(component.partial === true ? { partial: true } : {}), })), channel, limits); }, }; } /** * A tool's output with what its pushes were delivered as on a messaging channel: `{ …output, * delivered }` for an object output, `{ result: output, delivered }` for anything else (or an object * that already has a `delivered` of its own). */ export function withDelivered(output, delivered) { if (typeof output === 'object' && output !== null && !Array.isArray(output) && !Object.hasOwn(output, 'delivered')) { return { ...output, delivered }; } return { result: output === undefined ? null : output, delivered }; } export function createNegotiatedUiCollector(toolCallId, scope, resolveCatalog, writer) { const collector = createUiCollector(toolCallId, writer); const texts = new Map(); let next = 0; return { components: collector.components, text: () => [...texts.values()].join('\n'), restart: () => { next = 0; texts.clear(); collector.restart(); }, emit: async (component, props, options = {}) => { if (!resolveCatalog) { // No server catalog to negotiate against: the client's declaration can only narrow what is // drawn. A component it does not declare degrades to its fallback text, else is left out. const declared = scope.uiCapabilities === undefined || scope.uiCapabilities.components.some((entry) => entry.name === component && entry.version === (options.version ?? 1)); if (declared) return collector.emit(component, props, options); const id = options.id ?? `${toolCallId}:ui:${next++}`; if (options.fallbackText !== undefined && options.fallbackText.length > 0) { texts.set(id, options.fallbackText); await writer?.write({ t: 'text', v: options.fallbackText }); } return { id }; } props = snapshotActionProposal(props); options = { ...options }; const { prepareUiEmission } = await import('./genui/index.js'); const catalog = await resolveCatalog(scope); const prepared = await prepareUiEmission(catalog, scope.uiCapabilities, component, props, options.version); const id = options.id ?? `${toolCallId}:ui:${next++}`; if (prepared.kind === 'text') { texts.set(id, prepared.text); await writer?.write({ t: 'text', v: prepared.text }); return { id }; } const fallbackText = 'fallbackText' in prepared && typeof prepared.fallbackText === 'string' ? prepared.fallbackText : undefined; const versions = 'componentVersions' in prepared ? prepared.componentVersions : undefined; const componentVersions = versions !== null && typeof versions === 'object' && !Array.isArray(versions) ? snapshotActionProposal(versions) : undefined; return collector.emit(prepared.component, prepared.props, { id, version: prepared.version, ...(fallbackText !== undefined ? { fallbackText } : {}), ...(componentVersions !== undefined ? { componentVersions } : {}), }); }, }; } //# sourceMappingURL=negotiated-tool-ui.js.map