feat: improve conductor controls and token import refresh
This commit is contained in:
1 parent
733615d889
commit
7fede5a050
5 files changed
+27
-10
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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 [])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user