UNPKG

@adonis-agora/agent

Version:

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

53 lines • 2.44 kB
const WHITESPACE = /\s/; /** * The trigger token the caret currently sits in, or `null`. Scans backwards from the caret and * stops at the first whitespace, so a token is always one unbroken word: typing a space is what * ends a command and hands the rest of the line back to the user as prose. */ export function findActiveTrigger(text, caret, sources) { const end = Math.max(0, Math.min(caret, text.length)); for (let index = end - 1; index >= 0; index--) { const char = text[index]; if (char === undefined || WHITESPACE.test(char)) { return null; } const source = sources.find((candidate) => candidate.trigger === char); // A trigger that fails its own position rule is just a character in the token — `@ad/x` is one // mention query, not a command — so the scan continues past it rather than giving up. if (source && isAllowedAt(text, index, source.position)) { return { source, index, query: text.slice(index + 1, end) }; } } return null; } function isAllowedAt(text, index, position) { if (index === 0) { return true; } if (position === 'start') { return false; } const previous = text[index - 1]; return previous !== undefined && WHITESPACE.test(previous); } /** Case-insensitive substring over label and description. The default when a source names none. */ export function filterAutocompleteItems(items, query) { // An empty needle is a substring of everything, so it needs no branch of its own. const needle = query.trim().toLowerCase(); return items.filter((item) => item.label.toLowerCase().includes(needle) || (item.description?.toLowerCase().includes(needle) ?? false)); } /** * The text and caret after accepting `item`. The trigger character stays — `/deploy ` is what the * user meant to type — and everything after the caret is left untouched, so completing a token in * the middle of a sentence does not eat the rest of it. */ export function applyCompletion(text, caret, match, item) { const end = Math.max(match.index, Math.min(caret, text.length)); const inserted = `${match.source.trigger}${item.value ?? item.label}${match.source.insertSuffix ?? ' '}`; return { text: text.slice(0, match.index) + inserted + text.slice(end), caret: match.index + inserted.length, }; } //# sourceMappingURL=model.js.map