Skip to content

Commit 30e6965

Browse files
darkspockclaude
andcommitted
Fix chat: dynamic API URL, remove auto-followup, fix busy state
- API URL auto-detects localhost vs production - Removed auto Director follow-up (was causing race conditions) - Added chatBusy flag to prevent overlapping requests - Human messages always get a response now Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f1fe128 commit 30e6965

1 file changed

Lines changed: 18 additions & 29 deletions

File tree

website/src/components/OrchestraNetwork.astro

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,13 @@
164164
});
165165

166166
// --- Chat ---
167-
// Chat calls go through the CronControl backend proxy (no API key in frontend)
167+
// Proxy URL: use app.croncontrol.dev in prod, localhost in dev
168+
const CHAT_API = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
169+
? 'http://localhost:8090/api/v1/chat/simulate'
170+
: 'https://app.croncontrol.dev/api/v1/chat/simulate';
168171
let chatHistory: { role: string; content: string }[] = [];
169172
let chatAbort: AbortController | null = null;
173+
let chatBusy = false;
170174

171175
function openChat(idx: number) {
172176
chatNodeIdx = idx;
@@ -177,18 +181,19 @@
177181
chatDot.style.backgroundColor = info.statusColor;
178182
chatMessages.innerHTML = '';
179183
chatHistory = [];
184+
chatBusy = false;
180185
tooltip.style.opacity = '0';
181186

182-
// Initial exchange: Director asks the node for status
187+
// Initial Director message
183188
const directorMsg = idx === 0
184-
? 'Orchestra "product-cleanup" is active. 3 AgentNodes running, 2 idle. Awaiting validator results before proceeding.'
185-
: `Director → ${info.name}: Report your current status.`;
189+
? 'Orchestra "product-cleanup" is active. 3 AgentNodes running, 2 idle. Awaiting validator results.'
190+
: `${info.name}, report your current status.`;
186191

187192
addMessage('director', directorMsg);
188193

189-
// Call Groq for the node's response
194+
// Set up system context and get first response
190195
chatHistory = [
191-
{ role: 'system', content: info.context + ' You are in a live orchestra chat. The AI Director just asked for your status. Respond naturally as this agent would.' },
196+
{ role: 'system', content: info.context + ' You are in a live orchestra chat. The AI Director just asked for your status. A human operator may also join the conversation. Respond concisely in 1-2 sentences.' },
192197
{ role: 'user', content: directorMsg },
193198
];
194199
callGroq();
@@ -198,6 +203,7 @@
198203
chatOpen = false;
199204
chatPanel.style.display = 'none';
200205
chatNodeIdx = -1;
206+
chatBusy = false;
201207
if (chatAbort) { chatAbort.abort(); chatAbort = null; }
202208
}
203209

@@ -224,19 +230,19 @@
224230
function esc(s: string) { return s.replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
225231

226232
async function callGroq() {
233+
if (chatBusy) return;
234+
chatBusy = true;
227235
if (chatAbort) chatAbort.abort();
228236
chatAbort = new AbortController();
229237

230-
// Show typing indicator
231238
const typing = document.createElement('div');
232239
typing.className = 'flex gap-2 items-center';
233-
typing.id = 'typing';
234240
typing.innerHTML = `<span class="shrink-0 w-5 h-5 rounded-full bg-emerald-500/20 flex items-center justify-center"><span class="text-[8px] font-bold text-emerald-400">A</span></span><span class="text-zinc-500 text-[10px]">typing...</span>`;
235241
chatMessages.appendChild(typing);
236242
chatMessages.scrollTop = chatMessages.scrollHeight;
237243

238244
try {
239-
const res = await fetch('https://app.croncontrol.dev/api/v1/chat/simulate', {
245+
const res = await fetch(CHAT_API, {
240246
method: 'POST',
241247
headers: { 'Content-Type': 'application/json' },
242248
body: JSON.stringify({ messages: chatHistory, max_tokens: 150 }),
@@ -247,28 +253,11 @@
247253
const reply = data.choices?.[0]?.message?.content || 'No response.';
248254
addMessage('agent', reply);
249255
chatHistory.push({ role: 'assistant', content: reply });
250-
251-
// After first response, Director follows up after a delay
252-
if (chatHistory.length <= 3) {
253-
setTimeout(() => {
254-
if (!chatOpen || chatNodeIdx < 0) return;
255-
const followUp = chatNodeIdx === 0
256-
? 'Checking budget: 62% used. 3 movements remaining within limits.'
257-
: `Director → ${nodeInfo[chatNodeIdx].name}: Acknowledged. Proceed with current task. Report when complete.`;
258-
addMessage('director', followUp);
259-
chatHistory.push({ role: 'user', content: followUp });
260-
callGroq();
261-
}, 2000);
262-
} else if (chatHistory.length <= 5) {
263-
// One more exchange
264-
setTimeout(() => {
265-
if (!chatOpen || chatNodeIdx < 0) return;
266-
addMessage('system', 'Movement #4 completed successfully.');
267-
}, 2500);
268-
}
269256
} catch (e: any) {
270257
typing.remove();
271-
if (e.name !== 'AbortError') addMessage('system', 'Connection error.');
258+
if (e.name !== 'AbortError') addMessage('system', 'Connection error. Is the backend running?');
259+
} finally {
260+
chatBusy = false;
272261
}
273262
}
274263

0 commit comments

Comments
 (0)