Node System
AgentDock is built around a powerful node-based architecture using BaseNode as the foundation for all functionality. This design allows for modular, extensible, and highly configurable systems. BaseNode supports various node categories, including core functionalities like LLM interaction (AgentNode) and callable tools, forming the basis for sophisticated agent behaviors.
Looking Ahead: The Workflow Vision
The underlying structure, with defined input/output ports and MessageBus integration, provides the core capabilities necessary to build complex workflow engines and chained execution patterns directly using the open-source library. While the reference client currently focuses on AgentNode orchestrating individual tool executions, the architecture is designed for much more.
We are actively developing a richer set of node types to unlock true workflow automation, including:
- Event Nodes: To trigger workflows from external sources or schedules.
- Transform & AI Inference Nodes: For powerful data manipulation and specialized AI tasks.
- Connector & Action Nodes: To seamlessly integrate with external services and databases.
- Logic Nodes: For sophisticated flow control like branching and looping.
These planned additions, detailed further in the Workflow Nodes Roadmap, will empower users to build complex, multi-step automations visually and programmatically, extending far beyond the current agent-tool interaction model.
AgentDock Pro aims to enhance this capability by providing advanced tooling, such as visual workflow builders and management interfaces, built upon this expanding core open-source node system.
Core Node Types
While developers can create many types of custom nodes, AgentDock Core provides key foundational types:
BaseNode
The BaseNode is the foundation of AgentDock's architecture, provided by AgentDock Core. It creates a consistent interface and core functionality for all node types:
- Metadata Management: Each node provides detailed, immutable
NodeMetadataincluding:-
category: 'core' or 'custom' -
label: Display name -
description: Functionality overview -
inputs/outputs: Defined ports (see below) -
version: Semantic version string -
compatibility: Flags indicating core/pro/custom environment support
-
- Port System: Type-safe
inputsandoutputsdefined using theNodePortinterface:-
id: Unique port identifier -
type: Data type string -
label: Display name -
schema: Optional Zod schema for validation -
required: Boolean flag -
defaultValue: Optional default value
-
- Validation Hooks: Provides methods like
validateInput,validateOutput, andvalidateConnectionfor ensuring data integrity and connection validity (subclasses can override). - Message Passing: Integrates with a
MessageBus(set viasetMessageBus). Nodes can send messages (sendMessage) and register handlers (addMessageHandler,removeMessageHandler), enabling potential asynchronous coordination between nodes. - Lifecycle Management:
initialize()for setup,execute()for core logic, andcleanup()for resource disposal. - Serialization: Includes a
toJSON()method for converting the node's state (ID, type, config, metadata) to a JSON representation.
// From AgentDock Core
export abstract class BaseNode<TConfig = unknown> {
readonly id: string;
abstract readonly type: string; // e.g., 'core.agent'
protected config: TConfig; // Static configuration
readonly metadata: NodeMetadata;
// Core execution
abstract execute(input: unknown): Promise<unknown>;
// Lifecycle
async initialize(): Promise<void>;
async cleanup(): Promise<void>;
// Validation
validateInput(input: unknown): boolean;
validateOutput(output: unknown): boolean;
validateConnection(sourcePort: string, targetPort: string): boolean;
// Messaging
setMessageBus(messageBus: MessageBus): void;
protected async sendMessage<T>(targetId: string, type: string, payload: T): Promise<string>;
protected addMessageHandler<T>(type: string, handler: MessageHandler<T>): void;
protected removeMessageHandler(type: string): void;
// Serialization
toJSON(): { id: string; type: string; config: TConfig; metadata: NodeMetadata };
}
AgentNode
The AgentNode (type: 'core.agent') is a specialized node in AgentDock Core orchestrating conversational AI interactions:
- Configuration (
AgentNodeConfig): Initialized with provider details, API keys (primary and fallback), LLM options, and the crucialagentConfigobject containing the full agent definition (personality, nodes, orchestration rules). - LLM Integration: Manages
CoreLLMinstances (primary and optional fallback), handling provider/model derivation logic viacreateLLMInstanceif not explicitly configured. - Dynamic Tool Selection: Determines available tools for each turn via
getAvailableTools, consulting theToolRegistryand the agent'sorchestrationrules via an injectedOrchestrationManager. - Runtime Execution (
handleMessage): RequiresAgentNodeHandleMessageOptionsincluding conversationmessages, theOrchestrationManager,sessionId, and optional overrides for system prompts or LLM configuration. - Stream Delegation: Sets up the LLM call (using
streamTextfrom the LLM service) and returns theAgentDockStreamResult(containing the stream and promises) immediately. It delegates the consumption of the stream and handling of tool calls/results to the calling adapter/API route. - Error Handling: Implements fallback mechanisms for LLM provider issues.
// From AgentDock Core
export class AgentNode extends BaseNode<AgentNodeConfig> {
readonly type = 'core.agent';
// Main entry point for conversational turns
async handleMessage(options: AgentNodeHandleMessageOptions): Promise<AgentDockStreamResult>;
// Direct execution (less common for conversational flow)
async execute(input: unknown): Promise<unknown>;
// Retrieve token usage from the last interaction
getLastTokenUsage(): LanguageModelUsage | null;
}
Tools as Nodes
Tools in AgentDock are implemented as specialized node types, registered in the NodeRegistry with isTool: true:
- Registration: Registered like any other node but with additional tool-specific options (see
NodeRegistrybelow). - Schema & Description: Require a
parameters(Zod schema) anddescriptionduring registration, used for LLM interaction. - Consistent Interface: Follow the same
BaseNodepattern (execute,initialize,cleanup). TheNodeRegistrycan wrap them to fit the standard AI SDKToolinterface. - Dynamic Availability: Availability during a conversation is managed by the
AgentNodeusing theToolRegistryandOrchestrationManager.
Node Registration System
AgentDock uses registry systems to manage node and tool types:
Node Registry
The NodeRegistry from AgentDock Core provides a central system for discovering and instantiating node types:
- Type Management: Registers
NodeRegistrationobjects (containingnodeClass,version,isTool,parameters,description) mapped by a unique type string (e.g.,'core.agent'). - Core vs. Custom: Uses separate methods (
registerfor 'core',registerCustomNodefor 'custom') enforcing category constraints. - Instantiation (
create): Creates node instances, performing version compatibility checks between the registered version and the node class's reported version. - Tool Definition Generation (
getToolDefinitions): Generates an object mapping tool node types to AI SDK-compatibleToolobjects, automatically wrapping the node'sexecutemethod. - Metadata Access (
getNodeMetadata): Returns comprehensive metadata for all registered core and custom nodes.
Tool Registry
The ToolRegistry from AgentDock Core manages the runtime availability of tools for specific agent interactions:
- Purpose: Primarily used by
AgentNodeto determine which tools (identified by their node type strings) are available for a given agent configuration during a specific turn. - Filtering (
getToolsForAgent): Takes a list of node names (from agent config) and returns the corresponding tool objects registered globally. - Global Instance: Typically accessed via a singleton pattern (
getToolRegistry()).
Custom Node Development
(This section primarily describes the pattern in the NextJS reference implementation, which uses a simplified tool definition format compared to the core NodeRegistry registration.)
In the open source reference client implementation (NextJS), custom tools are implemented slightly differently, often directly defining objects conforming to the Vercel AI SDK Tool interface:
Implementation Pattern (Reference Client)
// Example from the NextJS reference implementation (src/nodes/tools)
import { z } from 'zod';
import { Tool } from 'ai'; // Vercel AI SDK Tool type
// ... potentially import React components ...
const myToolSchema = z.object({ /* ... */ });
export const myTool: Tool = {
name: 'my_tool_id', // Matches the key in the tools object
description: 'What this tool does',
parameters: myToolSchema,
execute: async (args) => { /* ... server-side logic ... */ },
// Optional: render function for UI display in NextJS client
// render: (props) => <MyComponent {...props} />
};
// Exported for auto-registration via src/nodes/init.ts
export const tools = {
my_tool_id: myTool,
};
(Note: This reference implementation pattern bypasses direct registration with agentdock-core's NodeRegistry for simpler tool definition, relying on its own loading mechanism.)
Security Best Practices
(These apply regardless of the implementation pattern)
- Keep API calls server-side within the tool's
executefunction. - Use environment variables for secrets (API keys).
- Implement robust error handling.
- Consider rate limiting.
Design Patterns
The node system implements several key design patterns:
- Factory Pattern:
NodeRegistry.createacts as a factory for node instances. - Registry Pattern:
NodeRegistryandToolRegistrymanage node/tool types. - Observer Pattern (Potential): The
MessageBusintegration allows for observer-like patterns between nodes. - Strategy Pattern: Different node implementations can represent different strategies for achieving a task.
Node Lifecycle
Nodes go through a defined lifecycle managed by the system interacting with them (e.g., an agent runner or workflow engine):
- Registration: Node type is registered with
NodeRegistry. - Instantiation: Node instance is created via
NodeRegistry.create. - Initialization: Node's
initialize()method is called (e.g., before first use). - Execution: Node's
execute()(orhandleMessageforAgentNode) is called potentially multiple times. - Cleanup: Node's
cleanup()method is called when the instance is no longer needed.
Node Relationships
Nodes can interact or be connected conceptually:
- Message Passing: Asynchronous communication via the
MessageBusenables decoupled interactions, suitable for complex event-driven workflows. - Tool Invocation:
AgentNodeinvokes tool nodes based on LLM requests, orchestrated viaToolRegistryandOrchestrationManager. - Workflow Connections: The
input/outputport system andvalidateConnectionmethod provide the foundation for defining explicit data flow chains between diverse node types (Event, Transform, Action, Logic, etc.), enabling the construction of complex, automated processes and future visual workflow builders.
Future Enhancements
The node system is designed to support future enhancements:
- Rich Workflow Node Library: Expanding the core library with robust implementations of Event, Transform, AI Inference, Connector, Action, and Logic nodes.
- Visual Node Editor: Leveraging
NodeMetadata(ports, descriptions) for a UI to connect the full range of workflow nodes. - Node Versioning: Core registry already supports versioning checks.
- Node Marketplace: Sharing custom node implementations.
- Workflow Engine: Building upon the message bus and port connections.
Documentation and Examples
For detailed guidance:
- Review
agentdock-coresource code insrc/nodes/. - See
src/nodes/custom-tool-contributions.mdin the reference implementation for client-specific tool patterns. - Examine existing tools in the reference implementation's
src/nodes/tools/directory.