feat: improve conductor controls and token import refresh

This commit is contained in:
Liang Jiaqing committed 2026-07-23 13:25:22 +08:00
1 parent 733615d889
commit 7fede5a050
5 files changed
+27 -10

No files matched your search

+5 -1
View File
@@ -76,6 +76,7 @@
}
.title { font-size: 17px; letter-spacing: .2px; font-weight: 700; }
.hint { color: var(--muted); font-size: 12px; }
#llm { max-width: 42vw; margin-left: 10px; padding: 4px 6px; border: 1px solid #dfe5ee; border-radius: 6px; background: #fff; font: 600 12px inherit; }
.cards {
flex: 1;
@@ -312,7 +313,7 @@
<!-- 聊天 -->
<section class="pane chat">
<div class="head">
<div class="title">Conversation</div>
<div class="title">Conversation <select id="llm" aria-label="Conductor model" disabled></select></div>
<div class="hint" id="wsStatus">connecting...</div>
</div>
<div class="messages" id="messages"></div>
@@ -331,6 +332,7 @@
const messagesEl = document.getElementById('messages');
const inputEl = document.getElementById('input');
const sendBtn = document.getElementById('send');
const llmEl = document.getElementById('llm');
const wsStatus = document.getElementById('wsStatus');
const apprEl = document.getElementById('approvals');
const apprBody = document.getElementById('approvalsBody');
@@ -452,6 +454,7 @@
renderCards(data.subagents||[]);
messagesEl.innerHTML=''; (data.chat||[]).forEach(addMsg);
renderLog(data.log||[]);
llmEl.innerHTML=(data.llms||[]).map(x=>`<option value="${x[0]}">${esc(x[1])}</option>`).join(''); llmEl.value=data.llm; llmEl.disabled=!llmEl.options.length;
} else if(data.type==='subagents'){ renderCards(data.items||[]); }
else if(data.type==='chat'){ addMsg(data.item); }
else if(data.type==='chat_read'){ markAllRead(); }
@@ -465,6 +468,7 @@
ws.send(JSON.stringify({msg})); inputEl.value=''; inputEl.focus();
}
sendBtn.addEventListener('click', send);
llmEl.addEventListener('change', ()=>{ if(ws?.readyState===1) ws.send(JSON.stringify({llm:+llmEl.value})); });
inputEl.addEventListener('keydown', e=>{ if(e.key==='Enter' && !e.shiftKey && !e.isComposing && e.keyCode!==229){ e.preventDefault(); send(); } });
// Input length limit (10000 chars)
+9 -6
View File
@@ -414,7 +414,6 @@ API: {base};requests,GET /readme查用法,GET /chat读未读对话,GET /
return
def _run(self):
self.agent = GenericAgent()
self.agent.inc_out = True
start_agent_runner(self.agent, "conductor-agent")
self.started = True
@@ -431,18 +430,19 @@ API: {base};requests,GET /readme查用法,GET /chat读未读对话,GET /
self.inbox.task_done()
except Exception:
break
kind = first.get("type"); others = [e for e in events if e.get("type") != kind]; events = [e for e in events if e.get("type") == kind] or [first]
for e in others: self.inbox.put(e)
try:
prompt = self._build_prompt(events)
# Follow the desktop-selected model live: re-read before each task
# so switching models in the UI takes effect without restarting.
_apply_desktop_model(self.agent)
dq = self.agent.put_task(prompt, source="conductor")
self._drain(dq, events)
except Exception as e:
print(f"Conductor error: {e}")
add_chat(f"⚠ 回复失败:{e}", role="error")
def start(self): threading.Thread(target=self._run, name="conductor-loop", daemon=True).start()
def start(self):
self.agent = GenericAgent(); _apply_desktop_model(self.agent)
threading.Thread(target=self._run, name="conductor-loop", daemon=True).start()
conductor = Conductor()
@@ -573,9 +573,12 @@ async def websocket(ws: WebSocket):
ws_clients.add(ws)
try:
running = any(s.status == "running" for s in pool.subagents.values())
await ws.send_json({"type": "hello", "subagents": pool.snapshot(), "chat": chat_messages, "log": conductor.log, "running": running})
await ws.send_json({"type": "hello", "subagents": pool.snapshot(), "chat": chat_messages, "log": conductor.log, "running": running, "llms": conductor.agent.list_llms(), "llm": conductor.agent.llm_no})
while True:
data = await ws.receive_json()
if "llm" in data:
if type(n := data["llm"]) is int and 0 <= n < len(conductor.agent.list_llms()): conductor.agent.next_llm(n)
continue
msg = (data.get("msg") or "").strip()
if not msg: continue
add_chat(msg, role="user", files=data.get("files") or [], images=data.get("images") or [])
+11 -1
View File
@@ -775,7 +775,17 @@ if (pqEl) pqEl.addEventListener('click', (e) => {
const btn = e.target.closest('.pq-btn[data-provider]');
if (!btn) return;
e.preventDefault(); e.stopPropagation();
if (btn.dataset.provider === 'ga-token') { bridgeFetch('/subscription-portal', { method: 'POST', body: {} }); return; }
if (btn.dataset.provider === 'ga-token') {
window.ga.getMykeyContent().then(r => {
const base = r?.content || '', t0 = Date.now();
bridgeFetch('/subscription-portal', { method: 'POST', body: {} });
const timer = setInterval(async () => {
const cur = (await window.ga.getMykeyContent().catch(() => null))?.content;
if ((cur != null && cur !== base) || Date.now() - t0 > 3e5) { clearInterval(timer); if (cur !== base) await loadModelProfiles(); }
}, 3000);
});
return;
}
openAddModelFormForProvider(btn.dataset.provider);
});
// 「快速接入」卡片折叠/展开(向下箭头),状态记忆到 localStorage
+1 -1
View File
@@ -696,6 +696,6 @@
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" crossorigin="anonymous"></script>
<script src="phosphor-icons.js?v=2"></script>
<script src="i18n.js?v=3"></script>
<script src="app.js?v=220"></script>
<script src="app.js?v=221"></script>
</body>
</html>
+1 -1
View File
@@ -565,7 +565,7 @@ class GenericAgentHandler(BaseHandler):
prompt = f"\n### [WORKING MEMORY]\n{earlier}{history}"
prompt += f"\nCurrent turn: {self.current_turn}\n"
if self.working.get('key_info'): prompt += f"\n<key_info>{self.working.get('key_info')}</key_info>"
if self.working.get('related_sop'): prompt += f"\n有不清晰的地方请再次读取{self.working.get('related_sop')}"
#if self.working.get('related_sop'): prompt += f"\n有不清晰的地方请再次读取{self.working.get('related_sop')}"
if getattr(self.parent, 'verbose', False): self.print(prompt)
return prompt