jorel
Version:
A unified wrapper for working with LLMs from multiple providers, including streams, images, documents & automatic tool use.
387 lines (386 loc) • 14.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LlmToolKitUtilities = void 0;
/**
* Static utilities for working with individual tool calls
*/
class LlmToolCallUtilities {
/**
* Extract tool calls that require approval
* @param toolCalls - Array of tool calls
* @returns Array of tool calls that require approval
*/
extractRequiringApproval(toolCalls) {
return toolCalls.filter((call) => call.approvalState === "requiresApproval");
}
/**
* Extract tool calls that are pending execution
* @param toolCalls - Array of tool calls
* @returns Array of tool calls that are pending execution
*/
extractPending(toolCalls) {
return toolCalls.filter((call) => call.executionState === "pending");
}
/**
* Extract tool calls that are completed
* @param toolCalls - Array of tool calls
* @returns Array of tool calls that are completed
*/
extractCompleted(toolCalls) {
return toolCalls.filter((call) => call.executionState === "completed");
}
/**
* Extract tool calls that have errors
* @param toolCalls - Array of tool calls
* @returns Array of tool calls that have errors
*/
extractErrored(toolCalls) {
return toolCalls.filter((call) => call.executionState === "error");
}
/**
* Classify tool calls
* @param toolCalls - Array of tool calls
* @returns Classification of the tool calls
*/
classify(toolCalls) {
if (toolCalls.length === 0)
return "completed";
const hasApprovalPending = toolCalls.some((call) => call.approvalState === "requiresApproval");
if (hasApprovalPending)
return "approvalPending";
const hasExecutionPending = toolCalls.some((call) => call.executionState === "pending" || call.executionState === "inProgress");
if (hasExecutionPending)
return "executionPending";
return "completed";
}
/**
* Check if any tool calls require approval
* @param toolCalls - Array of tool calls
* @returns True if any tool calls require approval
*/
hasRequiringApproval(toolCalls) {
return toolCalls.some((call) => call.approvalState === "requiresApproval");
}
/**
* Check if any tool calls are pending
* @param toolCalls - Array of tool calls
* @returns True if any tool calls are pending execution
*/
hasPending(toolCalls) {
return toolCalls.some((call) => call.executionState === "pending" || call.executionState === "inProgress");
}
/**
* Approve tool calls
* @param toolCalls - Array of tool calls
* @param options - Options for the operation
* @returns New array with approved tool calls
*/
approve(toolCalls, options = {}) {
return this.updateApprovalState(toolCalls, "approved", options);
}
/**
* Reject tool calls
* @param toolCalls - Array of tool calls
* @param options - Options for the operation
* @returns New array with rejected tool calls
*/
reject(toolCalls, options = {}) {
return this.updateApprovalState(toolCalls, "rejected", options);
}
/**
* Cancel tool calls
* @param toolCalls - Array of tool calls
* @param options - Options for the operation
* @returns New array with cancelled tool calls
*/
cancel(toolCalls, options = {}) {
const targetIds = this.normalizeToolCallIds(options.toolCallIds);
return toolCalls.map((call) => {
if ((call.executionState === "pending" || call.executionState === "inProgress") &&
(!targetIds || targetIds.includes(call.id))) {
return {
...call,
executionState: "cancelled",
result: null,
error: {
message: "Tool call was cancelled",
type: "ToolCancellation",
numberOfAttempts: 0,
lastAttempt: new Date(),
},
};
}
return call;
});
}
/**
* Update tool call approval state
* @internal
*/
updateApprovalState(toolCalls, approvalState, options) {
const targetIds = this.normalizeToolCallIds(options.toolCallIds);
return toolCalls.map((call) => {
if (call.approvalState === "requiresApproval" && (!targetIds || targetIds.includes(call.id))) {
return { ...call, approvalState };
}
return call;
});
}
/**
* Normalize tool call IDs to an array or null
* @internal
*/
normalizeToolCallIds(toolCallIds) {
if (!toolCallIds || toolCallIds.length === 0)
return null;
return Array.isArray(toolCallIds) ? toolCallIds : [toolCallIds];
}
}
const toolCallUtilities = new LlmToolCallUtilities();
/**
* Utilities for working with messages containing tool calls
*/
class LlmMessageUtilities {
/**
* Extract tool calls that require approval from an object with tool calls
* @param input - The object with tool calls
* @returns Array of tool calls that require approval
*/
extractToolCallsRequiringApproval(input) {
return toolCallUtilities.extractRequiringApproval(input.toolCalls);
}
/**
* Extract tool calls that are pending execution from an object with tool calls
* @param input - The object with tool calls
* @returns Array of tool calls that are pending execution
*/
extractPendingToolCalls(input) {
return toolCallUtilities.extractPending(input.toolCalls);
}
/**
* Extract tool calls that are completed from an object with tool calls
* @param input - The object with tool calls
* @returns Array of tool calls that are completed
*/
extractCompletedToolCalls(input) {
return toolCallUtilities.extractCompleted(input.toolCalls);
}
/**
* Extract tool calls that have errors from an object with tool calls
* @param input - The object with tool calls
* @returns Array of tool calls that have errors
*/
extractErroredToolCalls(input) {
return toolCallUtilities.extractErrored(input.toolCalls);
}
/**
* Classify the tool calls in an object with tool calls
* @param input - The object with tool calls
* @returns Classification of the tool calls
*/
classifyToolCalls(input) {
return toolCallUtilities.classify(input.toolCalls);
}
/**
* Check if an object has any tool calls requiring approval
* @param input - The object with tool calls
* @returns True if any tool calls require approval
*/
hasToolCallsRequiringApproval(input) {
return toolCallUtilities.hasRequiringApproval(input.toolCalls);
}
/**
* Check if an object has any pending tool calls
* @param input - The object with tool calls
* @returns True if any tool calls are pending execution
*/
hasPendingToolCalls(input) {
return toolCallUtilities.hasPending(input.toolCalls);
}
/**
* Approve tool calls in an object with tool calls
* @param input - The object with tool calls
* @param options - Options for the operation
* @returns New object with approved tool calls
*/
approveToolCalls(input, options = {}) {
const updatedToolCalls = toolCallUtilities.approve(input.toolCalls, options);
return { ...input, toolCalls: updatedToolCalls };
}
/**
* Reject tool calls in an object with tool calls
* @param input - The object with tool calls
* @param options - Options for the operation
* @returns New object with rejected tool calls
*/
rejectToolCalls(input, options = {}) {
const updatedToolCalls = toolCallUtilities.reject(input.toolCalls, options);
return { ...input, toolCalls: updatedToolCalls };
}
/**
* Cancel tool calls in an object with tool calls
* @param input - The object with tool calls
* @param options - Options for the operation
* @returns New object with cancelled tool calls
*/
cancelToolCalls(input, options = {}) {
const updatedToolCalls = toolCallUtilities.cancel(input.toolCalls, options);
return { ...input, toolCalls: updatedToolCalls };
}
}
const singleMessageUtilities = new LlmMessageUtilities();
/**
* Utilities for working with arrays of messages
*/
class LlmMessagesUtilities {
/**
* Find messages with tool calls requiring approval in a message list
* @param messages - Array of mixed messages
* @returns Array of messages that have tool calls requiring approval
*/
extractMessagesWithApprovalRequired(messages) {
return messages.filter((msg) => msg.role === "assistant_with_tools" &&
singleMessageUtilities.hasToolCallsRequiringApproval(msg));
}
/**
* Find messages with pending tool calls in a message list
* @param messages - Array of mixed messages
* @returns Array of messages that have pending tool calls
*/
extractMessagesWithPendingToolCalls(messages) {
return messages.filter((msg) => msg.role === "assistant_with_tools" &&
singleMessageUtilities.hasPendingToolCalls(msg));
}
/**
* Find the latest message with tool calls requiring approval
* @param messages - Array of mixed messages
* @returns The latest message with tool calls requiring approval, or null if none found
*/
getLatestMessageWithApprovalRequired(messages) {
const messagesWithApproval = this.extractMessagesWithApprovalRequired(messages);
return messagesWithApproval.length > 0 ? messagesWithApproval[messagesWithApproval.length - 1] : null;
}
/**
* Approve tool calls in messages
* @param messages - Array of mixed messages
* @param options - Options for the operation
* @returns New array of messages with approved tool calls
*/
approveToolCalls(messages, options = {}) {
return messages.map((msg) => {
if (msg.role === "assistant_with_tools") {
return singleMessageUtilities.approveToolCalls(msg, options);
}
return msg;
});
}
/**
* Reject tool calls in messages
* @param messages - Array of mixed messages
* @param options - Options for the operation
* @returns New array of messages with rejected tool calls
*/
rejectToolCalls(messages, options = {}) {
return messages.map((msg) => {
if (msg.role === "assistant_with_tools") {
return singleMessageUtilities.rejectToolCalls(msg, options);
}
return msg;
});
}
/**
* Cancel tool calls in messages
* @param messages - Array of mixed messages
* @param options - Options for the operation
* @returns New array of messages with cancelled tool calls
*/
cancelToolCalls(messages, options = {}) {
return messages.map((msg) => {
if (msg.role === "assistant_with_tools") {
return singleMessageUtilities.cancelToolCalls(msg, options);
}
return msg;
});
}
/**
* Check if an object has any pending tool calls
* @param input - The object with tool calls
* @returns True if any tool calls are pending execution
*/
extractPendingToolCalls(input) {
const pendingToolCalls = [];
for (const message of messageListUtilities.extractMessagesWithPendingToolCalls(input)) {
for (const call of toolCallUtilities.extractPending(message.toolCalls)) {
pendingToolCalls.push({
...call,
messageId: message.id ?? "",
});
}
}
return pendingToolCalls;
}
/**
* Get the number of pending tool calls in a message list
* @param messages - Array of mixed messages
* @returns Number of pending tool calls
*/
getNumberOfPendingToolCalls(messages) {
return messageListUtilities.extractPendingToolCalls(messages).length;
}
/**
* Get a summary of tool call states across all messages
* @param messages - Array of mixed messages
* @returns Summary of tool call states
*/
getToolCallSummary(messages) {
const summary = {
totalToolCalls: 0,
requiresApproval: 0,
approved: 0,
rejected: 0,
pending: 0,
inProgress: 0,
completed: 0,
cancelled: 0,
errored: 0,
};
messages.forEach((msg) => {
if (msg.role === "assistant_with_tools") {
msg.toolCalls.forEach((call) => {
summary.totalToolCalls++;
// Count approval states
if (call.approvalState === "requiresApproval")
summary.requiresApproval++;
else if (call.approvalState === "approved")
summary.approved++;
else if (call.approvalState === "rejected")
summary.rejected++;
// Count execution states
if (call.executionState === "pending")
summary.pending++;
else if (call.executionState === "inProgress")
summary.inProgress++;
else if (call.executionState === "completed")
summary.completed++;
else if (call.executionState === "cancelled")
summary.cancelled++;
else if (call.executionState === "error")
summary.errored++;
});
}
});
return summary;
}
}
const messageListUtilities = new LlmMessagesUtilities();
/**
* Utilities for working with tool calls and messages
*/
class LlmToolKitUtilities {
constructor() {
this.calls = toolCallUtilities;
this.message = singleMessageUtilities;
this.messages = messageListUtilities;
}
}
exports.LlmToolKitUtilities = LlmToolKitUtilities;