Socket
Book a DemoInstallSign in
Socket

directed-agent

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

directed-agent

A TypeScript library for agent graph functionality

latest
npmnpm
Version
0.1.10
Version published
Maintainers
1
Created
Source

Directed Agent

A powerful TypeScript library for building conversational AI flows and state machines using graph-based structures. Create complex agent interactions with nodes, edges, and seamless traversal capabilities.

Features

  • ๐ŸŽฏ Graph-based Architecture: Build conversational flows using nodes and edges
  • ๐Ÿ”„ Flexible Traversal: Multiple traversal strategies with built-in state management
  • ๐Ÿ“Š Rich Visualizations: Generate Mermaid diagrams, DOT graphs, ASCII art, and JSON exports
  • ๐Ÿ› ๏ธ TypeScript First: Full type safety and excellent developer experience
  • ๐Ÿงช Well Tested: Comprehensive test suite with Vitest
  • ๐Ÿ”Œ Extensible: Easy to extend with custom node types and traversal logic

Installation

npm install directed-agent

Quick Start

import { Graph, AgentGraphNode, GraphTraverser } from "directed-agent";

// Define a custom send node
class GreetingNode_Send extends AgentGraphNode {
  async onEnter(context: FormContext) {
    return {
      messages: [{ text: "Hello! How can I help you today?" }],
      nextNode: "greeting_receive",
    };
  }

  async getNextNodes(context: FormContext) {
    return ["greeting_receive"];
  }
}

// Define a custom receive node
class GreetingNode_Receive extends AgentGraphNode {
  async onEnter(context: FormContext) {
    const messages = context.messages;
    const userResponse = messages[messages.length - 1]?.content || "nothing";

    return {
      messages: [{ text: `Thanks for telling me about: ${userResponse}` }],
      nextNode: "greeting_send", // Loop back
    };
  }

  async getNextNodes(context: FormContext) {
    return ["greeting_send"];
  }
}

const graphRepresentation = {
  greeting_send: new GreetingNode_Send(),
  greeting_receive: new GreetingNode_Receive(),
};

// Create and populate the graph
const graph = Graph.fromAgentNodes(graphRepresentation);

// Set up traversal
const traverser = new GraphTraverser({
  graph,
  sendMessage: async (message) => console.log(message),
  updateState: async (state) => console.log(`State: ${state}`),
  getContext: async () => ({
    messages: [],
    formData: {},
    setFormData: () => {},
  }),
});

// Execute the flow
await traverser.execute("greeting_send");

Core Concepts

Graph Structure

The library uses a directed graph structure where:

  • Nodes represent states or actions in your conversational flow
  • Edges define the connections and possible transitions between nodes
  • Context carries data and state throughout the conversation

State Types

Agent Graph uses a convention-based approach for managing conversation flow with two types of states:

Send States (_send)

  • Purpose: Execute agent logic and send messages to the user
  • Behavior: Automatically transition to the next state after execution
  • Example: greeting_send, welcome_send, process_order_send

Receive States (_receive)

  • Purpose: Wait for and process user input
  • Behavior: Pause traversal until the user submits input, then continue
  • Example: greeting_receive, get_name_receive, collect_address_receive
class WelcomeNode_Send extends AgentGraphNode {
  async onEnter(context) {
    return {
      messages: [{ text: "Welcome! Please enter your name:" }],
      nextNode: "welcome_receive", // Transitions to receive state
    };
  }
}

class WelcomeNode_Receive extends AgentGraphNode {
  async onEnter(context) {
    const messages = context.messages;
    const userName = messages[messages.length - 1]?.content || "Guest";

    return {
      messages: [{ text: `Hello ${userName}! How can I help you?` }],
      nextNode: "main_menu_send", // Continue the flow
    };
  }
}

This pattern ensures smooth conversation flow where:

  • Send states deliver information and questions to users
  • Receive states capture and process user responses
  • Traversal automatically pauses at receive states until user input arrives

AgentGraphNode

The base class for all nodes in your graph. Implement custom logic by extending this class:

class CustomNode extends AgentGraphNode {
  async onEnter(context: FormContext): Promise<{
    messages?: { text: string }[];
    nextNode: string;
  }> {
    // Your custom logic here
    return {
      messages: [{ text: "Custom message" }],
      nextNode: "next-node-id",
    };
  }

  async getNextNodes(context: FormContext): Promise<string[]> {
    // Return possible next nodes
    return ["next-node-id"];
  }
}

Graph Management

const graph = new Graph();

// Add nodes
graph.addNode({ id: "node1", node: new CustomNode(), data: {} });
graph.addNode({ id: "node2", node: new CustomNode(), data: {} });

// Add edges
graph.addEdge({ id: "edge1", source: "node1", target: "node2" });

// Query the graph
const node = graph.getNode("node1");
const connectedNodes = graph.getConnectedNodes("node1");
const hasPath = graph.hasPath("node1", "node2");

Visualization

Generate visual representations of your graphs:

import { GraphVisualizer } from "directed-agent";

const visualizer = new GraphVisualizer(graph);

// Generate Mermaid diagram
const mermaid = visualizer.toMermaid();
console.log(mermaid);

// Generate DOT graph (for Graphviz)
const dot = visualizer.toDOT();

// Generate ASCII representation
const ascii = visualizer.toASCII();

// Export as JSON
const json = visualizer.toJSON();

Visualization Options

Customize the appearance of your visualizations:

const visualizer = new GraphVisualizer(graph, {
  nodeSize: 25,
  nodeColor: "#4f46e5",
  edgeColor: "#6b7280",
  fontSize: 14,
  width: 1000,
  height: 800,
});

Advanced Usage

TerminalTraverser

The TerminalTraverser class provides an easy way to test your conversational agents directly from your terminal. It's perfect for rapid prototyping and debugging your agent flows:

import { TerminalTraverser, Graph, AgentGraphNode } from "../src/";

// Simple greeting node
class GreetingNode_Send extends AgentGraphNode {
  async onEnter(context) {
    return {
      messages: [{ text: "Hello! What's your name?" }],
      nextNode: "greeting_receive",
    };
  }

  async getNextNodes() {
    return ["greeting_receive"];
  }
}

// Simple response node
class GreetingNode_Receive extends AgentGraphNode {
  async onEnter(context) {
    const messages = context.messages;
    const lastMessage =
      messages.length > 0 ? messages[messages.length - 1] : null;
    const name = lastMessage?.content || "friend";
    return {
      messages: [{ text: `Nice to meet you, ${name}!` }],
      nextNode: "greeting_send", // Loop back
    };
  }

  async getNextNodes() {
    return ["greeting_send"];
  }
}

async function runDemo() {
  // Create graph from service definition
  const serviceGraph = {
    greeting_send: new GreetingNode_Send(),
    greeting_receive: new GreetingNode_Receive(),
  };

  const graph = await Graph.fromAgentNodes(serviceGraph);

  const terminal = new TerminalTraverser({
    graph,
    initialState: "greeting_send",
  });

  await terminal.start();
}

// Run the demo
runDemo().catch(console.error);

The TerminalTraverser:

  • Interactive Console: Automatically handles user input from the terminal
  • Real-time Testing: See your agent's responses immediately as you type
  • State Visualization: View current state and context changes
  • Debug-Friendly: Perfect for testing conversation flows during development
  • Type-Safe: Full TypeScript support with custom data interfaces

This makes it incredibly easy to test complex conversation flows without building a full UI, allowing you to focus on perfecting your agent's logic and responses.

Custom Traverser

Create specialized traversers for different environments:

import { GraphTraverser, GraphTraverserOptions } from "directed-agent";

class TerminalTraverser extends GraphTraverser {
  constructor(
    options: GraphTraverserOptions & {
      initialState: string;
      initialContext: any;
    }
  ) {
    super({
      ...options,
      sendMessage: async (message) => {
        console.log(`๐Ÿค– ${message}`);
      },
      updateState: async (state) => {
        this.currentState = state;
      },
      getContext: async () => this.context,
    });
  }

  async start() {
    await this.execute(this.initialState);
  }
}

State Persistence

Track visited states and conversation flow:

const traverser = new GraphTraverser({
  graph,
  sendMessage: async (message) => console.log(message),
  updateState: async (state) => await saveState(state),
  getContext: async () => await loadContext(),
  steps: {
    getVisited: async () => await loadVisitedSteps(),
    addVisited: (step) => saveVisitedStep(step),
  },
});

Serialization

Export and import graph structures:

// Export graph to JSON
const graphData = graph.toJSON();

// Create graph from service definition
const serviceGraph = {
  node1: new GreetingNode(),
  node2: new QuestionNode(),
  node3: new ResponseNode(),
};

const newGraph = await Graph.fromAgentNodes(serviceGraph);

Examples

Pizza Delivery Bot

class IntroNode_Send extends AgentGraphNode {
  async onEnter(context: FormContext) {
    return {
      messages: [
        {
          text: "๐Ÿ• Welcome to Tony's Pizza! What would you like to order?",
        },
      ],
      nextNode: "intro_receive",
    };
  }
}

class IntroNode_Receive extends AgentGraphNode {
  async onEnter(context: FormContext) {
    const messages = context.messages;
    const order = messages[messages.length - 1]?.content || "pizza";

    return {
      messages: [
        {
          text: `Great choice! You want ${order}. What's your address?`,
        },
      ],
      nextNode: "address_receive",
    };
  }
}

class AddressNode_Receive extends AgentGraphNode {
  async onEnter(context: FormContext) {
    const messages = context.messages;
    const address = messages[messages.length - 1]?.content || "unknown address";

    return {
      messages: [
        {
          text: `Perfect! We'll deliver to ${address}. Your order is confirmed!`,
        },
      ],
      nextNode: "intro_send", // Start over
    };
  }
}

// Build the graph
const graph = new Graph();
graph.addNode({ id: "intro_send", node: new IntroNode_Send(), data: {} });
graph.addNode({ id: "intro_receive", node: new IntroNode_Receive(), data: {} });
graph.addNode({
  id: "address_receive",
  node: new AddressNode_Receive(),
  data: {},
});

Testing

The library includes comprehensive test utilities:

import { TestNode } from "directed-agent/test-utils";

// Use TestNode for easy testing
const testNode = new TestNode("next-node", [{ text: "Test message" }]);
const result = await testNode.onEnter({});
expect(result.nextNode).toBe("next-node");
expect(result.messages).toEqual([{ text: "Test message" }]);

API Reference

Graph Class

  • addNode(node: AgentNode): void - Add a node to the graph
  • addEdge(edge: AgentEdge): void - Add an edge to the graph
  • getNode(id: string): AgentNode | undefined - Get node by ID
  • getConnectedNodes(nodeId: string): AgentNode[] - Get connected nodes
  • hasPath(source: string, target: string): boolean - Check if path exists
  • toJSON(): AgentGraph - Export graph structure

AgentGraphNode Class

  • onEnter(context: FormContext): Promise<{ messages?, nextNode }> - Execute node logic
  • getNextNodes(context: FormContext): Promise<string[]> - Get possible next nodes

GraphVisualizer Class

  • toMermaid(): string - Generate Mermaid diagram
  • toDOT(): string

Keywords

typescript

FAQs

Package last updated on 08 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.