diff --git a/cortex/routers/chat.py b/cortex/routers/chat.py
index 69291e8..9650fe5 100644
--- a/cortex/routers/chat.py
+++ b/cortex/routers/chat.py
@@ -23,6 +23,7 @@ class ChatRequest(BaseModel):
include_long: bool = True
include_mid: bool = True
include_short: bool = True
+ off_record: bool = False # skip session log (in-memory context preserved)
user: str = "scott"
persona: str = "inara"
@@ -92,7 +93,8 @@ async def _stream_chat(req: ChatRequest):
response_text, actual_backend = task.result()
history.append({"role": "assistant", "content": response_text})
save_session(session_id, history)
- log_turn(session_id, req.message, response_text)
+ if not req.off_record:
+ log_turn(session_id, req.message, response_text)
requested = req.model or settings.primary_backend
payload = {
diff --git a/cortex/static/app.js b/cortex/static/app.js
index 6181d12..dc134db 100644
--- a/cortex/static/app.js
+++ b/cortex/static/app.js
@@ -80,11 +80,35 @@
agentModeBtnEl.addEventListener('click', () => {
agentMode = !agentMode;
+ if (agentMode) { otr_mode = false; update_otr_ui(); }
localStorage.setItem('agentMode', agentMode);
updateAgentModeUI();
inputEl.focus();
});
+ // ── Off the record mode ──────────────────────────────────────
+ let otr_mode = false;
+ const otr_btn_el = document.getElementById('otr-btn');
+
+ function update_otr_ui() {
+ otr_btn_el.classList.toggle('active', otr_mode);
+ inputEl.classList.toggle('otr-mode', otr_mode);
+ updateInputPlaceholder();
+ }
+
+ otr_btn_el.addEventListener('click', () => {
+ otr_mode = !otr_mode;
+ if (otr_mode) {
+ agentMode = false;
+ noteMode = false;
+ localStorage.setItem('agentMode', false);
+ updateAgentModeUI();
+ updateInputMode();
+ }
+ update_otr_ui();
+ inputEl.focus();
+ });
+
// ── Note mode ────────────────────────────────────────────────
let noteMode = false;
let notePublic = false;
@@ -124,6 +148,8 @@
inputEl.placeholder = ctrlEnterMode
? `Task for ${personaLabel}… (Gemini tool loop — Ctrl+Enter to run)`
: `Task for ${personaLabel}… (Gemini tool loop)`;
+ } else if (otr_mode) {
+ inputEl.placeholder = `Off the record — not logged or distilled…`;
} else {
inputEl.placeholder = ctrlEnterMode
? `Message ${personaLabel}… (Ctrl+Enter to send)`
@@ -133,6 +159,7 @@
noteBtnEl.addEventListener('click', () => {
noteMode = !noteMode;
+ if (noteMode) { otr_mode = false; update_otr_ui(); }
updateInputMode();
inputEl.focus();
});
@@ -690,6 +717,7 @@
include_long: memLong,
include_mid: memMid,
include_short: memShort,
+ off_record: otr_mode,
user: CORTEX_USER,
persona: CORTEX_PERSONA,
}),
diff --git a/cortex/static/index.html b/cortex/static/index.html
index 6c52c50..b707335 100644
--- a/cortex/static/index.html
+++ b/cortex/static/index.html
@@ -131,6 +131,7 @@
+
diff --git a/cortex/static/style.css b/cortex/static/style.css
index 1536b8b..ed7f801 100644
--- a/cortex/static/style.css
+++ b/cortex/static/style.css
@@ -571,6 +571,27 @@
#note-btn.active { border-color: rgba(180, 130, 40, 0.6); color: #c9a84c; }
#note-btn.active.public { border-color: rgba(40, 170, 150, 0.6); color: #4abfb0; }
+ /* OTR button */
+ #otr-btn {
+ background: var(--bg);
+ border: 1px solid var(--border);
+ color: var(--muted);
+ border-radius: 8px;
+ padding: 8px 0;
+ cursor: pointer;
+ font-size: 0.85rem;
+ text-align: center;
+ transition: border-color 0.15s, color 0.15s;
+ }
+ #otr-btn:hover { border-color: var(--muted); color: var(--text); }
+ #otr-btn.active { border-color: rgba(120, 80, 160, 0.6); color: #a87fd4; }
+
+ /* OTR textarea styling */
+ #input.otr-mode {
+ border-color: rgba(120, 80, 160, 0.4);
+ background: rgba(120, 80, 160, 0.04);
+ }
+
/* Send button */
#send {
background: var(--user-bg);