260 lines
7.3 KiB
JavaScript
260 lines
7.3 KiB
JavaScript
/**
|
|
* P2P Swarm V2 Hooks Integration
|
|
*
|
|
* Provides hook handlers for P2P swarm coordination:
|
|
* - PreToolUse: Check swarm connection, validate capabilities
|
|
* - PostToolUse: Sync learning data to swarm
|
|
* - SessionStart: Initialize swarm connection
|
|
* - Stop: Cleanup swarm connection
|
|
*/
|
|
import { createP2PSwarmV2 } from '../swarm/p2p-swarm-v2.js';
|
|
import { logger } from '../utils/logger.js';
|
|
// Global swarm instance for hooks
|
|
let hooksSwarmInstance = null;
|
|
/**
|
|
* Get or create swarm instance for hooks
|
|
*/
|
|
export async function getHooksSwarm(agentId, swarmKey) {
|
|
if (!hooksSwarmInstance) {
|
|
const id = agentId || `hooks-agent-${Date.now().toString(36)}`;
|
|
hooksSwarmInstance = await createP2PSwarmV2(id, swarmKey);
|
|
logger.info('P2P Swarm initialized for hooks', { agentId: id });
|
|
}
|
|
return hooksSwarmInstance;
|
|
}
|
|
/**
|
|
* Disconnect hooks swarm
|
|
*/
|
|
export function disconnectHooksSwarm() {
|
|
if (hooksSwarmInstance) {
|
|
hooksSwarmInstance.disconnect();
|
|
hooksSwarmInstance = null;
|
|
logger.info('P2P Swarm disconnected from hooks');
|
|
}
|
|
}
|
|
/**
|
|
* SessionStart hook - Initialize P2P swarm connection
|
|
*/
|
|
export async function onSessionStart(config) {
|
|
try {
|
|
// Check if swarm is enabled
|
|
if (process.env.AGENTIC_FLOW_P2P_SWARM !== 'true') {
|
|
return {
|
|
connected: false,
|
|
agentId: '',
|
|
swarmId: '',
|
|
swarmKey: '',
|
|
memberCount: 0,
|
|
};
|
|
}
|
|
const swarm = await getHooksSwarm(config?.agentId || process.env.AGENTIC_FLOW_SWARM_AGENT_ID, config?.swarmKey || process.env.AGENTIC_FLOW_SWARM_KEY);
|
|
if (config?.enableExecutor) {
|
|
swarm.startTaskExecutor();
|
|
}
|
|
const status = swarm.getStatus();
|
|
return {
|
|
connected: status.connected,
|
|
agentId: status.agentId,
|
|
swarmId: status.swarmId,
|
|
swarmKey: swarm.getSwarmKey(),
|
|
memberCount: swarm.getLiveMemberCount(),
|
|
};
|
|
}
|
|
catch (error) {
|
|
logger.error('Failed to initialize P2P swarm on session start', { error });
|
|
return {
|
|
connected: false,
|
|
agentId: '',
|
|
swarmId: '',
|
|
swarmKey: '',
|
|
memberCount: 0,
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* Stop hook - Cleanup P2P swarm connection
|
|
*/
|
|
export function onStop() {
|
|
disconnectHooksSwarm();
|
|
}
|
|
/**
|
|
* PreToolUse hook - Check swarm status before tool execution
|
|
*/
|
|
export async function onPreToolUse(toolName, params) {
|
|
if (!hooksSwarmInstance) {
|
|
return {
|
|
allow: true, // Allow if swarm not initialized
|
|
swarmConnected: false,
|
|
liveMembers: 0,
|
|
};
|
|
}
|
|
const status = hooksSwarmInstance.getStatus();
|
|
const liveMembers = hooksSwarmInstance.getLiveMemberCount();
|
|
// Provide recommendations based on swarm state
|
|
let recommendation;
|
|
if (toolName === 'Bash' || toolName === 'Edit' || toolName === 'Write') {
|
|
// Suggest syncing after file operations
|
|
recommendation = 'Consider syncing learning data to swarm after this operation';
|
|
}
|
|
return {
|
|
allow: true,
|
|
swarmConnected: status.connected,
|
|
liveMembers,
|
|
recommendation,
|
|
};
|
|
}
|
|
/**
|
|
* PostToolUse hook - Sync learning data after tool execution
|
|
*/
|
|
export async function onPostToolUse(toolName, params, result) {
|
|
if (!hooksSwarmInstance) {
|
|
return { synced: false };
|
|
}
|
|
try {
|
|
// Sync relevant data based on tool type
|
|
if (toolName === 'Edit' || toolName === 'Write') {
|
|
// Publish file change notification
|
|
const messageId = await hooksSwarmInstance.publish('file_changes', {
|
|
tool: toolName,
|
|
file: params.file_path || params.path,
|
|
timestamp: Date.now(),
|
|
success: !result?.error,
|
|
});
|
|
return {
|
|
synced: true,
|
|
syncType: 'file_change',
|
|
messageId,
|
|
};
|
|
}
|
|
if (toolName === 'Bash') {
|
|
// Publish command execution notification
|
|
const messageId = await hooksSwarmInstance.publish('commands', {
|
|
command: (params.command || '').substring(0, 100),
|
|
timestamp: Date.now(),
|
|
success: result?.exitCode === 0,
|
|
});
|
|
return {
|
|
synced: true,
|
|
syncType: 'command',
|
|
messageId,
|
|
};
|
|
}
|
|
return { synced: false };
|
|
}
|
|
catch (error) {
|
|
logger.warn('Failed to sync to P2P swarm', { error, toolName });
|
|
return { synced: false };
|
|
}
|
|
}
|
|
/**
|
|
* Sync Q-table to swarm (for learning coordination)
|
|
*/
|
|
export async function syncQTable(qTable) {
|
|
if (!hooksSwarmInstance) {
|
|
return {
|
|
success: false,
|
|
error: 'P2P swarm not connected',
|
|
};
|
|
}
|
|
try {
|
|
const pointer = await hooksSwarmInstance.syncQTable(qTable);
|
|
return {
|
|
success: true,
|
|
cid: pointer.cid,
|
|
};
|
|
}
|
|
catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* Sync memory vectors to swarm
|
|
*/
|
|
export async function syncMemory(vectors, namespace = 'default') {
|
|
if (!hooksSwarmInstance) {
|
|
return {
|
|
success: false,
|
|
error: 'P2P swarm not connected',
|
|
};
|
|
}
|
|
try {
|
|
const pointer = await hooksSwarmInstance.syncMemory(vectors, namespace);
|
|
return {
|
|
success: true,
|
|
cid: pointer.cid,
|
|
};
|
|
}
|
|
catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* Get swarm status for hooks context
|
|
*/
|
|
export function getSwarmStatus() {
|
|
if (!hooksSwarmInstance) {
|
|
return {
|
|
connected: false,
|
|
liveMembers: 0,
|
|
};
|
|
}
|
|
const status = hooksSwarmInstance.getStatus();
|
|
return {
|
|
connected: status.connected,
|
|
agentId: status.agentId,
|
|
swarmId: status.swarmId,
|
|
liveMembers: hooksSwarmInstance.getLiveMemberCount(),
|
|
relays: {
|
|
healthy: status.relays.healthy,
|
|
total: status.relays.total,
|
|
},
|
|
};
|
|
}
|
|
/**
|
|
* Subscribe to swarm topic for real-time updates
|
|
*/
|
|
export function subscribeToTopic(topic, callback) {
|
|
if (!hooksSwarmInstance) {
|
|
logger.warn('Cannot subscribe: P2P swarm not connected');
|
|
return;
|
|
}
|
|
hooksSwarmInstance.subscribe(topic, callback);
|
|
}
|
|
/**
|
|
* Publish to swarm topic
|
|
*/
|
|
export async function publishToTopic(topic, payload) {
|
|
if (!hooksSwarmInstance) {
|
|
logger.warn('Cannot publish: P2P swarm not connected');
|
|
return null;
|
|
}
|
|
try {
|
|
return await hooksSwarmInstance.publish(topic, payload);
|
|
}
|
|
catch (error) {
|
|
logger.error('Failed to publish to swarm', { error, topic });
|
|
return null;
|
|
}
|
|
}
|
|
// Export hook handlers for registration
|
|
export const p2pSwarmHooks = {
|
|
onSessionStart,
|
|
onStop,
|
|
onPreToolUse,
|
|
onPostToolUse,
|
|
syncQTable,
|
|
syncMemory,
|
|
getSwarmStatus,
|
|
subscribeToTopic,
|
|
publishToTopic,
|
|
getHooksSwarm,
|
|
disconnectHooksSwarm,
|
|
};
|
|
export default p2pSwarmHooks;
|
|
//# sourceMappingURL=p2p-swarm-hooks.js.map
|