@mrtkrcm/acp-claude-code
Version:
ACP (Agent Client Protocol) bridge for Claude Code
263 lines • 10.5 kB
JavaScript
/**
* Enhanced Agent Integration Module
*
* This module provides integration points for the new MCP optimization features
* without modifying the existing agent.ts file directly.
*/
import { ClaudeACPAgent } from './agent.js';
import { globalMcpManager } from './mcp-connection-manager.js';
import { globalToolBatcher } from './mcp-tool-batcher.js';
import { ContextOptimizer } from './context-optimizer.js';
import { ContextMonitor } from './context-monitor.js';
import { createLogger } from './logger.js';
/**
* Enhanced Claude ACP Agent with MCP optimizations
*/
export class EnhancedClaudeACPAgent extends ClaudeACPAgent {
contextOptimizer;
logger;
options;
constructor(client, options = {}) {
super(client);
this.logger = createLogger('Enhanced-Agent');
this.options = {
enableMcpOptimization: true,
enableToolBatching: true,
enableContextOptimization: true,
mcpConnectionPoolSize: 3,
toolBatchingStrategy: 'dependency-aware',
contextOptimizationStrategy: 'balanced',
...options
};
// Initialize context optimizer with the existing context monitor
this.contextOptimizer = new ContextOptimizer(new ContextMonitor());
this.initializeEnhancements();
}
async initializeEnhancements() {
this.logger.info('Initializing MCP enhancements', this.options);
if (this.options.enableMcpOptimization) {
await this.initializeMcpOptimization();
}
if (this.options.enableToolBatching) {
this.initializeToolBatching();
}
if (this.options.enableContextOptimization) {
this.initializeContextOptimization();
}
}
async initializeMcpOptimization() {
// Register default MCP servers that would typically be configured
// These would come from Claude Code SDK configuration in a real implementation
const defaultServers = [
{
name: 'filesystem',
type: 'stdio',
config: { command: 'mcp-filesystem', args: [] },
maxConnections: this.options.mcpConnectionPoolSize,
},
{
name: 'web-search',
type: 'stdio',
config: { command: 'mcp-web-search', args: [] },
maxConnections: this.options.mcpConnectionPoolSize,
},
{
name: 'terminal',
type: 'stdio',
config: { command: 'mcp-terminal', args: [] },
maxConnections: this.options.mcpConnectionPoolSize,
}
];
for (const server of defaultServers) {
try {
await globalMcpManager.registerServer(server);
this.logger.info(`Registered MCP server: ${server.name}`);
}
catch (error) {
this.logger.warn(`Failed to register MCP server ${server.name}: ${error}`);
}
}
}
initializeToolBatching() {
this.logger.info(`Tool batching enabled with ${this.options.toolBatchingStrategy} strategy`);
// Tool batching integration happens at the message processing level
}
initializeContextOptimization() {
this.logger.info(`Context optimization enabled with ${this.options.contextOptimizationStrategy} strategy`);
// Context optimization integration happens at the prompt processing level
}
/**
* Enhanced prompt processing with context optimization
*/
async processPromptWithOptimization(sessionId, promptText) {
if (!this.options.enableContextOptimization) {
return {
optimizedPrompt: promptText,
optimizationStats: null
};
}
// Add current prompt as context chunk
this.contextOptimizer.addContextChunk(sessionId, {
id: `prompt_${Date.now()}`,
content: promptText,
type: 'user',
timestamp: Date.now(),
importance: 1.0, // User prompts are always important
tokenCount: Math.ceil(promptText.length / 4),
});
// Analyze context health
const healthAnalysis = this.contextOptimizer.analyzeContextHealth(sessionId);
if (healthAnalysis.status !== 'healthy') {
this.logger.info(`Context health: ${healthAnalysis.status}`, {
sessionId,
recommendations: healthAnalysis.recommendations,
stats: healthAnalysis.stats
});
// Optimize context if needed
const optimization = this.contextOptimizer.optimizeContext(sessionId, this.options.contextOptimizationStrategy);
this.logger.info(`Context optimized for session ${sessionId}`, optimization.stats);
return {
optimizedPrompt: optimization.optimizedContext,
optimizationStats: optimization.stats
};
}
return {
optimizedPrompt: promptText,
optimizationStats: null
};
}
/**
* Enhanced tool call processing with batching
*/
async processToolCallsWithBatching(sessionId, toolCalls) {
if (!this.options.enableToolBatching || toolCalls.length <= 1) {
// Fall back to individual execution for single tools
return this.processToolCallsIndividually(toolCalls);
}
const batchId = `batch_${sessionId}_${Date.now()}`;
// Convert to batchable format and analyze dependencies
const batchableCalls = toolCalls.map((call, index) => ({
id: call.id,
serverName: this.mapToolToMcpServer(call.name),
toolName: call.name,
args: call.input,
priority: index, // Simple priority based on order
dependencies: this.analyzeDependencies(call, toolCalls),
timeout: 30000,
}));
// Add to batch
globalToolBatcher.addToBatch(batchId, batchableCalls);
// Execute batch with configured strategy
const results = await globalToolBatcher.executeBatch(batchId, {
strategy: this.options.toolBatchingStrategy,
maxConcurrency: 5,
batchTimeout: 120000, // 2 minutes
});
this.logger.info(`Batch execution completed`, {
batchId,
totalTools: toolCalls.length,
successCount: results.filter(r => r.success).length,
strategy: this.options.toolBatchingStrategy
});
return results;
}
async processToolCallsIndividually(toolCalls) {
const results = [];
for (const call of toolCalls) {
try {
const serverName = this.mapToolToMcpServer(call.name);
const result = await globalMcpManager.executeToolWithPooling(serverName, call.name, call.input);
results.push({
id: call.id,
success: true,
result,
});
}
catch (error) {
results.push({
id: call.id,
success: false,
error: error instanceof Error ? error.message : String(error),
});
}
}
return results;
}
mapToolToMcpServer(toolName) {
// Map Claude Code tools to MCP servers
const toolServerMap = {
'Bash': 'terminal',
'BashOutput': 'terminal',
'FileRead': 'filesystem',
'FileWrite': 'filesystem',
'FileEdit': 'filesystem',
'Glob': 'filesystem',
'Grep': 'filesystem',
'WebFetch': 'web-search',
'WebSearch': 'web-search',
'ListMcpResources': 'filesystem',
'ReadMcpResource': 'filesystem',
'Mcp': 'filesystem', // Default fallback
};
return toolServerMap[toolName] || 'filesystem';
}
analyzeDependencies(currentTool, allTools) {
const dependencies = [];
const currentIndex = allTools.findIndex(t => t.id === currentTool.id);
// Simple dependency analysis based on tool types
for (let i = 0; i < currentIndex; i++) {
const previousTool = allTools[i];
// File operations depend on previous file operations on the same file
if (this.isFileOperation(currentTool.name) && this.isFileOperation(previousTool.name)) {
const currentFile = this.extractFilePath(currentTool.input);
const previousFile = this.extractFilePath(previousTool.input);
if (currentFile && previousFile && currentFile === previousFile) {
dependencies.push(previousTool.id);
}
}
// Web operations can depend on previous Bash operations (e.g., setup)
if (currentTool.name === 'WebSearch' && previousTool.name === 'Bash') {
dependencies.push(previousTool.id);
}
}
return dependencies;
}
isFileOperation(toolName) {
return ['FileRead', 'FileWrite', 'FileEdit', 'Glob', 'Grep'].includes(toolName);
}
extractFilePath(input) {
return (input.file_path || input.path || input.file);
}
/**
* Get comprehensive health and performance metrics
*/
getEnhancedHealthStatus() {
return {
baseHealth: this.getHealthStatus(),
mcpStats: globalMcpManager.getStats(),
batchStats: globalToolBatcher.getBatchStats(),
contextStats: this.contextOptimizer.getOptimizationStats(),
};
}
/**
* Cleanup enhanced components
*/
async destroy() {
this.logger.info('Destroying enhanced agent components');
// Clear tool batches
globalToolBatcher.clearPendingBatches();
// Clear context optimizations
// (Context optimizer cleanup would be implemented here)
// Call parent destroy if it exists
if (super.destroy && typeof super.destroy === 'function') {
await super.destroy();
}
}
}
/**
* Factory function to create enhanced agent
*/
export function createEnhancedAgent(client, options) {
return new EnhancedClaudeACPAgent(client, options);
}
//# sourceMappingURL=enhanced-agent-integration.js.map