UNPKG

@botpress/adk-cli

Version:

Command-line interface for the Botpress Agent Development Kit (ADK)

846 lines (844 loc) 28.2 kB
// @bun import { Tool } from "./chunk-knvm2anf.js"; import { require_lib1 as require_lib, require_lib2, require_lib3, require_lib6 as require_lib4 } from "./chunk-6771vrjp.js"; import { formatTypings, getTypings } from "./chunk-50hzjdck.js"; import { CodeFormattingError } from "./chunk-nn2jb0x0.js"; import { truncateWrappedContent, wrapContent } from "./chunk-kkk13rcb.js"; import { escapeString, getMultilineComment, isValidIdentifier, toValidFunctionName, toValidObjectName } from "./chunk-na956zz3.js"; import { Component } from "./chunk-f4bw8q7c.js"; import { cloneDeep_default, exports_exports, upperFirst_default } from "./chunk-54qt5g7m.js"; import { __require, __toESM } from "./chunk-dhs2bg35.js"; // ../../node_modules/.bun/llmz@0.0.79+b49d396f5ed96e7f/node_modules/llmz/dist/index.js var import_generator = __toESM(require_lib2(), 1); var import_parser = __toESM(require_lib3(), 1); var import_traverse = __toESM(require_lib4(), 1); var t = __toESM(require_lib(), 1); var version = "0.0.79"; var traverse = import_traverse.default; function getTypingsWithoutComments(type) { const typeClone = cloneDeep_default(type); removeBabelComments(typeClone); return new import_generator.CodeGenerator(typeClone, { comments: false }).generate().code; } function removeBabelComments(node) { node.leadingComments = null; node.trailingComments = null; node.innerComments = null; Object.keys(node).forEach((key) => { const val = node[key]; if (Array.isArray(val)) { val.forEach((child) => child && typeof child === "object" && removeBabelComments(child)); } else if (val && typeof val === "object" && val.type) { removeBabelComments(val); } }); } function extractAndHoistTypes(ast) { const typeMap = /* @__PURE__ */ new Map; const typeCounts = /* @__PURE__ */ new Map; const hoistedTypes = []; function addTypeToMap(typeNode) { const typeString = getTypingsWithoutComments(typeNode.typeAnnotation); if (!typeMap.has(typeString)) { typeMap.set(typeString, typeNode); } } function generateUniqueTypeName(baseName) { let typeName = baseName; let counter = 1; while ([...typeMap.values()].some((typeNode) => typeNode.id.name === typeName)) { typeName = `${baseName}${counter++}`; } return typeName; } function createTypeAlias(name, type) { return t.tsTypeAliasDeclaration(t.identifier(name), null, type); } function getTypePaths(path) { var _a, _b, _c; let currPath = path; const parts = /* @__PURE__ */ new Set; while (currPath) { const { node, parentPath } = currPath; if (t.isIdentifier(node) && node.name) { parts.add(node.name); } if (t.isTSMethodSignature(node) && currPath.key === "parameters") { parts.add("Input"); } if (currPath.key === "returnType") { parts.add("Output"); const methodName = "id" in parentPath.node && "name" in parentPath.node.id && ((_b = (_a = parentPath == null ? undefined : parentPath.node) == null ? undefined : _a.id) == null ? undefined : _b.name); if (methodName) { parts.add(methodName); } } if (((_c = node == null ? undefined : node.key) == null ? undefined : _c.type) === "Identifier") { parts.add(node.key.name); } if (t.isTSParameterProperty(node) || t.isTSFunctionType(node)) { parts.add("Input"); } if (t.isTSFunctionType(node)) { parts.add("Output"); } currPath = parentPath; } return parts.size ? Array.from(parts).reverse().map(upperFirst_default) : ["UnnamedType"]; } function generateTypeName(path) { return getTypePaths(path).join(""); } function findNestedTypes(path) { const node = path.node; if (t.isTSTypeLiteral(node)) { const typeString = getTypingsWithoutComments(node); typeCounts.set(typeString, (typeCounts.get(typeString) || 0) + 1); if (typeMap.has(typeString) && (typeCounts.get(typeString) || 0) > 1) { path.replaceWith(t.tsTypeReference(typeMap.get(typeString).id)); } else if (!typeMap.has(typeString) && (typeCounts.get(typeString) || 0) > 1) { const typeName = generateUniqueTypeName(generateTypeName(path)); const typeAlias = createTypeAlias(typeName, node); addTypeToMap(typeAlias); path.replaceWith(t.tsTypeReference(t.identifier(typeName))); } const members = path.get("members"); const memberPaths = Array.isArray(members) ? members : [members]; memberPaths.forEach((memberPath) => { findNestedTypes(memberPath); }); } if (t.isTSPropertySignature(node) && path.get("typeAnnotation")) { const annPath = path.get("typeAnnotation.typeAnnotation"); if (annPath == null ? undefined : annPath.node) { findNestedTypes(annPath); } } if (t.isTSArrayType(node)) { findNestedTypes(path.get("elementType")); } if (t.isTSUnionType(node) || t.isTSIntersectionType(node)) { path.get("types").forEach((p) => findNestedTypes(p)); } if (t.isTSTypeReference(node) && node.typeParameters) { path.get("typeParameters.params").forEach((param) => findNestedTypes(param)); } if (t.isTSFunctionType(node)) { const returnPath = path.get("typeAnnotation"); if (returnPath == null ? undefined : returnPath.node) findNestedTypes(returnPath); const params = path.get("parameters"); params.forEach((paramPath) => { const ta = paramPath.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); } if (t.isTSMethodSignature(node)) { const returnPath = path.get("typeAnnotation"); if (returnPath == null ? undefined : returnPath.node) { findNestedTypes(returnPath); } const params = path.get("parameters"); params.forEach((paramPath) => { const ta = paramPath.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); } if (t.isTSDeclareFunction(node)) { const params = path.get("params"); params.forEach((p) => { const ta = p.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); const returnType = path.get("returnType.typeAnnotation"); if (returnType == null ? undefined : returnType.node) findNestedTypes(returnType); } } traverse(ast, { TSTypeAliasDeclaration(path) { const typeString = getTypingsWithoutComments(path.node.typeAnnotation); typeCounts.set(typeString, (typeCounts.get(typeString) || 0) + 1); if (typeMap.has(typeString) && (typeCounts.get(typeString) || 0) > 1) { const existing = typeMap.get(typeString); path.replaceWith(t.tsTypeAliasDeclaration(path.node.id, null, t.tsTypeReference(t.identifier(existing.id.name)))); } else { addTypeToMap(path.node); } }, TSPropertySignature(path) { const annPath = path.get("typeAnnotation.typeAnnotation"); if (annPath == null ? undefined : annPath.node) findNestedTypes(annPath); }, TSFunctionType(path) { const returnPath = path.get("typeAnnotation"); if (returnPath.node) findNestedTypes(returnPath); const params = path.get("parameters"); params.forEach((param) => { const ta = param.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); }, TSMethodSignature(path) { const returnPath = path.get("typeAnnotation.typeAnnotation"); if (returnPath == null ? undefined : returnPath.node) { findNestedTypes(returnPath); } const params = path.get("parameters"); params.forEach((param) => { const ta = param.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); }, TSDeclareFunction(path) { const params = path.get("params"); params.forEach((p) => { const ta = p.get("typeAnnotation.typeAnnotation"); if (ta == null ? undefined : ta.node) findNestedTypes(ta); }); const returnPath = path.get("returnType.typeAnnotation"); if (returnPath == null ? undefined : returnPath.node) findNestedTypes(returnPath); } }); typeMap.forEach((typeNode, typeString) => { if ((typeCounts.get(typeString) || 0) > 1) { if (!hoistedTypes.some((ht) => { return getTypingsWithoutComments(ht.typeAnnotation) === getTypingsWithoutComments(typeNode.typeAnnotation); })) { hoistedTypes.push(typeNode); } } }); ast.program.body = [ ...hoistedTypes, ...ast.program.body.filter((node) => !hoistedTypes.some((ht) => t.isTSTypeAliasDeclaration(node) && node.id.name === ht.id.name)) ]; return ast; } async function hoistTypings(code, formatOptions) { formatOptions ??= {}; formatOptions.throwOnError ??= true; for (let i = 1;i <= 5; i++) { try { const initialCode = code; const ast = import_parser.parse(code, { sourceType: "module", plugins: ["typescript"] }); const transformedAst = extractAndHoistTypes(ast); code = new import_generator.CodeGenerator(transformedAst, { compact: false }).generate().code; if (initialCode === code) { break; } } catch (err) { console.error(err); if (formatOptions.throwOnError) { throw new CodeFormattingError(err instanceof Error ? err.message : String(err ?? "Unknown Error"), code); } break; } } return formatTypings(code, formatOptions); } var LARGE_OBJECT_LINES_OF_CODE = 10; var ObjectInstance = class { name; description; properties; tools; metadata; constructor(props) { var _a; if (!isValidIdentifier(props.name)) { throw new Error(`Invalid name for tool ${props.name}. A tool name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`); } if (props.description !== undefined && typeof props.description !== "string") { throw new Error(`Invalid description for tool ${props.name}. Expected a string, but got type "${typeof props.description}"`); } if (props.metadata !== undefined && typeof props.metadata !== "object") { throw new Error(`Invalid metadata for tool ${props.name}. Expected an object, but got type "${typeof props.metadata}"`); } if (props.properties !== undefined && !Array.isArray(props.properties)) { throw new Error(`Invalid properties for tool ${props.name}. Expected an array, but got type "${typeof props.properties}"`); } if (props.tools !== undefined && !Array.isArray(props.tools)) { throw new Error(`Invalid tools for tool ${props.name}. Expected an array, but got type "${typeof props.tools}"`); } if ((_a = props.properties) == null ? undefined : _a.length) { if (props.properties.length > 100) { throw new Error(`Too many properties for tool ${props.name}. Expected at most 100 properties, but got ${props.properties.length}`); } for (const prop of props.properties) { if (props.properties.filter((p) => p.name === prop.name).length > 1) { throw new Error(`Duplicate property name "${prop.name}" in tool ${props.name}`); } if (!isValidIdentifier(prop.name)) { throw new Error(`Invalid name for property ${prop.name}. A property name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`); } if (prop.description !== undefined && typeof prop.description !== "string") { throw new Error(`Invalid description for property ${prop.name}. Expected a string, but got type "${typeof prop.description}"`); } if (props.description && props.description.length >= 5000) { throw new Error(`Description for property ${prop.name} is too long. Expected at most 5000 characters, but got ${props.description.length}`); } if (typeof prop.writable !== "boolean") { prop.writable = false; } } } this.name = props.name; this.description = props.description; this.metadata = props.metadata ?? {}; this.properties = props.properties; this.tools = Tool.withUniqueNames(props.tools ?? []); } async getTypings() { return getObjectTypings(this).withProperties().withTools().build(); } toJSON() { return { name: this.name, description: this.description, properties: this.properties, tools: (this.tools ?? []).map((tool) => tool.toJSON()), metadata: this.metadata }; } }; function getObjectTypings(obj) { let includeProperties = false; let includeTools = false; let hoisting = false; const typings = []; const addProperties = async () => { var _a; if (includeProperties && ((_a = obj.properties) == null ? undefined : _a.length)) { typings.push(""); typings.push("// ---------------- //"); typings.push("// Properties //"); typings.push("// ---------------- //"); typings.push(""); for (const prop of obj.properties ?? []) { const description = prop.description ?? ""; if (description == null ? undefined : description.trim().length) { typings.push(getMultilineComment(description)); } let type = "unknown"; if (prop.type) { type = await getTypings(prop.type, {}); } else if (prop.value !== undefined) { type = typeof prop.value; } type = prop.writable ? `Writable<${type}>` : `Readonly<${type}>`; const value = embedPropertyValue(prop); typings.push(`const ${prop.name}: ${type} = ${value}`); } } }; const addTools = async () => { var _a; if (includeTools && ((_a = obj.tools) == null ? undefined : _a.length)) { typings.push(""); typings.push("// ---------------- //"); typings.push("// Tools //"); typings.push("// ---------------- //"); typings.push(""); for (const tool of obj.tools) { const fnType = exports_exports.function(tool.zInput, tool.zOutput).title(tool.name).describe(tool.description ?? ""); let temp = await getTypings(fnType, { declaration: true }); temp = temp.replace("declare function ", "function "); typings.push(temp); } } }; const finalize = async () => { var _a; let closingBracket = ""; if (typings.length >= LARGE_OBJECT_LINES_OF_CODE) { closingBracket = ` // end namespace "${obj.name}"`; } let body = typings.join(` `); if (hoisting) { body = await hoistTypings(body, { throwOnError: false }); } typings.push("}" + closingBracket); let header = ""; if ((_a = obj.description) == null ? undefined : _a.trim().length) { header = getMultilineComment(obj.description); } return formatTypings(`${header} export namespace ${obj.name} { ${body} } ${closingBracket}`.trim(), { throwOnError: false }); }; const api = { withProperties: () => { includeProperties = true; return api; }, withTools: () => { includeTools = true; return api; }, withHoisting: () => { hoisting = true; return api; }, async build() { await addProperties(); await addTools(); return finalize(); } }; return api; } function embedPropertyValue(property) { if (typeof property.value === "string") { return escapeString(property.value); } if (Number.isNaN(property.value)) { return "NaN"; } if (typeof property.value === "number" && Number.isInteger(property.value)) { return property.value.toString(); } if (typeof property.value === "boolean") { return property.value.toString(); } if (Array.isArray(property.value) || typeof property.value === "object") { return JSON.stringify(property.value); } if (property.value instanceof Date) { return `new Date('${property.value.toISOString()}')`; } if (property.value instanceof RegExp) { return `new RegExp(${escapeString(property.value.source)}, ${escapeString(property.value.flags)})`; } if (property.value === null) { return "null"; } if (property.value === undefined) { return "undefined"; } if (typeof property.value === "function") { return "function() {}"; } if (typeof property.value === "symbol") { return "Symbol()"; } if (typeof property.value === "bigint") { return `${property.value}n`; } if (property.value instanceof Error) { return `Error(${escapeString(property.value.message)})`; } if (property.value instanceof Map) { return `new Map(${JSON.stringify(Array.from(property.value.entries()))})`; } if (property.value instanceof Set) { return `new Set(${JSON.stringify(Array.from(property.value.values()))})`; } return "unknown"; } var RARE_SYMBOLS = { ARROW_UP: "\u2191", CIRCLE_BULLET: "\u30FB", STAR_BULLET_FULL: "\u2605", STAR_BULLET_EMPTY: "\u2606", ARROW_BULLET: "\u2192", SQUARE_BULLET: "\u25A0", TRIANGLE_BULLET: "\u25BA", OPENING_TAG: "\u3010", CLOSING_TAG: "\u3011", SS: "\xA7", CROSS: "\u2020" }; var CitationsManager = class { _citations = /* @__PURE__ */ new Map; _nextId = 0; registerSource(source) { const id = this._nextId++; const tag = `${RARE_SYMBOLS.OPENING_TAG}${id}${RARE_SYMBOLS.CLOSING_TAG}`; const citation = { id, source, tag }; this._citations.set(id, citation); return citation; } extractCitations(content, replace) { const citations = []; const notFoundCitation = { id: -1, source: "Not Found", tag: "" }; const regex = new RegExp(`${RARE_SYMBOLS.OPENING_TAG}([\\d|\\w|\\s|,]{0,})${RARE_SYMBOLS.CLOSING_TAG}`, "ig"); let match; const offsets = []; while ((match = regex.exec(content)) !== null) { const offset = match.index; const length = match[0].length; offsets.push({ start: offset, length }); const multi = (match[1] ?? "").split(/\D/g).map((s) => s.trim()).filter(Boolean).map((s) => parseInt(s, 10)).filter((s) => !isNaN(s) && s >= 0); for (const citationId of multi) { const citation = this._citations.get(citationId); if (citation) { citations.push({ ...citation, offset }); } else { citations.push({ ...notFoundCitation, offset }); } } } const entries = offsets.map((o) => ({ start: o.start, length: o.length, citations: citations.filter((x) => x.offset === o.start && x.id !== -1) })).sort((a, b) => a.start - b.start); let result = ""; let cursor = 0; for (const { start, length, citations: citations2 } of entries) { result += content.slice(cursor, start); const replacement = citations2.map((citation) => replace ? replace(citation) : "").join(""); result += replacement; cursor = start + length; } result += content.slice(cursor); return { cleaned: result, citations }; } static stripCitationTags(content) { const regex = new RegExp(`${RARE_SYMBOLS.OPENING_TAG}([\\d|\\w|\\s|,]{0,})${RARE_SYMBOLS.CLOSING_TAG}?`, "g"); return content.replace(regex, ""); } removeCitationsFromObject(obj) { const result = []; const processObject = (current, path) => { if (typeof current === "string") { const extraction = this.extractCitations(current); if (extraction.citations.length > 0) { result.push(...extraction.citations.map((citation) => ({ path, citation }))); } return extraction.cleaned; } else if (typeof current === "object" && current !== null) { const newObject = Array.isArray(current) ? [] : {}; for (const key of Object.keys(current)) { newObject[key] = processObject(current[key], `${path}.${key}`); } return newObject; } return current; }; const newObj = processObject(obj, "root"); return [newObj, result]; } reAddCitations(cleaned, citations) { let content = cleaned; citations.sort((a, b) => (a.offset ?? 0) - (b.offset ?? 0)); const adjustment = 0; for (const citation of citations) { if (citation.offset != null) { const position = citation.offset + adjustment; content = content.slice(0, position) + citation.tag + content.slice(position); } } return content; } }; var Button = new Component({ type: "leaf", description: "A button component that can perform actions when clicked", name: "Button", aliases: ["btn"], examples: [ { name: "Say action", description: "A button that triggers a say action", code: `yield <Message> <Button action="say" label="Hello" /> </Message>` }, { name: "Postback action", description: "A button that sends a postback value", code: `yield <Message> Choose an option: <Button action="postback" label="Buy" value="buy_product" /> <Button action="postback" label="Buy" value="buy_product2" /> </Message>` } ], leaf: { props: exports_exports.object({ action: exports_exports.enum(["say", "url", "postback"]).default("say").describe('The action to perform when the button is clicked. Can be "say", "url", or "postback"'), label: exports_exports.string().describe("The text displayed on the button (min 1 character, max 250 characters)"), value: exports_exports.string().optional().describe('The postback value to send when the button is clicked. Required if action is "postback"'), url: exports_exports.string().optional().describe('The URL to open when the button is clicked. Required if action is "url"') }) } }); var Image = new Component({ type: "leaf", name: "Image", description: "Displays an image from a URL.", aliases: [], examples: [ { name: "Basic image", description: "A simple image with alt text", code: `yield <Message> An example image: <Image url="https://example.com/photo.jpg" alt="Example image" /> </Message>` } ], leaf: { props: exports_exports.object({ url: exports_exports.string().describe("The URL of the image (must be valid)"), alt: exports_exports.string().optional().describe("Alternative text describing the image") }) } }); var File = new Component({ type: "leaf", name: "File", description: "Sends a downloadable file to the user.", aliases: [], examples: [ { name: "PDF download", description: "Send a PDF file with a name", code: `yield <Message> Here is your report: <File url="https://example.com/report.pdf" name="Report.pdf" /> </Message>` } ], leaf: { props: exports_exports.object({ url: exports_exports.string().describe("The URL of the file (must be valid)"), name: exports_exports.string().optional().describe("The display name of the file") }) } }); var Video = new Component({ type: "leaf", name: "Video", description: "Embeds a video from a URL.", aliases: [], examples: [ { name: "Intro video", description: "A video with a title", code: `yield <Message> Watch this video: <Video url="https://example.com/intro.mp4" title="Welcome" /> </Message>` } ], leaf: { props: exports_exports.object({ url: exports_exports.string().describe("The URL of the video (must be valid)"), title: exports_exports.string().optional().describe("Title for the video") }) } }); var Audio = new Component({ type: "leaf", name: "Audio", description: "Plays an audio clip from a URL.", aliases: [], examples: [ { name: "Sample audio", description: "Play a short audio clip with a title", code: `yield <Message> Listen to this audio: <Audio url="https://example.com/audio.mp3" title="Sample" /> </Message>` } ], leaf: { props: exports_exports.object({ url: exports_exports.string().describe("The URL of the audio clip (must be valid)"), title: exports_exports.string().optional().describe("Title for the audio clip") }) } }); var Card = new Component({ type: "container", name: "Card", description: "A visual card component that can include an image and buttons.", aliases: [], examples: [ { name: "Product card", description: "A card with an image and two buttons", code: `yield <Message> Featured product: <Card title="Product Name" subtitle="Limited offer"> <Image url="https://example.com/product.jpg" alt="Product image" /> <Button action="postback" label="Buy" value="buy_product" /> <Button action="postback" label="Wishlist" value="wishlist" /> </Card> </Message>` } ], container: { props: exports_exports.object({ title: exports_exports.string().min(1).max(250).describe("Title text (1\u2013250 characters)"), subtitle: exports_exports.string().optional().describe("Optional subtitle for the card") }), children: [ { description: "Image (optional, max 1)", component: Image.definition }, { description: "Button (optional, up to 5)", component: Button.definition } ] } }); var Carousel = new Component({ type: "container", name: "Carousel", description: "A virtual container for displaying 1 to 10 Card components as a carousel.", aliases: [], examples: [ { name: "Product carousel", description: "A carousel with multiple cards", code: `yield <Message> Here are some products you might like: <Carousel> <Card title="Item 1" subtitle="First product"> <Image url="https://example.com/item1.jpg" alt="Item 1" /> <Button action="postback" label="Buy" value="buy_1" /> </Card> <Card title="Item 2" subtitle="Second product"> <Image url="https://example.com/item2.jpg" alt="Item 2" /> <Button action="postback" label="Buy" value="buy_2" /> </Card> </Carousel> </Message>` } ], container: { props: exports_exports.object({}), children: [ { description: "Card component (required, 1\u201310 allowed)", component: Card.definition } ] } }); var Text = new Component({ type: "default", name: "Message", aliases: ["Text", "Markdown"], description: "Markdown-formatted text that appears directly inside components like <Message>.", examples: [ { name: "Basic Markdown", description: "Simple markdown content inside a message", code: `yield <Message> **Hello**, welcome to our service! </Message>` } ], default: { props: exports_exports.object({}), children: [] } }); var DefaultComponents = { Button, Image, File, Video, Audio, Card, Carousel, Text }; var Chat = class { handler; transcript; components; constructor(props) { this.handler = props.handler; this.components = props.components; this.transcript = props.transcript || []; } onExecutionDone(_result) {} }; var utils = { toValidObjectName, toValidFunctionName, wrapContent, truncateWrappedContent }; var execute = async (props) => { const { executeContext } = await import("./chunk-40hne28c.js"); return executeContext(props); }; var init = async () => { await import("./chunk-40hne28c.js"); await import("./chunk-z2gn7fdy.js"); await import("./chunk-q5ss8n6y.js"); await import("./chunk-rz1nbz7z.js"); await import("./chunk-g8zs9qpy.js"); await import("./chunk-91d1m8cq.js"); await import("./chunk-v7e14rst.js"); await import("./chunk-482kd79w.js"); await import("./chunk-vhfkjms6.js"); await import("./chunk-sxeq8kjm.js"); }; export { version, ObjectInstance, CitationsManager, DefaultComponents, Chat, utils, execute, init };