From 981f77b1ebcfb91e788516f1d6edc6a7e062e40a Mon Sep 17 00:00:00 2001 From: nogueiraguh Date: Thu, 12 Mar 2026 08:45:54 -0300 Subject: [PATCH] fix: Terraform Agent uses SQLite RAG only, terminal shows errors properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Skip ADB vector search for Terraform Agent (uses local SQLite resource reference instead) - Show error message in terminal when plan fails validation (no more stuck "Aguardando execução") - Write region validation error to plan_output field for terminal display - Fix Plan/Re-plan button visibility for all workspace states (including stuck planning/applying) --- backend/app.py | 6 +++--- frontend/index.html | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/app.py b/backend/app.py index a98df6d..98e47d1 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3962,7 +3962,7 @@ async def _chat_background(mid: str, sid: str, msg: ChatMsg, user: dict, genai_c log.info(f"RAG: filtering by tenancy '{rag_tenancy}'") rag_context = "" - adb_cfgs = _get_active_adb_configs(user["id"]) + adb_cfgs = _get_active_adb_configs(user["id"]) if agent_type != "terraform" else [] if adb_cfgs: all_documents = [] for adb_cfg in adb_cfgs: @@ -5176,8 +5176,8 @@ async def _terraform_exec(wid: str, action: str, user: dict): ) log.warning(f"Workspace {wid}: missing variable 'region' — blocking plan") with db() as c: - c.execute("UPDATE terraform_workspaces SET status='failed', error=?, updated_at=datetime('now') WHERE id=?", - (error_msg, wid)) + c.execute("UPDATE terraform_workspaces SET status='failed', plan_output=?, error=?, updated_at=datetime('now') WHERE id=?", + (error_msg, error_msg, wid)) return region_value = 'var.region' diff --git a/frontend/index.html b/frontend/index.html index 02d1151..5f93530 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1401,12 +1401,13 @@ function _tfBadge(st){ function rTfActions(){ if(S.tfRunning)return''; const st=S.tfStatus;let btns=''; - if(S.tfCode&&(st==='draft'||st==='failed'||st==='destroyed'))btns+=``; + const canPlan=S.tfCode&&['draft','failed','destroyed','planning','applying','destroying'].includes(st); + const canReplan=S.tfCode&&['planned','failed','applied'].includes(st); + if(canPlan&&!canReplan)btns+=``; + if(canReplan)btns+=``; if(st==='failed'&&S.tfPlanOut&&S.tfFiles.length&&S.tfModel)btns+=``; if(st==='failed'&&(S.tfApplyOut||S.tfHadApply))btns+=''; - if(st==='planned'||st==='failed')btns+=``; if(st==='planned')btns+=''; - if(st==='applied')btns+=``; if(st==='applied'||st==='planned')btns+=''; return btns; } @@ -1786,13 +1787,14 @@ async function tfPollExec(){ S.tfPlanOut=r.plan_output||S.tfPlanOut; S.tfApplyOut=r.apply_output||S.tfApplyOut; S.tfDestroyOut=r.destroy_output||S.tfDestroyOut; + S.tfError=r.error||''; S.tfStatus=r.status; const done=!['planning','applying','destroying'].includes(r.status); if(done){S.tfRunning=false;if(r.status==='destroyed')S.tfHadApply=false;} // Update only the terminal body without full re-render const t=document.getElementById('tfTermOut'); if(t){ - const content=S.tfDestroyOut||S.tfApplyOut||S.tfPlanOut||''; + const content=S.tfDestroyOut||S.tfApplyOut||S.tfPlanOut||(done&&S.tfError?'ERROR: '+S.tfError:'')||''; t.innerHTML=content?escHtml(content):'Aguardando execução...'; t.scrollTop=t.scrollHeight; }