mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-07 07:59:42 +02:00
feat: add AI-powered idle check for respawn controller
Replace the "Worked for Xm Xs" pattern as the sole primary idle detection signal with a final AI-powered check. When pre-filter conditions are met (output silence, no working patterns, tokens stable), a fresh Claude CLI session is spawned in a screen to analyze terminal output and provide a definitive IDLE/WORKING verdict before proceeding with the respawn cycle. New state in state machine: `ai_checking` (between pre-filter confirmation and `sending_update`). WORKING verdict triggers a 3-minute cooldown. Errors auto-disable after 3 consecutive failures, falling back to the existing noOutputTimeoutMs safety net. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -939,6 +939,36 @@ class ClaudemanApp {
|
||||
}
|
||||
});
|
||||
|
||||
this.eventSource.addEventListener('respawn:aiCheckStarted', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.sessionId === this.activeSessionId) {
|
||||
document.getElementById('respawnStep').textContent = 'AI Check: Analyzing...';
|
||||
}
|
||||
});
|
||||
|
||||
this.eventSource.addEventListener('respawn:aiCheckCompleted', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.sessionId === this.activeSessionId) {
|
||||
const icon = data.verdict === 'IDLE' ? '✓' : '⏳';
|
||||
document.getElementById('respawnStep').textContent = `AI Check: ${data.verdict} ${icon}`;
|
||||
}
|
||||
});
|
||||
|
||||
this.eventSource.addEventListener('respawn:aiCheckFailed', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.sessionId === this.activeSessionId) {
|
||||
document.getElementById('respawnStep').textContent = `AI Check: Error - ${data.error?.substring(0, 50)}`;
|
||||
}
|
||||
});
|
||||
|
||||
this.eventSource.addEventListener('respawn:aiCheckCooldown', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.sessionId === this.activeSessionId && data.active) {
|
||||
const remaining = Math.ceil((data.endsAt - Date.now()) / 1000);
|
||||
document.getElementById('respawnStep').textContent = `AI Check: WORKING (cooldown ${remaining}s)`;
|
||||
}
|
||||
});
|
||||
|
||||
// Respawn timer events
|
||||
this.eventSource.addEventListener('respawn:timerStarted', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
@@ -1904,6 +1934,26 @@ class ClaudemanApp {
|
||||
} else {
|
||||
confidenceEl.style.display = 'none';
|
||||
}
|
||||
|
||||
// Show AI check info if available
|
||||
const aiCheckEl = document.getElementById('detectionAiCheck');
|
||||
if (aiCheckEl && detection.aiCheck) {
|
||||
const ai = detection.aiCheck;
|
||||
let aiText = '';
|
||||
if (ai.status === 'checking') {
|
||||
aiText = 'AI: Analyzing...';
|
||||
} else if (ai.status === 'cooldown' && ai.cooldownEndsAt) {
|
||||
const remaining = Math.ceil((ai.cooldownEndsAt - Date.now()) / 1000);
|
||||
aiText = `AI: WORKING (${remaining}s cooldown)`;
|
||||
} else if (ai.status === 'disabled') {
|
||||
aiText = `AI: Disabled (${ai.disabledReason || 'errors'})`;
|
||||
} else if (ai.lastVerdict) {
|
||||
aiText = `AI: Last=${ai.lastVerdict}`;
|
||||
if (ai.lastCheckDurationMs) aiText += ` (${Math.round(ai.lastCheckDurationMs / 1000)}s)`;
|
||||
}
|
||||
aiCheckEl.textContent = aiText;
|
||||
aiCheckEl.style.display = aiText ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
showRespawnTimer() {
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<span class="detection-status" id="detectionStatus"></span>
|
||||
<span class="detection-waiting" id="detectionWaiting"></span>
|
||||
<span class="detection-confidence" id="detectionConfidence"></span>
|
||||
<span class="detection-ai-check" id="detectionAiCheck" style="display: none;"></span>
|
||||
</span>
|
||||
<span class="respawn-cycles">Cycle <span id="respawnCycleCount">0</span></span>
|
||||
<span class="respawn-timer" id="respawnTimer" style="display: none;"></span>
|
||||
|
||||
Reference in New Issue
Block a user