mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 19:12:58 +00:00
8.5 KiB
8.5 KiB
Agent Polling System Guide
This document explains how to use the reusable polling system for NetCop AI agents.
Overview
The agent polling system provides a standardized way to handle asynchronous requests in agent templates, with proper cleanup, error handling, and user feedback.
Key Features
- Automatic cleanup: Prevents memory leaks and duplicate polling
- Error handling: Handles network errors and timeouts gracefully
- Duplicate prevention: Ensures results are displayed only once
- Progressive feedback: Shows status steps for better UX
- Reusable utilities: Common functions for wallet updates, toasts, etc.
Basic Usage
1. Include the Script
Add to your agent template's extra_css block:
{% block extra_js %}
<script src="{% static 'js/agent-polling.js' %}"></script>
<script>
// Your agent-specific code here
</script>
{% endblock %}
2. Set Up Polling
// For agents that use async polling
function startPolling(requestId) {
const poller = window.pollingManager.createPoller('myAgent', {
requestId: requestId,
statusUrl: `/agents/my-agent/status/${requestId}/`,
maxPolls: 30,
pollInterval: 1000,
onComplete: (result) => {
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
resultsId: 'results',
buttonText: '🔄 Generate Again (5.00 AED)'
});
displayResults(result);
},
onError: (error) => {
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
buttonText: '🔄 Try Again (5.00 AED)'
});
AgentUtils.showToast('❌ Network error - please try again', 'error');
},
onTimeout: () => {
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
buttonText: '🔄 Try Again (5.00 AED)'
});
AgentUtils.showToast('❌ Processing timeout - please try again', 'error');
}
});
poller.start();
}
3. Handle Form Submission
document.getElementById('myForm').addEventListener('submit', function(e) {
e.preventDefault();
// Validation
if (!isFormValid()) {
AgentUtils.showToast('Please fill in all required fields', 'error');
return;
}
// Authentication check
if (!isAuthenticated) {
window.location.href = loginUrl;
return;
}
// Balance check
if (userBalance < requiredAmount) {
AgentUtils.showToast(`Insufficient balance! You need ${requiredAmount} AED.`, 'error');
setTimeout(() => window.location.href = walletUrl, 2000);
return;
}
// Clear any existing polling
window.pollingManager.stopAll();
// Show processing status
AgentUtils.showProcessing({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
resultsId: 'results',
processingText: '⏳ Processing...'
});
// Start status steps
const stepper = new StatusStepper([
'Analyzing request...',
'Processing data...',
'Generating results...',
'Finalizing output...'
], 'statusText');
stepper.start();
// Submit form
const formData = new FormData(this);
fetch(submitUrl, {
method: 'POST',
body: formData,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(response => response.json())
.then(result => {
stepper.stop();
if (result.success && result.request_id) {
// Start polling for async agents
startPolling(result.request_id);
} else {
// Handle immediate response
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
buttonText: '🔄 Try Again (5.00 AED)'
});
if (result.error) {
AgentUtils.showToast(`❌ ${result.error}`, 'error');
} else {
displayResults(result);
}
}
})
.catch(error => {
stepper.stop();
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
buttonText: '🔄 Try Again (5.00 AED)'
});
AgentUtils.showToast('❌ Network error - please try again', 'error');
});
});
4. Reset Function
function resetForm() {
// Stop all polling
window.pollingManager.stopAll();
// Reset form
document.getElementById('myForm').reset();
// Reset UI
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
resultsId: 'results',
buttonText: '🚀 Generate (5.00 AED)'
});
AgentUtils.showToast('Form reset! Ready for another request.', 'success');
}
API Reference
AgentPoller Class
const poller = new AgentPoller({
requestId: 'string', // Request ID to poll
statusUrl: 'string', // Status endpoint URL
maxPolls: 30, // Maximum poll attempts
pollInterval: 1000, // Poll interval in ms
onComplete: function(result) {}, // Success callback
onError: function(error) {}, // Error callback
onTimeout: function() {} // Timeout callback
});
PollingManager
// Create and start a poller
const poller = window.pollingManager.createPoller('pollerId', config);
poller.start();
// Stop specific poller
window.pollingManager.stopPoller('pollerId');
// Stop all pollers
window.pollingManager.stopAll();
AgentUtils
// Update wallet balance
AgentUtils.updateWalletBalance(150.00);
// Reset UI elements
AgentUtils.resetUI({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
resultsId: 'results',
buttonText: 'Process Again'
});
// Show processing state
AgentUtils.showProcessing({
processingStatusId: 'processingStatus',
processButtonId: 'processButton',
resultsId: 'results',
processingText: '⏳ Working...'
});
// Show toast notification
AgentUtils.showToast('Success message', 'success');
AgentUtils.showToast('Error message', 'error');
StatusStepper
const stepper = new StatusStepper([
'Step 1...',
'Step 2...',
'Step 3...'
], 'statusTextElementId', 800); // 800ms interval
stepper.start();
stepper.stop();
Migration Guide
Converting Existing Agents
- Include the script in your template
- Replace polling logic with
AgentPoller - Use
AgentUtilsfor common operations - Add proper cleanup in reset functions
- Use
StatusStepperfor better UX
Before (old way):
// Old polling code with potential issues
let pollInterval = setInterval(() => {
fetch(statusUrl)
.then(response => response.json())
.then(result => {
if (result.status === 'completed') {
clearInterval(pollInterval);
displayResults(result);
}
});
}, 1000);
After (new way):
// New robust polling
const poller = window.pollingManager.createPoller('agent', {
requestId: requestId,
statusUrl: statusUrl,
onComplete: displayResults,
onError: handleError,
onTimeout: handleTimeout
});
poller.start();
Best Practices
- Always stop existing polling before starting new requests
- Use unique poller IDs for different agents/features
- Provide clear error messages to users
- Set appropriate timeouts based on expected processing time
- Clean up resources in reset functions
- Use progressive status steps for better UX
- Prevent duplicate submissions with proper state management
Troubleshooting
Common Issues
- Multiple polling instances: Use
pollingManager.stopAll()before starting new requests - Memory leaks: Always call
stop()or use the manager's cleanup methods - Duplicate results: The system prevents this automatically
- Network errors: Handled automatically with proper user feedback
Debug Mode
Enable debug logging:
// In development
window.agentPollingDebug = true;
This will log polling activities to the console for debugging.