Spaces:
Running
Running
deploy(S4): Blender headless pipeline + WebAR client + backend fixes
Browse files
backend/omega/research_engine.py
CHANGED
|
@@ -91,6 +91,33 @@ def _save_research_note(note: ResearchNote):
|
|
| 91 |
except Exception as e:
|
| 92 |
logging.error(f"ResearchEngine: DB save_note error: {e}")
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
def _save_proposal(proposal: PendingProposal):
|
| 96 |
try:
|
|
|
|
| 91 |
except Exception as e:
|
| 92 |
logging.error(f"ResearchEngine: DB save_note error: {e}")
|
| 93 |
|
| 94 |
+
# Mirror the note to any connected PC. The Space's disk is ephemeral — a
|
| 95 |
+
# rebuild restores the image-baked memory.db and everything learned since is
|
| 96 |
+
# gone. The PC has real disk and is the permanent archive, so each new note
|
| 97 |
+
# is pushed down the relay WebSocket as it is created. pc_relay_client
|
| 98 |
+
# INSERT OR IGNOREs by id, so repeats are harmless and ordering does not
|
| 99 |
+
# matter. Best-effort only: a disconnected PC must never break research.
|
| 100 |
+
try:
|
| 101 |
+
from backend.ws.agent_ws import ws_manager
|
| 102 |
+
payload = {
|
| 103 |
+
"event": "relay:research",
|
| 104 |
+
"payload": {"notes": [{
|
| 105 |
+
"id": note.id, "timestamp": note.timestamp, "category": note.category,
|
| 106 |
+
"title": note.title, "summary": note.summary, "source": note.source,
|
| 107 |
+
"importance": note.importance, "recommended_action": note.recommended_action,
|
| 108 |
+
}]},
|
| 109 |
+
}
|
| 110 |
+
import asyncio
|
| 111 |
+
try:
|
| 112 |
+
loop = asyncio.get_running_loop()
|
| 113 |
+
loop.create_task(ws_manager.broadcast(payload))
|
| 114 |
+
except RuntimeError:
|
| 115 |
+
# Called from a sync context with no running loop — skip rather than
|
| 116 |
+
# block the research thread.
|
| 117 |
+
pass
|
| 118 |
+
except Exception as e:
|
| 119 |
+
logging.debug(f"ResearchEngine: relay push skipped: {e}")
|
| 120 |
+
|
| 121 |
|
| 122 |
def _save_proposal(proposal: PendingProposal):
|
| 123 |
try:
|
backend/services/usb_monitor.py
CHANGED
|
@@ -24,6 +24,22 @@ except ImportError:
|
|
| 24 |
usb = None
|
| 25 |
|
| 26 |
def get_db_path():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
if getattr(sys, 'frozen', False):
|
| 28 |
return os.path.join(os.environ.get('APPDATA', os.path.expanduser('~')), 'JARVIS_OS', 'memory.db')
|
| 29 |
# abspath is backend/services/usb_monitor.py
|
|
|
|
| 24 |
usb = None
|
| 25 |
|
| 26 |
def get_db_path():
|
| 27 |
+
# JARVIS_APP_DATA_DIR wins when set. backend/security/vault.py has always
|
| 28 |
+
# honoured it, but this copy did not — and this is the one the research
|
| 29 |
+
# engine and the vault actually call. The mismatch meant pointing the app at
|
| 30 |
+
# durable storage silently did nothing: notes kept landing in the
|
| 31 |
+
# image-baked memory.db and were wiped by every Space rebuild.
|
| 32 |
+
#
|
| 33 |
+
# Nothing changes when the variable is unset: the frozen and project-root
|
| 34 |
+
# paths below are reached exactly as before.
|
| 35 |
+
app_data = os.environ.get('JARVIS_APP_DATA_DIR', '').strip()
|
| 36 |
+
if app_data:
|
| 37 |
+
try:
|
| 38 |
+
os.makedirs(app_data, exist_ok=True)
|
| 39 |
+
except Exception:
|
| 40 |
+
pass
|
| 41 |
+
return os.path.join(app_data, 'memory.db')
|
| 42 |
+
|
| 43 |
if getattr(sys, 'frozen', False):
|
| 44 |
return os.path.join(os.environ.get('APPDATA', os.path.expanduser('~')), 'JARVIS_OS', 'memory.db')
|
| 45 |
# abspath is backend/services/usb_monitor.py
|