generalbots/botui/ui/suite/vibe/vibe-websocket.js
Rodrigo Rodriguez (Pragmatismo) 28c48eeabf feat: Split chat.html into modular JS modules for #495 switcher support
- Split partials/chat.html (1513→70 lines) into 8 JS modules:
  chat-state.js, chat-switchers.js, chat-mentions.js,
  chat-messages.js, chat-suggestions.js, chat-theme.js,
  chat-websocket.js, chat-init.js
- Centralized state in ChatState global object
- Switcher chips auto-activate on switch_context suggestion action
- active_switchers sent in every WS message payload
- Removed old chat-main.js (merged into modules)
- Split vibe.html into vibe/ module directory with CSS extraction
- Updated standalone chat/chat.html to use same modules
2026-04-25 07:03:26 -03:00

271 lines
5 KiB
JavaScript

function connectVibeWs() {
setVibeStatus("connecting");
var botName = window.__INITIAL_BOT_NAME__ || "default";
fetch("/api/auth?bot_name=" + encodeURIComponent(botName))
.then(function (r) {
return r.json();
})
.then(function (auth) {
vibeUserId = auth.user_id;
vibeSessionId = auth.session_id;
vibeBotId = auth.bot_id || "default";
vibeBotName = botName;
var proto =
location.protocol === "https:" ? "wss://" : "ws://";
var url =
proto +
location.host +
"/ws?session_id=" +
vibeSessionId +
"&user_id=" +
vibeUserId +
"&bot_name=" +
vibeBotName;
vibeWs = new WebSocket(url);
vibeWs.onopen = function () {
setVibeStatus("connected");
};
vibeWs.onmessage = function (event) {
try {
var data = JSON.parse(event.data);
if (data.type === "connected") return;
if (data.event) return;
if (data.type === "thought_process") {
vibeAddMsg("system", "💭 " + esc(data.content));
return;
}
if (data.type === "terminal_output") {
vibeAddMsg("system", "🖥️ " + esc(data.line));
return;
}
if (data.type === "step_progress") {
var pct = Math.round(
(data.current / data.total) * 100,
);
updateMantis1("working");
var bar = document.querySelector(
'.as-agent-card[data-agent-id="1"] .as-bar-fill',
);
if (bar) bar.style.width = pct + "%";
return;
}
if (data.message_type === 2) {
if (data.is_complete) {
if (vibeStreaming) {
vibeFinalizeStream();
} else if (
data.content &&
data.content.trim()
) {
vibeAddMsg("bot", data.content);
}
vibeStreaming = false;
} else {
if (!vibeStreaming) {
vibeStreaming = true;
vibeAddStreamStart();
vibeUpdateStream(data.content || "");
} else {
vibeUpdateStream(data.content || "");
}
}
}
} catch (e) {
console.error("Vibe WS parse error:", e);
}
};
vibeWs.onclose = function () {
setVibeStatus("disconnected");
};
vibeWs.onerror = function () {
setVibeStatus("disconnected");
};
})
.catch(function () {
setVibeStatus("disconnected");
vibeAddMsg(
"system",
"⚠️ Could not connect to backend. You can still plan offline.",
);
});
}
function vibeSendWs(content) {
if (vibeWs && vibeWs.readyState === WebSocket.OPEN) {
vibeWs.send(
JSON.stringify({
bot_id: vibeBotId,
user_id: vibeUserId,
session_id: vibeSessionId,
channel: "web",
content: content,
message_type: 1,
timestamp: new Date().toISOString(),
}),
);
}
}
function connectTaskProgressWs(taskId) {
var proto = location.protocol === "https:" ? "wss://" : "ws://";
var url =
proto +
location.host +
"/ws/task-progress" +
(taskId ? "/" + taskId : "");
if (taskProgressWs) {
try {
taskProgressWs.close();
} catch (ignore) { }
}
taskProgressWs = new WebSocket(url);
taskProgressWs.onmessage = function (event) {
try {
var data = JSON.parse(event.data);
if (data.type === "connected") return;
if (
data.event_type === "agent_thought" ||
data.step === "agent_thought"
) {
var agentLabel = (data.details || "mantis_1").replace(
"mantis_",
"Mantis #",
);
vibeAddMsg(
"system",
"💭 " +
agentLabel +
": " +
esc(data.text || data.message || ""),
);
return;
}
if (
data.event_type === "agent_update" ||
data.step === "agent_update"
) {
try {
var info =
typeof data.details === "string"
? JSON.parse(data.details)
: data.details;
if (info) {
updateAgentCard(
info.agent_id,
info.status,
info.detail,
);
}
} catch (ignore) { }
return;
}
if (
data.event_type === "task_node" ||
data.step === "task_node"
) {
try {
var nodeInfo =
typeof data.details === "string"
? JSON.parse(data.details)
: data.details;
if (nodeInfo) {
addTaskNode(
nodeInfo.title || data.message || "Task",
nodeInfo.description || "",
{
status: nodeInfo.status || "Planning",
estimated_files:
nodeInfo.estimated_files,
estimated_time:
nodeInfo.estimated_time,
estimated_tokens:
nodeInfo.estimated_tokens,
fileList: nodeInfo.files || [],
},
);
}
} catch (ignore) {
addTaskNode(data.message || "Task", "", {
status: "Planning",
});
}
return;
}
if (
data.event_type === "step_progress" ||
data.step === "step_progress"
) {
var pct = 0;
if (data.current_step && data.total_steps) {
pct = Math.round(
(data.current_step / data.total_steps) * 100,
);
} else if (data.current && data.total) {
pct = Math.round((data.current / data.total) * 100);
}
updateMantis1("working");
var bar = document.querySelector(
'.as-agent-card[data-agent-id="1"] .as-bar-fill',
);
if (bar) bar.style.width = pct + "%";
var stageMap = {
Planning: "plan",
Building: "build",
Reviewing: "review",
Deploying: "deploy",
Monitoring: "monitor",
};
var stageLabel = data.message || "";
var tabStage = stageMap[stageLabel];
if (tabStage) {
var allTabs =
document.querySelectorAll(".vibe-pipeline-tab");
allTabs.forEach(function (t) {
t.classList.remove("active");
});
var activeTab = document.querySelector(
'.vibe-pipeline-tab[data-stage="' +
tabStage +
'"]',
);
if (activeTab) activeTab.classList.add("active");
}
return;
}
if (
data.event_type === "pipeline_complete" ||
data.step === "pipeline_complete"
) {
updateMantis1("done");
vibeAddMsg(
"system",
"✅ Pipeline complete — all stages finished",
);
return;
}
if (data.event_type === "manifest_update") {
return;
}
} catch (e) {
console.error("Task progress parse error:", e);
}
};
taskProgressWs.onerror = function () { };
taskProgressWs.onclose = function () { };
}