@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
700 lines (698 loc) • 21.4 kB
JavaScript
// @bun
import {
runAsyncFunction
} from "./chunk-qvn2q0t4.js";
import {
Context,
ErrorExecutionResult,
PartialExecutionResult,
Snapshot,
SuccessExecutionResult,
parseExit,
ulid
} from "./chunk-vay209b5.js";
import {
Uk
} from "./chunk-3xrpxgq4.js";
import {
Cognitive
} from "./chunk-rfm3jr1m.js";
import"./chunk-w346ejn9.js";
import"./chunk-knvm2anf.js";
import"./chunk-65h5trb5.js";
import"./chunk-s2akeqpw.js";
import"./chunk-6771vrjp.js";
import {
require_ms
} from "./chunk-g8mm42v1.js";
import"./chunk-50hzjdck.js";
import {
AssignmentError,
CodeExecutionError,
CognitiveError,
InvalidCodeError,
LoopExceededError,
Signals,
SnapshotSignal,
ThinkSignal,
VMSignal
} from "./chunk-nn2jb0x0.js";
import"./chunk-v8xvth6j.js";
import {
truncateWrappedContent
} from "./chunk-kkk13rcb.js";
import {
cleanStackTrace
} from "./chunk-ytpp1kam.js";
import {
init,
stripInvalidIdentifiers
} from "./chunk-na956zz3.js";
import"./chunk-kb6q8m3w.js";
import"./chunk-0q6b88ns.js";
import"./chunk-f4bw8q7c.js";
import"./chunk-0v8vgrns.js";
import {
clamp_default,
exports_exports,
isEqual_default,
isPlainObject_default,
omit_default
} from "./chunk-54qt5g7m.js";
import {
__toESM
} from "./chunk-dhs2bg35.js";
// ../../node_modules/.bun/llmz@0.0.79+b49d396f5ed96e7f/node_modules/llmz/dist/llmz-F227HVGB.js
var import_ms = __toESM(require_ms(), 1);
function createJoinedAbortController(signals) {
const controller = new AbortController;
const validSignals = signals.filter((signal) => signal != null);
if (validSignals.length === 0) {
return controller;
}
for (const signal of validSignals) {
if (signal.aborted) {
controller.abort(signal.reason);
return controller;
}
}
const abortListeners = [];
for (const signal of validSignals) {
const listener = () => {
controller.abort(signal.reason);
cleanup();
};
signal.addEventListener("abort", listener);
abortListeners.push(() => signal.removeEventListener("abort", listener));
}
const cleanup = () => {
abortListeners.forEach((removeListener) => removeListener());
};
controller.signal.addEventListener("abort", cleanup, { once: true });
return controller;
}
var getErrorMessage = (err) => err instanceof Error ? err.message : JSON.stringify(err);
var SLOW_TOOL_WARNING = import_ms.default("15s");
var RESPONSE_LENGTH_BUFFER = {
MIN_TOKENS: 1000,
MAX_TOKENS: 16000,
PERCENTAGE: 0.1
};
var getModelOutputLimit = (inputLength) => clamp_default(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
var executeContext = async (props) => {
var _a, _b;
await init();
const result = await _executeContext(props);
try {
(_b = (_a = result.context.chat) == null ? undefined : _a.onExecutionDone) == null || _b.call(_a, result);
} catch {}
return result;
};
var _executeContext = async (props) => {
var _a, _b;
const controller = createJoinedAbortController([props.signal]);
const { onIterationStart, onIterationEnd, onTrace, onExit, onBeforeExecution, onAfterTool, onBeforeTool } = props;
const client = props.client ?? new Uk;
const cognitive = Cognitive.isCognitiveClient(client) ? client : new Cognitive({ client, __experimental_beta: true });
const cleanups = [];
const ctx = new Context({
chat: props.chat,
instructions: props.instructions,
objects: props.objects,
tools: props.tools,
loop: (_a = props.options) == null ? undefined : _a.loop,
timeout: (_b = props.options) == null ? undefined : _b.timeout,
exits: props.exits,
snapshot: props.snapshot,
model: props.model,
temperature: props.temperature,
reasoningEffort: props.reasoningEffort
});
try {
while (true) {
if (ctx.iterations.length >= ctx.loop) {
return new ErrorExecutionResult(ctx, new LoopExceededError);
}
const iteration = await ctx.nextIteration();
try {
await executeOnIterationStartHook({
iteration,
ctx,
onIterationStart,
controller,
onIterationEnd
});
} catch (err) {
if (err instanceof ThinkSignal) {
continue;
}
}
if (controller.signal.aborted) {
iteration.end({
type: "aborted",
aborted: {
reason: controller.signal.reason ?? "The operation was aborted"
}
});
return new ErrorExecutionResult(ctx, controller.signal.reason ?? "The operation was aborted");
}
cleanups.push(iteration.traces.onPush((traces) => {
for (const trace of traces) {
onTrace == null || onTrace({ trace, iteration: ctx.iterations.length });
}
}));
try {
await executeIteration({
iteration,
ctx,
cognitive,
controller,
onExit,
onBeforeExecution,
onAfterTool,
onBeforeTool
});
} catch (err) {
if (err instanceof CognitiveError) {
return new ErrorExecutionResult(ctx, err);
}
iteration.end({
type: "execution_error",
execution_error: {
message: "An unexpected error occurred: " + getErrorMessage(err),
stack: cleanStackTrace(err.stack ?? "No stack trace available")
}
});
}
try {
await (onIterationEnd == null ? undefined : onIterationEnd(iteration, controller));
} catch (err) {
console.error(err);
}
if (iteration.status.type === "exit_success") {
const exitName = iteration.status.exit_success.exit_name;
return new SuccessExecutionResult(ctx, {
exit: iteration.exits.find((x) => x.name === exitName),
result: iteration.status.exit_success.return_value
});
}
if (iteration.status.type === "callback_requested") {
return new PartialExecutionResult(ctx, iteration.status.callback_requested.signal, Snapshot.fromSignal(iteration.status.callback_requested.signal));
}
if (iteration.status.type === "thinking_requested" || iteration.status.type === "exit_error" || iteration.status.type === "execution_error" || iteration.status.type === "invalid_code_error") {
continue;
}
return new ErrorExecutionResult(ctx, iteration.error ?? `Unknown error. Status: ${iteration.status.type}`);
}
} catch (error) {
return new ErrorExecutionResult(ctx, error ?? "Unknown error");
} finally {
for (const cleanup of cleanups) {
try {
cleanup();
} catch {}
}
}
};
var executeIteration = async ({
iteration,
ctx,
cognitive,
controller,
onExit,
onBeforeExecution,
onBeforeTool,
onAfterTool
}) => {
var _a, _b, _c, _d;
let startedAt = Date.now();
const traces = iteration.traces;
const modelRef = Array.isArray(iteration.model) ? iteration.model[0] : iteration.model;
const model = await cognitive.getModelDetails(modelRef).catch((thrown) => {
throw new CognitiveError(`Failed to fetch model details for model "${modelRef}": ${getErrorMessage(thrown)}`);
});
const modelLimit = Math.max(model.input.maxTokens, 8000);
const responseLengthBuffer = getModelOutputLimit(modelLimit);
const messages = truncateWrappedContent({
messages: iteration.messages,
tokenLimit: modelLimit - responseLengthBuffer,
throwOnFailure: true
}).filter((x) => typeof x.content !== "string" || x.content.trim().length > 0);
iteration.messages = messages;
traces.push({
type: "llm_call_started",
started_at: startedAt,
ended_at: startedAt,
model: model.ref
});
const output = await cognitive.generateContent({
signal: controller.signal,
systemPrompt: (_a = messages.find((x) => x.role === "system")) == null ? undefined : _a.content,
model: iteration.model,
temperature: iteration.temperature,
responseFormat: "text",
reasoningEffort: iteration.reasoningEffort,
messages: messages.filter((x) => x.role !== "system"),
stopSequences: ctx.version.getStopTokens()
}).catch((thrown) => {
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
});
const out = typeof ((_c = (_b = output.output.choices) == null ? undefined : _b[0]) == null ? undefined : _c.content) === "string" ? output.output.choices[0].content : null;
if (!out) {
throw new CognitiveError("LLM did not return any text output");
}
const assistantResponse = ctx.version.parseAssistantResponse(out);
iteration.code = assistantResponse.code.trim();
if (typeof onBeforeExecution === "function") {
try {
const hookRes = await onBeforeExecution(iteration, controller);
if (typeof (hookRes == null ? undefined : hookRes.code) === "string" && hookRes.code.trim().length > 0) {
iteration.code = hookRes.code.trim();
}
} catch (err) {
if (err instanceof ThinkSignal) {
return iteration.end({
type: "thinking_requested",
thinking_requested: {
variables: err.context,
reason: err.reason
}
});
}
return iteration.end({
type: "execution_error",
execution_error: {
message: `Error in onBeforeExecution hook: ${getErrorMessage(err)}`,
stack: cleanStackTrace(err.stack ?? "No stack trace available")
}
});
}
}
iteration.llm = {
cached: output.meta.cached || false,
ended_at: Date.now(),
started_at: startedAt,
status: "success",
tokens: output.meta.tokens.input + output.meta.tokens.output,
spend: output.meta.cost.input + output.meta.cost.output,
output: assistantResponse.raw,
model: `${output.meta.model.integration}:${output.meta.model.model}`,
usage: output.output.usage
};
traces.push({
type: "llm_call_success",
started_at: startedAt,
ended_at: iteration.llm.ended_at,
model: model.ref,
code: iteration.code
});
const vmContext = { ...stripInvalidIdentifiers(iteration.variables) };
for (const obj of iteration.objects) {
const internalValues = {};
const instance = {};
for (const { name, value, writable, type } of obj.properties ?? []) {
internalValues[name] = value;
const initialValue = value;
const schema = type ?? exports_exports.any();
Object.defineProperty(instance, name, {
enumerable: true,
configurable: true,
get() {
return internalValues[name];
},
set(value2) {
if (isEqual_default(value2, internalValues[name])) {
return;
}
if (!writable) {
throw new AssignmentError(`Property ${obj.name}.${name} is read-only and cannot be modified`);
}
if (value2 === internalValues[name]) {
return;
}
const parsed = schema.safeParse(value2);
if (!parsed.success) {
throw new AssignmentError(`Invalid value for Object property ${obj.name}.${name}: ${getErrorMessage(parsed.error)}`);
}
internalValues[name] = parsed.data;
traces.push({
type: "property",
started_at: Date.now(),
object: obj.name,
property: name,
value: parsed.data
});
iteration.trackMutation({ object: obj.name, property: name, before: initialValue, after: parsed.data });
}
});
}
for (const tool of obj.tools ?? []) {
instance[tool.name] = wrapTool({
chat: ctx.chat,
tool,
traces,
object: obj.name,
iteration,
beforeHook: onBeforeTool,
afterHook: onAfterTool,
controller
});
}
Object.preventExtensions(instance);
Object.seal(instance);
vmContext[obj.name] = instance;
}
for (const tool of iteration.tools) {
const wrapped = wrapTool({
chat: ctx.chat,
tool,
traces,
iteration,
beforeHook: onBeforeTool,
afterHook: onAfterTool,
controller
});
for (const key of [tool.name, ...tool.aliases ?? []]) {
vmContext[key] = wrapped;
}
}
if (controller.signal.aborted) {
traces.push({
type: "abort_signal",
started_at: Date.now(),
reason: "The operation was aborted by user."
});
return iteration.end({
type: "aborted",
aborted: {
reason: controller.signal.reason ?? "The operation was aborted"
}
});
}
startedAt = Date.now();
const result = await runAsyncFunction(vmContext, iteration.code, traces, controller.signal, ctx.timeout).catch((err) => {
return {
success: false,
error: err,
lines_executed: [],
traces: [],
variables: {}
};
});
if (result.error && result.error instanceof InvalidCodeError) {
return iteration.end({
type: "invalid_code_error",
invalid_code_error: {
message: result.error.message
}
});
}
traces.push({
type: "code_execution",
lines_executed: result.lines_executed ?? 0,
started_at: startedAt,
ended_at: Date.now()
});
if (controller.signal.aborted) {
return iteration.end({
type: "aborted",
aborted: {
reason: controller.signal.reason ?? "The operation was aborted"
}
});
}
if (result.error && result.error instanceof CodeExecutionError) {
return iteration.end({
type: "execution_error",
execution_error: {
message: result.error.message,
stack: cleanStackTrace(result.error.stacktrace ?? result.error.stack ?? "No stack trace available")
}
});
}
if (!result.success) {
return iteration.end({
type: "execution_error",
execution_error: {
message: ((_d = result == null ? undefined : result.error) == null ? undefined : _d.message) ?? "Unknown error occurred",
stack: cleanStackTrace(result.error.stack ?? "No stack trace available")
}
});
}
if (result.signal instanceof ThinkSignal) {
return iteration.end({
type: "thinking_requested",
thinking_requested: {
variables: result.signal.context,
reason: result.signal.reason,
metadata: result.signal.metadata
}
});
}
if (result.signal instanceof SnapshotSignal) {
return iteration.end({
type: "callback_requested",
callback_requested: {
signal: result.signal
}
});
}
let returnValue = result.success && result.return_value ? result.return_value : null;
const returnAction = returnValue == null ? undefined : returnValue.action;
if (returnAction === "think") {
const variables = omit_default(returnValue ?? {}, "action");
if (isPlainObject_default(variables) && Object.keys(variables).length > 0) {
return iteration.end({
type: "thinking_requested",
thinking_requested: {
variables,
reason: "Thinking requested"
}
});
}
return iteration.end({
type: "thinking_requested",
thinking_requested: {
reason: "Thinking requested",
variables: iteration.variables
}
});
}
const parsedExit = parseExit(returnValue, iteration.exits);
if (!parsedExit.success) {
return iteration.end({
type: "exit_error",
exit_error: {
exit: (returnValue == null ? undefined : returnValue.action) ?? "n/a",
message: parsedExit.error,
return_value: returnValue
}
});
}
const returnExit = parsedExit.exit;
returnValue = { action: returnExit.name, value: parsedExit.value };
try {
await (onExit == null ? undefined : onExit({
exit: returnExit,
result: returnValue == null ? undefined : returnValue.value
}));
} catch (err) {
return iteration.end({
type: "exit_error",
exit_error: {
exit: returnExit.name,
message: `Error executing exit ${returnExit.name}: ${getErrorMessage(err)}`,
return_value: returnValue
}
});
}
return iteration.end({
type: "exit_success",
exit_success: {
exit_name: returnExit.name,
return_value: returnValue == null ? undefined : returnValue.value
}
});
};
function wrapTool({ chat, tool, traces, object, iteration, beforeHook, afterHook, controller }) {
const getToolInput = (input) => tool.zInput.safeParse(input).data ?? input;
return function(input) {
const toolCallId = `tcall_${ulid()}`;
const alertSlowTool = setTimeout(() => traces.push({
type: "tool_slow",
tool_name: tool.name,
tool_call_id: toolCallId,
started_at: Date.now(),
input: getToolInput(input),
object,
duration: SLOW_TOOL_WARNING
}), SLOW_TOOL_WARNING);
const cancelSlowTool = () => clearTimeout(alertSlowTool);
const toolStart = Date.now();
let output;
let error;
let success = true;
const handleSignals = (error2) => {
if (output === error2) {
return true;
}
if (error2 instanceof SnapshotSignal) {
error2.toolCall = {
name: tool.name,
inputSchema: tool.input,
outputSchema: tool.output,
input
};
error2.message = Signals.serializeError(error2);
}
if (error2 instanceof ThinkSignal) {
traces.push({
type: "think_signal",
started_at: Date.now(),
line: 0,
ended_at: Date.now()
});
success = true;
output = error2;
return true;
}
return false;
};
try {
const withHooks = async (input2) => {
const beforeRes = await (beforeHook == null ? undefined : beforeHook({
iteration,
tool,
input: input2,
controller,
object,
toolCallId
}));
if (typeof (beforeRes == null ? undefined : beforeRes.input) !== "undefined") {
input2 = beforeRes.input;
}
let output2 = await tool.execute(input2, {
callId: toolCallId
}, chat);
const afterRes = await (afterHook == null ? undefined : afterHook({
iteration,
tool,
input: input2,
output: output2,
controller,
object,
toolCallId
}));
if (typeof (afterRes == null ? undefined : afterRes.output) !== "undefined") {
output2 = afterRes.output;
}
return output2;
};
const result = withHooks(input);
if (result instanceof Promise || (result == null ? undefined : result.then) && (result == null ? undefined : result.catch)) {
return result.then((res) => {
output = res;
success = true;
return res;
}).catch(async (err) => {
if (!handleSignals(err)) {
success = false;
error = err;
} else {
const afterRes = await (afterHook == null ? undefined : afterHook({
iteration,
tool,
input,
output,
controller,
object,
toolCallId
}));
if (typeof (afterRes == null ? undefined : afterRes.output) !== "undefined") {
output = afterRes.output;
}
}
throw err;
}).finally(() => {
cancelSlowTool();
traces.push({
type: "tool_call",
tool_call_id: toolCallId,
started_at: toolStart,
ended_at: Date.now(),
tool_name: tool.name,
object,
input: getToolInput(input),
output,
error,
success
});
});
}
success = true;
output = result;
} catch (err) {
if (!handleSignals(err)) {
success = false;
error = err;
}
}
cancelSlowTool();
traces.push({
type: "tool_call",
tool_call_id: toolCallId,
started_at: toolStart,
ended_at: Date.now(),
tool_name: tool.name,
object,
input: getToolInput(input),
output,
error,
success
});
if (!success) {
throw error;
}
if (output instanceof VMSignal) {
throw output;
}
return output;
};
}
var executeOnIterationStartHook = async (props) => {
const { iteration, ctx, onIterationStart, controller, onIterationEnd } = props;
try {
const hookRes = await (onIterationStart == null ? undefined : onIterationStart(iteration, controller, ctx));
if (hookRes) {
Object.assign(iteration, hookRes);
}
} catch (err) {
if (err instanceof ThinkSignal) {
iteration.end({
type: "thinking_requested",
thinking_requested: {
variables: err.context,
reason: err.reason
}
});
try {
await (onIterationEnd == null ? undefined : onIterationEnd(iteration, controller));
} catch (err2) {
console.error(err2);
}
} else {
iteration.end({
type: "execution_error",
execution_error: {
message: `Error in onIterationStart hook: ${getErrorMessage(err)}`,
stack: cleanStackTrace(err.stack ?? "No stack trace available")
}
});
}
throw err;
}
};
export {
executeContext,
_executeContext
};