feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing - Add AUTO-TRIGGER-SUMMARY.md documentation - Add FINAL-INTEGRATION-SUMMARY.md documentation - Complete Prometheus integration (6 commands + 4 tools) - Complete Dexto integration (12 commands + 5 tools) - Enhanced Ralph with access to all agents - Fix /clawd command (removed disable-model-invocation) - Update hooks.json to v5 with intelligent routing - 291 total skills now available - All 21 commands with automatic routing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
266
dexto/packages/core/src/utils/service-initializer.ts
Normal file
266
dexto/packages/core/src/utils/service-initializer.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Service Initializer: Centralized Wiring for Dexto Core Services
|
||||
*
|
||||
* This module is responsible for initializing and wiring together all core agent services (LLM, client manager, message manager, event bus, etc.)
|
||||
* for the Dexto application. It provides a single entry point for constructing the service graph, ensuring consistent dependency injection
|
||||
* and configuration across CLI, web, and test environments.
|
||||
*
|
||||
* **Configuration Pattern:**
|
||||
* - The primary source of configuration is the config file (e.g., `agent.yml`), which allows users to declaratively specify both high-level
|
||||
* and low-level service options (such as compression strategies for ContextManager, LLM provider/model, etc.).
|
||||
* - For most use cases, the config file is sufficient and preferred, as it enables environment-specific, auditable, and user-friendly customization.
|
||||
*
|
||||
* **Service Architecture:**
|
||||
* - All services are initialized based on the provided configuration.
|
||||
* - For testing scenarios, mock the service dependencies directly using test frameworks rather than relying on service injection patterns.
|
||||
*
|
||||
* **Best Practice:**
|
||||
* - Use the config file for all user-facing and environment-specific configuration, including low-level service details.
|
||||
* - For testing, use proper mocking frameworks rather than service injection to ensure clean, maintainable tests.
|
||||
*
|
||||
* This pattern ensures a clean, scalable, and maintainable architecture, balancing flexibility with simplicity.
|
||||
*/
|
||||
|
||||
import { MCPManager } from '../mcp/manager.js';
|
||||
import { ToolManager } from '../tools/tool-manager.js';
|
||||
import { SystemPromptManager } from '../systemPrompt/manager.js';
|
||||
import { AgentStateManager } from '../agent/state-manager.js';
|
||||
import { SessionManager } from '../session/index.js';
|
||||
import { SearchService } from '../search/index.js';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { createStorageManager, StorageManager } from '../storage/index.js';
|
||||
import { createAllowedToolsProvider } from '../tools/confirmation/allowed-tools-provider/factory.js';
|
||||
import type { IDextoLogger } from '../logger/v2/types.js';
|
||||
import type { ValidatedAgentConfig } from '@core/agent/schemas.js';
|
||||
import { AgentEventBus } from '../events/index.js';
|
||||
import { ResourceManager } from '../resources/manager.js';
|
||||
import { ApprovalManager } from '../approval/manager.js';
|
||||
import { MemoryManager } from '../memory/index.js';
|
||||
import { PluginManager } from '../plugins/manager.js';
|
||||
import { registerBuiltInPlugins } from '../plugins/registrations/builtins.js';
|
||||
|
||||
/**
|
||||
* Type for the core agent services returned by createAgentServices
|
||||
*/
|
||||
export type AgentServices = {
|
||||
mcpManager: MCPManager;
|
||||
toolManager: ToolManager;
|
||||
systemPromptManager: SystemPromptManager;
|
||||
agentEventBus: AgentEventBus;
|
||||
stateManager: AgentStateManager;
|
||||
sessionManager: SessionManager;
|
||||
searchService: SearchService;
|
||||
storageManager: StorageManager;
|
||||
resourceManager: ResourceManager;
|
||||
approvalManager: ApprovalManager;
|
||||
memoryManager: MemoryManager;
|
||||
pluginManager: PluginManager;
|
||||
};
|
||||
|
||||
// High-level factory to load, validate, and wire up all agent services in one call
|
||||
/**
|
||||
* Initializes all agent services from a validated configuration.
|
||||
* @param config The validated agent configuration object
|
||||
* @param configPath Optional path to the config file (for relative path resolution)
|
||||
* @param logger Logger instance for this agent (dependency injection)
|
||||
* @param agentEventBus Pre-created event bus from DextoAgent constructor
|
||||
* @returns All the initialized services required for a Dexto agent
|
||||
*/
|
||||
export async function createAgentServices(
|
||||
config: ValidatedAgentConfig,
|
||||
configPath: string | undefined,
|
||||
logger: IDextoLogger,
|
||||
agentEventBus: AgentEventBus
|
||||
): Promise<AgentServices> {
|
||||
// 0. Initialize telemetry FIRST (before any decorated classes are instantiated)
|
||||
// This must happen before creating any services that use @InstrumentClass decorator
|
||||
if (config.telemetry?.enabled) {
|
||||
const { Telemetry } = await import('../telemetry/telemetry.js');
|
||||
await Telemetry.init(config.telemetry);
|
||||
logger.debug('Telemetry initialized');
|
||||
}
|
||||
|
||||
// 1. Use the event bus provided by DextoAgent constructor
|
||||
logger.debug('Using pre-created agent event bus');
|
||||
|
||||
// 2. Initialize storage manager (schema provides in-memory defaults, CLI enrichment adds filesystem paths)
|
||||
logger.debug('Initializing storage manager');
|
||||
const storageManager = await createStorageManager(config.storage, logger);
|
||||
|
||||
logger.debug('Storage manager initialized', {
|
||||
cache: config.storage.cache.type,
|
||||
database: config.storage.database.type,
|
||||
});
|
||||
|
||||
// 3. Initialize approval system (generalized user approval)
|
||||
// Created before MCP manager since MCP manager depends on it for elicitation support
|
||||
logger.debug('Initializing approval manager');
|
||||
const approvalManager = new ApprovalManager(
|
||||
{
|
||||
toolConfirmation: {
|
||||
mode: config.toolConfirmation.mode,
|
||||
...(config.toolConfirmation.timeout !== undefined && {
|
||||
timeout: config.toolConfirmation.timeout,
|
||||
}),
|
||||
},
|
||||
elicitation: {
|
||||
enabled: config.elicitation.enabled,
|
||||
...(config.elicitation.timeout !== undefined && {
|
||||
timeout: config.elicitation.timeout,
|
||||
}),
|
||||
},
|
||||
},
|
||||
logger
|
||||
);
|
||||
logger.debug('Approval system initialized');
|
||||
|
||||
// 4. Initialize MCP manager
|
||||
const mcpManager = new MCPManager(logger);
|
||||
await mcpManager.initializeFromConfig(config.mcpServers);
|
||||
|
||||
// 4.1 - Wire approval manager into MCP manager for elicitation support
|
||||
mcpManager.setApprovalManager(approvalManager);
|
||||
logger.debug('Approval manager connected to MCP manager for elicitation support');
|
||||
|
||||
// 5. Initialize search service
|
||||
const searchService = new SearchService(storageManager.getDatabase(), logger);
|
||||
|
||||
// 6. Initialize memory manager
|
||||
const memoryManager = new MemoryManager(storageManager.getDatabase(), logger);
|
||||
logger.debug('Memory manager initialized');
|
||||
|
||||
// 6.5 Initialize plugin manager
|
||||
const configDir = configPath ? dirname(resolve(configPath)) : process.cwd();
|
||||
const pluginManager = new PluginManager(
|
||||
{
|
||||
agentEventBus,
|
||||
storageManager,
|
||||
configDir,
|
||||
},
|
||||
logger
|
||||
);
|
||||
|
||||
// Register built-in plugins from registry
|
||||
registerBuiltInPlugins({ pluginManager, config });
|
||||
logger.debug('Built-in plugins registered');
|
||||
|
||||
// Initialize plugin manager (loads custom and registry plugins, validates, calls initialize())
|
||||
await pluginManager.initialize(config.plugins.custom, config.plugins.registry);
|
||||
logger.info('Plugin manager initialized');
|
||||
|
||||
// 7. Initialize resource manager (MCP + internal resources)
|
||||
// Moved before tool manager so it can be passed to internal tools
|
||||
const resourceManager = new ResourceManager(
|
||||
mcpManager,
|
||||
{
|
||||
internalResourcesConfig: config.internalResources,
|
||||
blobStore: storageManager.getBlobStore(),
|
||||
},
|
||||
logger
|
||||
);
|
||||
await resourceManager.initialize();
|
||||
|
||||
// 8. Initialize tool manager with internal tools options
|
||||
// 8.1 - Create allowed tools provider based on configuration
|
||||
const allowedToolsProvider = createAllowedToolsProvider(
|
||||
{
|
||||
type: config.toolConfirmation.allowedToolsStorage,
|
||||
storageManager,
|
||||
},
|
||||
logger
|
||||
);
|
||||
|
||||
// 8.2 - Initialize tool manager with direct ApprovalManager integration
|
||||
const toolManager = new ToolManager(
|
||||
mcpManager,
|
||||
approvalManager,
|
||||
allowedToolsProvider,
|
||||
config.toolConfirmation.mode,
|
||||
agentEventBus,
|
||||
config.toolConfirmation.toolPolicies,
|
||||
{
|
||||
internalToolsServices: {
|
||||
searchService,
|
||||
resourceManager,
|
||||
},
|
||||
internalToolsConfig: config.internalTools,
|
||||
customToolsConfig: config.customTools,
|
||||
},
|
||||
logger
|
||||
);
|
||||
// NOTE: toolManager.initialize() is called in DextoAgent.start() after agent reference is set
|
||||
// This allows custom tools to access the agent for bidirectional communication
|
||||
|
||||
const mcpServerCount = Object.keys(config.mcpServers).length;
|
||||
if (mcpServerCount === 0) {
|
||||
logger.info('Agent initialized without MCP servers - only built-in capabilities available');
|
||||
} else {
|
||||
logger.debug(`MCPManager initialized with ${mcpServerCount} MCP server(s)`);
|
||||
}
|
||||
|
||||
if (config.internalTools.length === 0) {
|
||||
logger.info('No internal tools enabled by configuration');
|
||||
} else {
|
||||
logger.info(`Internal tools enabled: ${config.internalTools.join(', ')}`);
|
||||
}
|
||||
|
||||
// 9. Initialize prompt manager
|
||||
logger.debug(
|
||||
`[ServiceInitializer] Creating SystemPromptManager with configPath: ${configPath} → configDir: ${configDir}`
|
||||
);
|
||||
const systemPromptManager = new SystemPromptManager(
|
||||
config.systemPrompt,
|
||||
configDir,
|
||||
memoryManager,
|
||||
config.memories,
|
||||
logger
|
||||
);
|
||||
|
||||
// 10. Initialize state manager for runtime state tracking
|
||||
const stateManager = new AgentStateManager(config, agentEventBus, logger);
|
||||
logger.debug('Agent state manager initialized');
|
||||
|
||||
// 11. Initialize session manager
|
||||
const sessionManager = new SessionManager(
|
||||
{
|
||||
stateManager,
|
||||
systemPromptManager,
|
||||
toolManager,
|
||||
agentEventBus,
|
||||
storageManager, // Add storage manager to session services
|
||||
resourceManager, // Add resource manager for blob storage
|
||||
pluginManager, // Add plugin manager for plugin execution
|
||||
mcpManager, // Add MCP manager for ChatSession
|
||||
},
|
||||
{
|
||||
maxSessions: config.sessions?.maxSessions,
|
||||
sessionTTL: config.sessions?.sessionTTL,
|
||||
},
|
||||
logger
|
||||
);
|
||||
|
||||
// Initialize the session manager with persistent storage
|
||||
await sessionManager.init();
|
||||
|
||||
logger.debug('Session manager initialized with storage support');
|
||||
|
||||
// 12.5 Wire up plugin support to ToolManager (after SessionManager is created)
|
||||
toolManager.setPluginSupport(pluginManager, sessionManager, stateManager);
|
||||
logger.debug('Plugin support connected to ToolManager');
|
||||
|
||||
// 13. Return the core services
|
||||
return {
|
||||
mcpManager,
|
||||
toolManager,
|
||||
systemPromptManager,
|
||||
agentEventBus,
|
||||
stateManager,
|
||||
sessionManager,
|
||||
searchService,
|
||||
storageManager,
|
||||
resourceManager,
|
||||
approvalManager,
|
||||
memoryManager,
|
||||
pluginManager,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user