@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
473 lines (431 loc) • 18.7 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", { value: true });
exports.A2AProtocolWidget = A2AProtocolWidget;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
function A2AProtocolWidget({ config, className, style }) {
const [agents, setAgents] = (0, react_1.useState)([]);
const [selectedAgent, setSelectedAgent] = (0, react_1.useState)(null);
const [taskDescription, setTaskDescription] = (0, react_1.useState)('');
const [taskType, setTaskType] = (0, react_1.useState)('delegate');
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
const [messages, setMessages] = (0, react_1.useState)([]);
const [activeStreams, setActiveStreams] = (0, react_1.useState)(new Map());
// Discover agents on component mount
(0, react_1.useEffect)(() => {
discoverAgents();
}, []);
const discoverAgents = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/a2a/agents');
const data = await response.json();
setAgents(data.agents || []);
}
catch (error) {
console.error('Failed to discover agents:', error);
}
finally {
setIsLoading(false);
}
};
const delegateTask = async () => {
if (!selectedAgent || !taskDescription.trim()) {
alert('Please select an agent and enter a task description');
return;
}
try {
setIsLoading(true);
const task = {
type: taskType,
description: taskDescription,
input: { description: taskDescription },
priority: 'medium',
timeout: 30000
};
const message = {
id: `msg_${Date.now()}`,
fromAgent: config.agentId,
toAgent: selectedAgent.id,
task: { ...task, id: `task_${Date.now()}` },
timestamp: new Date(),
status: 'pending'
};
// Add to messages
setMessages(prev => [...prev, message]);
// Send task
const response = await fetch('/api/a2a/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
const result = await response.json();
// Update message status
setMessages(prev => prev.map(msg => msg.id === message.id
? { ...msg, status: 'completed', result: result.result }
: msg));
// Clear form
setTaskDescription('');
setSelectedAgent(null);
}
catch (error) {
console.error('Failed to delegate task:', error);
alert('Failed to delegate task');
}
finally {
setIsLoading(false);
}
};
const startStreamingTask = async () => {
if (!selectedAgent || !taskDescription.trim()) {
alert('Please select an agent and enter a task description');
return;
}
try {
setIsLoading(true);
const task = {
type: 'stream',
description: taskDescription,
input: { description: taskDescription },
priority: 'medium',
timeout: 60000
};
const message = {
id: `msg_${Date.now()}`,
fromAgent: config.agentId,
toAgent: selectedAgent.id,
task: { ...task, id: `task_${Date.now()}` },
timestamp: new Date(),
status: 'pending'
};
// Add to messages
setMessages(prev => [...prev, message]);
// Create stream
const response = await fetch('/api/a2a/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
const result = await response.json();
if (result.success) {
// Start listening to stream
listenToStream(result.streamId, message.id);
}
}
catch (error) {
console.error('Failed to start streaming task:', error);
alert('Failed to start streaming task');
}
finally {
setIsLoading(false);
}
};
const listenToStream = (streamId, messageId) => {
const eventSource = new EventSource(`/api/a2a/stream?streamId=${streamId}`);
eventSource.onmessage = (event) => {
const chunk = JSON.parse(event.data);
if (chunk.type === 'connection') {
console.log('Stream connected:', streamId);
}
else if (chunk.type === 'complete') {
console.log('Stream completed:', streamId);
eventSource.close();
// Update message status
setMessages(prev => prev.map(msg => msg.id === messageId
? { ...msg, status: 'completed' }
: msg));
}
else {
// Handle data chunk
setActiveStreams(prev => {
const newStreams = new Map(prev);
const stream = newStreams.get(streamId) || { chunks: [] };
stream.chunks.push(chunk);
newStreams.set(streamId, stream);
return newStreams;
});
}
};
eventSource.onerror = (error) => {
console.error('Stream error:', error);
eventSource.close();
};
};
const collaborateWithMultipleAgents = async () => {
const selectedAgents = agents.filter(agent => agent.capabilities.some(cap => ['collaboration', 'teamwork', 'coordination'].includes(cap.toLowerCase()))).slice(0, 3); // Limit to 3 agents
if (selectedAgents.length === 0) {
alert('No suitable agents found for collaboration');
return;
}
try {
setIsLoading(true);
const task = {
type: 'collaborate',
description: taskDescription,
input: {
description: taskDescription,
participants: selectedAgents.map(a => a.id)
},
priority: 'high',
timeout: 60000
};
// Send to each agent
const promises = selectedAgents.map(agent => {
const message = {
id: `msg_${Date.now()}_${agent.id}`,
fromAgent: config.agentId,
toAgent: agent.id,
task: { ...task, id: `task_${Date.now()}_${agent.id}` },
timestamp: new Date(),
status: 'pending'
};
setMessages(prev => [...prev, message]);
return fetch('/api/a2a/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
});
const results = await Promise.all(promises);
// Update message statuses
results.forEach((result, index) => {
const messageId = `msg_${Date.now()}_${selectedAgents[index].id}`;
setMessages(prev => prev.map(msg => msg.id === messageId
? { ...msg, status: 'completed' }
: msg));
});
}
catch (error) {
console.error('Failed to collaborate:', error);
alert('Failed to start collaboration');
}
finally {
setIsLoading(false);
}
};
return ((0, jsx_runtime_1.jsxs)("div", { className: `a2a-protocol-widget ${className || ''}`, style: style, children: [(0, jsx_runtime_1.jsxs)("div", { className: "a2a-header", children: [(0, jsx_runtime_1.jsx)("h3", { children: "A2A Protocol - Agent Collaboration" }), (0, jsx_runtime_1.jsx)("button", { onClick: discoverAgents, disabled: isLoading, className: "a2a-refresh-btn", children: isLoading ? 'Discovering...' : 'Refresh Agents' })] }), (0, jsx_runtime_1.jsxs)("div", { className: "a2a-content", children: [(0, jsx_runtime_1.jsxs)("div", { className: "a2a-section", children: [(0, jsx_runtime_1.jsxs)("h4", { children: ["Available Agents (", agents.length, ")"] }), (0, jsx_runtime_1.jsx)("div", { className: "a2a-agents-list", children: agents.map(agent => ((0, jsx_runtime_1.jsx)("div", { className: `a2a-agent ${selectedAgent?.id === agent.id ? 'selected' : ''}`, onClick: () => setSelectedAgent(agent), children: (0, jsx_runtime_1.jsxs)("div", { className: "agent-info", children: [(0, jsx_runtime_1.jsx)("strong", { children: agent.name }), (0, jsx_runtime_1.jsx)("p", { children: agent.description }), (0, jsx_runtime_1.jsx)("div", { className: "agent-capabilities", children: agent.capabilities.map(cap => ((0, jsx_runtime_1.jsx)("span", { className: "capability-tag", children: cap }, cap))) })] }) }, agent.id))) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "a2a-section", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Task Configuration" }), (0, jsx_runtime_1.jsxs)("div", { className: "a2a-task-form", children: [(0, jsx_runtime_1.jsxs)("select", { value: taskType, onChange: (e) => setTaskType(e.target.value), className: "a2a-select", children: [(0, jsx_runtime_1.jsx)("option", { value: "delegate", children: "Delegate Task" }), (0, jsx_runtime_1.jsx)("option", { value: "collaborate", children: "Collaborate" }), (0, jsx_runtime_1.jsx)("option", { value: "query", children: "Query" }), (0, jsx_runtime_1.jsx)("option", { value: "stream", children: "Stream" })] }), (0, jsx_runtime_1.jsx)("textarea", { value: taskDescription, onChange: (e) => setTaskDescription(e.target.value), placeholder: "Describe the task you want to delegate...", className: "a2a-textarea", rows: 3 }), (0, jsx_runtime_1.jsxs)("div", { className: "a2a-actions", children: [(0, jsx_runtime_1.jsx)("button", { onClick: delegateTask, disabled: !selectedAgent || !taskDescription.trim() || isLoading, className: "a2a-btn primary", children: isLoading ? 'Processing...' : 'Delegate Task' }), taskType === 'stream' && ((0, jsx_runtime_1.jsx)("button", { onClick: startStreamingTask, disabled: !selectedAgent || !taskDescription.trim() || isLoading, className: "a2a-btn secondary", children: "Start Streaming" })), (0, jsx_runtime_1.jsx)("button", { onClick: collaborateWithMultipleAgents, disabled: !taskDescription.trim() || isLoading, className: "a2a-btn tertiary", children: "Collaborate with Multiple Agents" })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "a2a-section", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Message History" }), (0, jsx_runtime_1.jsx)("div", { className: "a2a-messages", children: messages.map(message => ((0, jsx_runtime_1.jsxs)("div", { className: `a2a-message ${message.status}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "message-header", children: [(0, jsx_runtime_1.jsx)("span", { className: "message-type", children: message.task.type }), (0, jsx_runtime_1.jsx)("span", { className: "message-status", children: message.status }), (0, jsx_runtime_1.jsx)("span", { className: "message-time", children: message.timestamp.toLocaleTimeString() })] }), (0, jsx_runtime_1.jsxs)("div", { className: "message-content", children: [(0, jsx_runtime_1.jsxs)("p", { children: [(0, jsx_runtime_1.jsx)("strong", { children: "To:" }), " ", message.toAgent] }), (0, jsx_runtime_1.jsxs)("p", { children: [(0, jsx_runtime_1.jsx)("strong", { children: "Task:" }), " ", message.task.description] }), message.result && ((0, jsx_runtime_1.jsxs)("div", { className: "message-result", children: [(0, jsx_runtime_1.jsx)("strong", { children: "Result:" }), (0, jsx_runtime_1.jsx)("pre", { children: JSON.stringify(message.result, null, 2) })] }))] })] }, message.id))) })] }), activeStreams.size > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "a2a-section", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Active Streams" }), (0, jsx_runtime_1.jsx)("div", { className: "a2a-streams", children: Array.from(activeStreams.entries()).map(([streamId, stream]) => ((0, jsx_runtime_1.jsxs)("div", { className: "a2a-stream", children: [(0, jsx_runtime_1.jsxs)("h5", { children: ["Stream: ", streamId] }), (0, jsx_runtime_1.jsx)("div", { className: "stream-chunks", children: stream.chunks.map((chunk, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "stream-chunk", children: [(0, jsx_runtime_1.jsx)("span", { className: "chunk-data", children: chunk.chunk.data }), (0, jsx_runtime_1.jsxs)("span", { className: "chunk-progress", children: [chunk.chunk.progress, "%"] })] }, index))) })] }, streamId))) })] }))] }), (0, jsx_runtime_1.jsx)("style", { children: `
.a2a-protocol-widget {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
border: 1px solid #e1e5e9;
border-radius: 8px;
background: white;
max-width: 800px;
margin: 0 auto;
}
.a2a-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #e1e5e9;
background: #f8f9fa;
}
.a2a-header h3 {
margin: 0;
color: #2c3e50;
}
.a2a-refresh-btn {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.a2a-refresh-btn:disabled {
background: #6c757d;
cursor: not-allowed;
}
.a2a-content {
padding: 16px;
}
.a2a-section {
margin-bottom: 24px;
}
.a2a-section h4 {
margin: 0 0 12px 0;
color: #2c3e50;
}
.a2a-agents-list {
display: grid;
gap: 12px;
max-height: 200px;
overflow-y: auto;
}
.a2a-agent {
padding: 12px;
border: 1px solid #e1e5e9;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
}
.a2a-agent:hover {
border-color: #007bff;
background: #f8f9fa;
}
.a2a-agent.selected {
border-color: #007bff;
background: #e3f2fd;
}
.agent-info strong {
display: block;
margin-bottom: 4px;
}
.agent-info p {
margin: 4px 0;
color: #6c757d;
font-size: 14px;
}
.agent-capabilities {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 8px;
}
.capability-tag {
background: #e9ecef;
color: #495057;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
}
.a2a-task-form {
display: flex;
flex-direction: column;
gap: 12px;
}
.a2a-select,
.a2a-textarea {
padding: 8px 12px;
border: 1px solid #e1e5e9;
border-radius: 4px;
font-size: 14px;
}
.a2a-textarea {
resize: vertical;
min-height: 80px;
}
.a2a-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.a2a-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.a2a-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.a2a-btn.primary {
background: #007bff;
color: white;
}
.a2a-btn.secondary {
background: #6c757d;
color: white;
}
.a2a-btn.tertiary {
background: #28a745;
color: white;
}
.a2a-messages {
max-height: 300px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 12px;
}
.a2a-message {
padding: 12px;
border: 1px solid #e1e5e9;
border-radius: 6px;
background: #f8f9fa;
}
.a2a-message.completed {
border-color: #28a745;
background: #d4edda;
}
.a2a-message.failed {
border-color: #dc3545;
background: #f8d7da;
}
.message-header {
display: flex;
gap: 12px;
margin-bottom: 8px;
font-size: 12px;
}
.message-type {
background: #007bff;
color: white;
padding: 2px 8px;
border-radius: 12px;
}
.message-status {
background: #6c757d;
color: white;
padding: 2px 8px;
border-radius: 12px;
}
.message-time {
color: #6c757d;
}
.message-content p {
margin: 4px 0;
font-size: 14px;
}
.message-result {
margin-top: 8px;
padding: 8px;
background: white;
border-radius: 4px;
}
.message-result pre {
margin: 4px 0;
font-size: 12px;
white-space: pre-wrap;
}
.a2a-streams {
display: flex;
flex-direction: column;
gap: 12px;
}
.a2a-stream {
padding: 12px;
border: 1px solid #e1e5e9;
border-radius: 6px;
background: #f8f9fa;
}
.a2a-stream h5 {
margin: 0 0 8px 0;
color: #2c3e50;
}
.stream-chunks {
display: flex;
flex-direction: column;
gap: 4px;
}
.stream-chunk {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 8px;
background: white;
border-radius: 4px;
font-size: 12px;
}
.chunk-progress {
background: #007bff;
color: white;
padding: 2px 6px;
border-radius: 12px;
}
` })] }));
}