daggerai
Version:
A simple and powerful Typescript based agent framework to help businesses thrive in the AI Agent revolution.
118 lines • 4.37 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Squad = void 0;
const events_1 = require("events");
const nanoid_1 = require("nanoid");
const typescript_graph_1 = require("typescript-graph");
const helpers_1 = require("./helpers");
class Squad {
graph = new typescript_graph_1.DirectedAcyclicGraph();
env = {};
queue = [];
order = [];
nodes = [];
history = [];
// additional instructions the user can send to the squad
inputs = [];
instructions = '';
events = new events_1.EventEmitter();
verbose = false;
constructor(params = {}) {
this.verbose = params.verbose || false;
}
async evaluate(params) {
this.inputs = params.inputs;
this.instructions = params.instructions || '';
// find the nodes with no incoming edges
let inDegree = {};
for (const node of this.nodes) {
inDegree[node.id] = node.adjancentFrom.length;
}
// the queue starts with the nodes that have no incoming edges
this.queue = Object.keys(inDegree).filter(id => inDegree[id] === 0);
// the order the nodes were executed
this.order = [];
// Keep running the loop until there are no more nodes to execute
while (true) {
const nextNode = this.findNextNode(this.queue);
if (!nextNode) {
break;
}
// Remove the next node from the queue
this.queue.splice(this.queue.indexOf(nextNode.id), 1);
if (nextNode.type === 'input') {
const inputNode = nextNode;
if (!this.inputs) {
throw new Error('Inputs are required');
}
const input = this.inputs.find(i => (0, helpers_1.removeDiacritics)(i.name).toLowerCase() ===
(0, helpers_1.removeDiacritics)(inputNode.name).toLowerCase());
inputNode.output = input?.value || '';
}
if (nextNode.type === 'task') {
const taskNode = nextNode;
// Add the next node to the order array
this.order.push(taskNode);
// Executes the node
const taskResponse = await taskNode.execute(this);
this.env[taskNode.id] = taskResponse;
}
this.history.push(nextNode.id);
// Add the IDs of the nodes that the current node is adjacent to to the queue
for (const id of nextNode.adjacentTo) {
if (this.history.includes(id) || this.queue.includes(id)) {
continue;
}
this.queue.push(id);
}
}
this.events.emit('squad.finished', {
name: 'Squad',
output: Object.values(this.env).join('\n\n'),
});
// Return the environment object containing the results of all executed tasks
return this.env;
}
recalculateInDegree(id) {
const node = this.nodes.find(t => t.id === id);
const dependencies = node.adjancentFrom;
return dependencies.filter(d => !this.history.includes(d)).length;
}
findNextNode(ids) {
for (let id of ids) {
const degree = this.recalculateInDegree(id);
if (degree === 0) {
return this.nodes.find(t => t.id === id);
}
}
return null;
}
connect(from, to) {
const fromNode = this.nodes.find(t => t.id === from.id);
const toNode = this.nodes.find(t => t.id === to.id);
if (!fromNode || !toNode) {
throw new Error('Node not found');
}
fromNode.adjacentTo.push(to.id);
toNode.adjancentFrom.push(from.id);
this.graph.addEdge(from.graphId, to.graphId);
}
add(node) {
if (!node.id) {
node.id = (0, nanoid_1.nanoid)();
}
node.graphId = this.graph.insert(node.id);
this.nodes.push(node);
}
sortedNodes() {
return this.graph
.topologicallySortedNodes()
.map(n => this.nodes.find(t => t.id === n));
}
nodesById(ids) {
const allNodes = this.sortedNodes();
return ids.map(t => allNodes.find(n => n.id === t));
}
}
exports.Squad = Squad;
//# sourceMappingURL=squad.js.map