@agentdao/core
Version:
Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration
439 lines (438 loc) • 16.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.A2AProtocolSkill = void 0;
const axios_1 = __importDefault(require("axios"));
class A2AProtocolSkill {
constructor(config) {
this.activeTasks = new Map();
this.agentRegistry = new Map();
this.messageQueue = [];
this.isRunning = false;
this.config = config;
this.validateConfig();
}
/**
* Initialize the A2A Protocol skill
*/
async initialize() {
try {
// Register this agent in the A2A registry
if (this.config.discovery.enabled && this.config.discovery.autoRegister) {
await this.registerAgent();
}
// Start discovery service
if (this.config.discovery.enabled) {
await this.startDiscoveryService();
}
// Start message processing
this.startMessageProcessor();
console.log(`A2A Protocol initialized for agent: ${this.config.agentName}`);
}
catch (error) {
console.error('Failed to initialize A2A Protocol:', error);
throw error;
}
}
/**
* Register this agent in the A2A registry
*/
async registerAgent() {
const agent = {
id: this.config.agentId,
name: this.config.agentName,
description: this.config.agentDescription,
capabilities: this.config.capabilities,
endpoint: this.config.endpoint,
version: this.config.version,
framework: this.config.framework,
metadata: {
registeredAt: new Date().toISOString(),
lastHeartbeat: new Date().toISOString()
}
};
if (this.config.discovery.registryUrl) {
try {
await axios_1.default.post(`${this.config.discovery.registryUrl}/agents`, agent, {
headers: this.getAuthHeaders()
});
console.log(`Agent registered in A2A registry: ${this.config.agentName}`);
}
catch (error) {
console.warn('Failed to register agent in external registry:', error);
}
}
// Add to local registry
this.agentRegistry.set(this.config.agentId, agent);
}
/**
* Discover available agents
*/
async discoverAgents(filters) {
const discoveredAgents = [];
// Query external registry
if (this.config.discovery.registryUrl) {
try {
const response = await axios_1.default.get(`${this.config.discovery.registryUrl}/agents`, {
params: filters,
headers: this.getAuthHeaders()
});
discoveredAgents.push(...response.data.agents);
}
catch (error) {
console.warn('Failed to query external registry:', error);
}
}
// Add local registry agents
discoveredAgents.push(...Array.from(this.agentRegistry.values()));
// Apply filters
if (filters) {
return discoveredAgents.filter(agent => {
return Object.entries(filters).every(([key, value]) => {
if (key === 'capabilities') {
return Array.isArray(value)
? value.some(cap => agent.capabilities.includes(cap))
: agent.capabilities.includes(value);
}
return agent[key] === value;
});
});
}
return discoveredAgents;
}
/**
* Send a task to another agent
*/
async delegateTask(targetAgentId, task, options) {
const targetAgent = this.agentRegistry.get(targetAgentId);
if (!targetAgent) {
throw new Error(`Target agent not found: ${targetAgentId}`);
}
const message = {
id: this.generateMessageId(),
fromAgent: this.config.agentId,
toAgent: targetAgentId,
task: {
...task,
id: this.generateTaskId(),
priority: options?.priority || 'medium',
timeout: options?.timeout || this.config.taskManagement.taskTimeout
},
timestamp: new Date(),
status: 'pending',
metadata: options?.metadata
};
// Add to active tasks
this.activeTasks.set(message.id, message);
try {
// Send task to target agent
const response = await axios_1.default.post(`${targetAgent.endpoint}/a2a/tasks`, message, {
headers: this.getAuthHeaders(),
timeout: message.task.timeout
});
// Update message status
message.status = 'processing';
this.activeTasks.set(message.id, message);
return message;
}
catch (error) {
message.status = 'failed';
message.error = error instanceof Error ? error.message : 'Unknown error';
this.activeTasks.set(message.id, message);
throw error;
}
}
/**
* Send a streaming task to another agent
*/
async streamTask(targetAgentId, task, onChunk, options) {
const targetAgent = this.agentRegistry.get(targetAgentId);
if (!targetAgent) {
throw new Error(`Target agent not found: ${targetAgentId}`);
}
const message = {
id: this.generateMessageId(),
fromAgent: this.config.agentId,
toAgent: targetAgentId,
task: {
...task,
id: this.generateTaskId(),
type: 'stream',
priority: options?.priority || 'medium',
timeout: options?.timeout || this.config.streaming.maxStreamDuration
},
timestamp: new Date(),
status: 'pending'
};
try {
// Use Server-Sent Events for streaming
const eventSource = new EventSource(`${targetAgent.endpoint}/a2a/stream/${message.id}`);
eventSource.onmessage = (event) => {
const chunk = JSON.parse(event.data);
onChunk(chunk);
if (chunk.isComplete) {
eventSource.close();
message.status = 'completed';
this.activeTasks.set(message.id, message);
}
};
eventSource.onerror = (error) => {
eventSource.close();
message.status = 'failed';
message.error = 'Streaming error';
this.activeTasks.set(message.id, message);
throw error;
};
// Send initial task
await axios_1.default.post(`${targetAgent.endpoint}/a2a/stream`, message, {
headers: this.getAuthHeaders(),
timeout: message.task.timeout
});
}
catch (error) {
message.status = 'failed';
message.error = error instanceof Error ? error.message : 'Unknown error';
this.activeTasks.set(message.id, message);
throw error;
}
}
/**
* Collaborate with multiple agents on a complex task
*/
async collaborate(agentIds, task, coordinationStrategy = 'parallel') {
const results = [];
switch (coordinationStrategy) {
case 'parallel':
// Execute tasks in parallel
const promises = agentIds.map(agentId => this.delegateTask(agentId, task).then(msg => this.waitForCompletion(msg.id)));
results.push(...await Promise.all(promises));
break;
case 'sequential':
// Execute tasks sequentially
for (const agentId of agentIds) {
const message = await this.delegateTask(agentId, task);
const result = await this.waitForCompletion(message.id);
results.push(result);
}
break;
case 'hierarchical':
// Execute with a coordinator agent
const coordinatorId = agentIds[0];
const subAgents = agentIds.slice(1);
const coordinationTask = {
...task,
id: this.generateTaskId(),
type: 'delegate',
input: {
...task.input,
subAgents,
coordinationType: 'hierarchical'
}
};
const message = await this.delegateTask(coordinatorId, coordinationTask);
const result = await this.waitForCompletion(message.id);
results.push(result);
break;
}
return results;
}
/**
* Wait for task completion
*/
async waitForCompletion(messageId, timeout) {
const startTime = Date.now();
const maxWait = timeout || this.config.taskManagement.taskTimeout;
while (Date.now() - startTime < maxWait) {
const message = this.activeTasks.get(messageId);
if (!message) {
throw new Error(`Message not found: ${messageId}`);
}
if (message.status === 'completed') {
return {
success: true,
data: message.result,
metadata: message.metadata,
executionTime: Date.now() - startTime
};
}
if (message.status === 'failed') {
return {
success: false,
error: message.error,
metadata: message.metadata,
executionTime: Date.now() - startTime
};
}
// Wait before checking again
await new Promise(resolve => setTimeout(resolve, 100));
}
throw new Error(`Task timeout: ${messageId}`);
}
/**
* Handle incoming tasks from other agents
*/
async handleIncomingTask(message) {
// Validate message
if (message.toAgent !== this.config.agentId) {
throw new Error('Message not intended for this agent');
}
// Check security
if (this.config.security.enabled) {
if (this.config.security.allowedAgents &&
!this.config.security.allowedAgents.includes(message.fromAgent)) {
throw new Error('Unauthorized agent');
}
}
// Process task based on type
switch (message.task.type) {
case 'delegate':
return await this.processDelegatedTask(message);
case 'collaborate':
return await this.processCollaborationTask(message);
case 'query':
return await this.processQueryTask(message);
case 'stream':
return await this.processStreamingTask(message);
default:
throw new Error(`Unknown task type: ${message.task.type}`);
}
}
/**
* Process delegated tasks
*/
async processDelegatedTask(message) {
try {
// This is where you would implement your agent's specific logic
// For now, we'll return a placeholder response
const result = {
taskId: message.task.id,
processedBy: this.config.agentName,
input: message.task.input,
output: `Task processed by ${this.config.agentName}`,
timestamp: new Date().toISOString()
};
// Update message status
message.status = 'completed';
message.result = result;
this.activeTasks.set(message.id, message);
return {
success: true,
data: result,
executionTime: Date.now() - message.timestamp.getTime()
};
}
catch (error) {
message.status = 'failed';
message.error = error instanceof Error ? error.message : 'Unknown error';
this.activeTasks.set(message.id, message);
return {
success: false,
error: message.error,
executionTime: Date.now() - message.timestamp.getTime()
};
}
}
/**
* Process collaboration tasks
*/
async processCollaborationTask(message) {
// Implement collaboration logic
return await this.processDelegatedTask(message);
}
/**
* Process query tasks
*/
async processQueryTask(message) {
// Implement query logic
return await this.processDelegatedTask(message);
}
/**
* Process streaming tasks
*/
async processStreamingTask(message) {
// Implement streaming logic
return await this.processDelegatedTask(message);
}
/**
* Get agent status and health
*/
getAgentStatus() {
return {
agentId: this.config.agentId,
agentName: this.config.agentName,
status: this.isRunning ? 'online' : 'offline',
activeTasks: this.activeTasks.size,
capabilities: this.config.capabilities,
lastHeartbeat: new Date()
};
}
/**
* Get task statistics
*/
getTaskStats() {
const tasks = Array.from(this.activeTasks.values());
const completed = tasks.filter(t => t.status === 'completed').length;
const failed = tasks.filter(t => t.status === 'failed').length;
const pending = tasks.filter(t => t.status === 'pending' || t.status === 'processing').length;
return {
totalTasks: tasks.length,
completedTasks: completed,
failedTasks: failed,
pendingTasks: pending,
averageExecutionTime: 0 // Calculate based on completed tasks
};
}
// Private helper methods
validateConfig() {
if (!this.config.agentId || !this.config.agentName || !this.config.endpoint) {
throw new Error('Missing required A2A configuration: agentId, agentName, endpoint');
}
}
getAuthHeaders() {
const headers = {
'Content-Type': 'application/json',
'User-Agent': `AgentDAO-A2A/${this.config.version}`
};
if (this.config.security.apiKey) {
headers['Authorization'] = `Bearer ${this.config.security.apiKey}`;
}
return headers;
}
generateMessageId() {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
generateTaskId() {
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
async startDiscoveryService() {
// Start periodic agent discovery
setInterval(async () => {
try {
const agents = await this.discoverAgents();
agents.forEach(agent => {
this.agentRegistry.set(agent.id, agent);
});
}
catch (error) {
console.warn('Discovery service error:', error);
}
}, this.config.discovery.heartbeatInterval);
}
startMessageProcessor() {
this.isRunning = true;
// Process message queue
setInterval(() => {
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
if (message) {
this.handleIncomingTask(message).catch(error => {
console.error('Failed to process message:', error);
});
}
}
}, 100);
}
}
exports.A2AProtocolSkill = A2AProtocolSkill;