UNPKG

grix-connector

Version:

Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.

2 lines (1 loc) 2.37 kB
import{log as t}from"../core/log/index.js";const l=3e3,n=6e4,i=10,r=300*1e3,o=6e4,p=1e4,h=3;class w{attempts=0;slowRetryTimer=null;respawnTimer=null;healthCheckTimer=null;healthFailures=0;get exhausted(){return this.attempts>=i}resetAttempts(){this.attempts=0}resetHealthFailures(){this.healthFailures=0}stopSlowRetry(){this.slowRetryTimer&&(clearTimeout(this.slowRetryTimer),this.slowRetryTimer=null)}stopHealthCheck(){this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=null)}stop(){this.stopSlowRetry(),this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null)}stopAll(){this.stopHealthCheck(),this.stop()}startHealthCheck(e){this.stopHealthCheck(),e.pingAgent&&(this.healthFailures=0,this.healthCheckTimer=setInterval(()=>{if(e.stopped){this.stopHealthCheck();return}if(!e.pingAgent){this.stopHealthCheck();return}e.agentAlive!==!1&&e.pingAgent(p).then(s=>{s?this.healthFailures=0:(this.healthFailures++,t.info(e.name,`Health check failed (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted, triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e)))}).catch(()=>{this.healthFailures++,t.info(e.name,`Health check error (${this.healthFailures}/${h})`),this.healthFailures>=h&&(t.error(e.name,"Health check exhausted (error), triggering respawn"),this.healthFailures=0,e.onAbortActiveRun&&e.onAbortActiveRun("health check exhausted"),this.scheduleRespawn(e))})},o))}scheduleRespawn(e){try{e.onCleanupAgent()}catch{}if(this.respawnTimer&&(clearTimeout(this.respawnTimer),this.respawnTimer=null),this.attempts++,this.attempts>i){t.error(e.name,`Max respawn attempts reached, will retry in ${r/1e3}s`),this.scheduleSlowRetry(e);return}const s=Math.min(l*2**(this.attempts-1),n);t.info(e.name,`Respawn attempt ${this.attempts}/${i} in ${s}ms`),this.respawnTimer=setTimeout(()=>{this.respawnTimer=null,!e.stopped&&e.onRespawnNeeded().catch(a=>{t.error(e.name,`Respawn failed: ${a}`),this.scheduleRespawn(e)})},s)}scheduleSlowRetry(e){this.stopSlowRetry(),this.slowRetryTimer=setTimeout(()=>{e.stopped||(t.info(e.name,"Slow retry: attempting respawn"),this.attempts=0,e.onRespawnNeeded().catch(s=>{t.error(e.name,`Slow retry failed: ${s}`),this.scheduleRespawn(e)}))},r)}}export{w as RespawnManager};