feat: replace Agent mode with independent Tools toggle
- Remove 'agent' from mode dropdown; Chat/Note/OTR remain - Add ⚡ tools toggle button in input bar (persisted in localStorage) When on: routes to POST /orchestrate (Gemini tool loop); send btn → "Run" When off: routes to POST /chat (direct to active role); no change - Role selector and tools toggle are now fully independent: active chat_role sent in orchestrate payload → used for final response - orchestrator_engine.run() accepts response_role param; passes it to complete(role=...) instead of hardcoded model="claude" - OrchestrateRequest gains chat_role field (default "chat") - Migrate stored 'agent' mode/MRU entries to 'chat' on load Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,7 @@ async def run(
|
||||
respond_with_claude: bool = True,
|
||||
gemini_api_key: str | None = None,
|
||||
model_name: str | None = None,
|
||||
response_role: str = "chat",
|
||||
) -> OrchestratorResult:
|
||||
"""
|
||||
Run the full orchestration loop for a task.
|
||||
@@ -176,7 +177,7 @@ async def run(
|
||||
response_text, backend = await complete(
|
||||
system_prompt=system_prompt,
|
||||
messages=messages,
|
||||
model="claude",
|
||||
role=response_role,
|
||||
)
|
||||
else:
|
||||
# Cron/background tasks: return Gemini's summary directly, no Claude call
|
||||
|
||||
@@ -52,6 +52,7 @@ class OrchestrateRequest(BaseModel):
|
||||
include_short: bool = True
|
||||
user: str = "scott"
|
||||
persona: str = "inara"
|
||||
chat_role: str = "chat" # role used for the final response (decoupled from tool-loop model)
|
||||
|
||||
|
||||
class OrchestrateResponse(BaseModel):
|
||||
@@ -184,6 +185,7 @@ async def _run_job(job_id: str, req: OrchestrateRequest, user: str) -> None:
|
||||
respond_with_claude=req.respond_with_claude,
|
||||
gemini_api_key=gemini_key,
|
||||
model_name=orch_model.get("model_name") if orch_model else None,
|
||||
response_role=req.chat_role,
|
||||
)
|
||||
|
||||
# Save the turn to the session store so it survives a page refresh
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
const mode_icon_el = document.getElementById('mode-icon');
|
||||
const mode_label_el = document.getElementById('mode-label');
|
||||
const note_vis_btn_el = document.getElementById('note-vis-btn');
|
||||
const tools_toggle_el = document.getElementById('tools-toggle');
|
||||
const settings_btn_el = document.getElementById('settings-btn');
|
||||
const settings_dd_el = document.getElementById('settings-dropdown');
|
||||
const sessionsBackdrop = document.getElementById('sessions-backdrop');
|
||||
@@ -151,22 +152,22 @@
|
||||
|
||||
// ── Input mode — dropdown select with MRU ordering ──────────
|
||||
const MODES = {
|
||||
chat: { icon: 'message-circle', label: 'Chat' },
|
||||
note: { icon: 'pencil', label: 'Note' },
|
||||
otr: { icon: 'lock', label: 'OTR' },
|
||||
agent: { icon: 'bot', label: 'Agent' },
|
||||
chat: { icon: 'message-circle', label: 'Chat' },
|
||||
note: { icon: 'pencil', label: 'Note' },
|
||||
otr: { icon: 'lock', label: 'OTR' },
|
||||
};
|
||||
const send_defs = {
|
||||
chat: { icon: 'arrow-up', label: 'Send' },
|
||||
note: { icon: 'pencil', label: 'Note' },
|
||||
otr: { icon: 'arrow-up', label: 'Send' },
|
||||
agent: { icon: 'zap', label: 'Run' },
|
||||
chat: { icon: 'arrow-up', label: 'Send' },
|
||||
note: { icon: 'pencil', label: 'Note' },
|
||||
otr: { icon: 'arrow-up', label: 'Send' },
|
||||
};
|
||||
|
||||
let current_mode = localStorage.getItem('current_mode') || 'chat';
|
||||
if (!(current_mode in MODES)) current_mode = 'chat'; // migrate stored 'agent'
|
||||
let note_public = false;
|
||||
// MRU list — most recent first; used to sort dropdown options
|
||||
let mode_mru = JSON.parse(localStorage.getItem('mode_mru') || '["chat","note","otr","agent"]');
|
||||
let mode_mru = JSON.parse(localStorage.getItem('mode_mru') || '["chat","note","otr"]');
|
||||
mode_mru = mode_mru.filter(m => m in MODES); // strip stale 'agent' entries
|
||||
|
||||
function push_mru(mode) {
|
||||
mode_mru = [mode, ...mode_mru.filter(m => m !== mode)];
|
||||
@@ -219,7 +220,7 @@
|
||||
});
|
||||
|
||||
function update_mode_ui() {
|
||||
const m = MODES[current_mode];
|
||||
const m = MODES[current_mode] || MODES.chat;
|
||||
const sd = send_defs[current_mode] || send_defs.chat;
|
||||
|
||||
// Update trigger button
|
||||
@@ -235,13 +236,15 @@
|
||||
note_vis_btn_el.classList.toggle('pub', note_public);
|
||||
|
||||
// Textarea mode classes
|
||||
inputEl.classList.toggle('mode-note', current_mode === 'note');
|
||||
inputEl.classList.toggle('public', current_mode === 'note' && note_public);
|
||||
inputEl.classList.toggle('mode-otr', current_mode === 'otr');
|
||||
inputEl.classList.toggle('mode-agent', current_mode === 'agent');
|
||||
inputEl.classList.toggle('mode-note', current_mode === 'note');
|
||||
inputEl.classList.toggle('public', current_mode === 'note' && note_public);
|
||||
inputEl.classList.toggle('mode-otr', current_mode === 'otr');
|
||||
|
||||
// Send button label + icon
|
||||
sendBtn.innerHTML = icon_html(sd.icon) + ' ' + sd.label;
|
||||
// Send button label + icon (tools active → "Run", otherwise per-mode)
|
||||
const effectiveSd = toolsEnabled && current_mode !== 'note'
|
||||
? { icon: 'zap', label: 'Run' }
|
||||
: sd;
|
||||
sendBtn.innerHTML = icon_html(effectiveSd.icon) + ' ' + effectiveSd.label;
|
||||
|
||||
render_icons();
|
||||
updateInputPlaceholder();
|
||||
@@ -252,12 +255,14 @@
|
||||
inputEl.placeholder = note_public
|
||||
? 'Public note — LLM sees this next turn…'
|
||||
: 'Private note — only you see this…';
|
||||
} else if (current_mode === 'agent') {
|
||||
inputEl.placeholder = ctrlEnterMode
|
||||
? `Task for ${personaLabel}… (orchestrator — Ctrl+Enter to run)`
|
||||
: `Task for ${personaLabel}… (orchestrator)`;
|
||||
} else if (current_mode === 'otr') {
|
||||
inputEl.placeholder = 'Off the record — not logged or distilled…';
|
||||
inputEl.placeholder = toolsEnabled
|
||||
? `Task for ${personaLabel}… ⚡ tools + off the record`
|
||||
: 'Off the record — not logged or distilled…';
|
||||
} else if (toolsEnabled) {
|
||||
inputEl.placeholder = ctrlEnterMode
|
||||
? `Task for ${personaLabel}… ⚡ tools (Ctrl+Enter to run)`
|
||||
: `Task for ${personaLabel}… ⚡ tools`;
|
||||
} else {
|
||||
inputEl.placeholder = ctrlEnterMode
|
||||
? `Message ${personaLabel}… (Ctrl+Enter to send)`
|
||||
@@ -272,6 +277,26 @@
|
||||
update_mode_ui();
|
||||
});
|
||||
|
||||
// ── Tools toggle ─────────────────────────────────────────────
|
||||
// When on: submit goes to POST /orchestrate (Gemini tool loop → active role responds).
|
||||
// When off: submit goes to POST /chat (direct to active role, no tools).
|
||||
let toolsEnabled = localStorage.getItem('tools-enabled') === 'true';
|
||||
|
||||
function updateToolsToggleUI() {
|
||||
tools_toggle_el.classList.toggle('local-on', toolsEnabled);
|
||||
tools_toggle_el.title = toolsEnabled
|
||||
? '⚡ Tools enabled — click to disable'
|
||||
: 'Tools disabled — click to enable';
|
||||
update_mode_ui();
|
||||
}
|
||||
|
||||
tools_toggle_el.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
toolsEnabled = !toolsEnabled;
|
||||
localStorage.setItem('tools-enabled', toolsEnabled);
|
||||
updateToolsToggleUI();
|
||||
});
|
||||
|
||||
// ── Settings dropdown ─────────────────────────────────────────
|
||||
settings_btn_el.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -1098,6 +1123,7 @@
|
||||
include_long: memLong,
|
||||
include_mid: memMid,
|
||||
include_short: memShort,
|
||||
chat_role: activeRole()?.role || 'chat',
|
||||
user: CORTEX_USER,
|
||||
persona: CORTEX_PERSONA,
|
||||
}),
|
||||
@@ -1171,7 +1197,7 @@
|
||||
|
||||
function dispatchSend() {
|
||||
if (current_mode === 'note') addNote();
|
||||
else if (current_mode === 'agent') sendOrchestrate();
|
||||
else if (toolsEnabled) sendOrchestrate();
|
||||
else sendMessage();
|
||||
}
|
||||
|
||||
@@ -1636,6 +1662,7 @@
|
||||
|
||||
updateTierUI();
|
||||
updateMemUI();
|
||||
updateToolsToggleUI();
|
||||
update_mode_ui();
|
||||
|
||||
// ── Init ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -176,6 +176,8 @@
|
||||
<div id="mode-dropdown"></div>
|
||||
<!-- Note visibility sub-toggle — only shown when note mode is active -->
|
||||
<button id="note-vis-btn" title="Toggle note visibility (private / public)">prv</button>
|
||||
<!-- Tools toggle — routes through the orchestrator tool loop when active -->
|
||||
<button id="tools-toggle" title="Tools disabled — click to enable">⚡</button>
|
||||
</div>
|
||||
<textarea id="input" rows="1" placeholder="Message…" autofocus></textarea>
|
||||
<div id="send-col">
|
||||
|
||||
Reference in New Issue
Block a user