Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/openmlr/db/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ async def upsert_paper_resource(
async def upsert_resource(
db: AsyncSession, conv_id: int,
resource_id: str, title: str, resource_type: str,
content: str = None, url: str = None,
content: str | None = None, url: str | None = None,
) -> ConversationResource:
"""Create or update a resource by resource_id."""
existing = await get_resource_by_id(db, resource_id)
Expand Down Expand Up @@ -478,7 +478,7 @@ async def update_job_status(

# ---- User Settings ----

async def get_user_settings(db: AsyncSession, user_id: int, category: str = None) -> dict:
async def get_user_settings(db: AsyncSession, user_id: int, category: str | None = None) -> dict:
"""Get user settings as a dict. Optionally filter by category."""
query = select(UserSetting).where(UserSetting.user_id == user_id)
if category:
Expand Down
5 changes: 3 additions & 2 deletions backend/openmlr/services/session_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@

session = Session(config=config, conversation_id=conversation_id)

# Import here (not at module level) to avoid circular imports
from ..db import operations as ops

# Determine effective compute node
effective_node = None
if user_id and db:
try:
from ..db import operations as ops
# Check conversation override
conv = await ops.get_conversation_by_id(db, conversation_id)
if conv and conv.extra:
Expand Down Expand Up @@ -130,7 +132,6 @@
# Load MCP servers from user settings if available
if user_id and db:
try:
from ..db import operations as ops
user_settings = await ops.get_all_settings(db, user_id, category="mcp")
mcp_settings = user_settings.get("mcp", {})
mcp_servers = mcp_settings.get("servers", {})
Expand Down Expand Up @@ -176,7 +177,7 @@
if user_id and db:
try:
all_nodes = await ops.get_compute_nodes(db, user_id)
except Exception:

Check notice on line 180 in backend/openmlr/services/session_manager.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
pass
if len(all_nodes) > 1:
lines.append("\n### Other Available Nodes")
Expand Down Expand Up @@ -226,16 +227,16 @@
try:
if not active.session.pending_answers.done():
active.session.pending_answers.cancel()
except Exception:

Check notice on line 230 in backend/openmlr/services/session_manager.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
pass
try:
await active.sandbox_manager.destroy()
except Exception:

Check notice on line 234 in backend/openmlr/services/session_manager.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
pass
# Disconnect MCP servers
try:
await active.mcp_manager.disconnect_all()
except Exception:

Check notice on line 239 in backend/openmlr/services/session_manager.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
pass
if self.current_conversation_id == conversation_id:
self.current_conversation_id = None
Expand Down Expand Up @@ -287,7 +288,7 @@
return None
try:
return await LLMProvider.generate_title(messages, active.session.config)
except Exception:

Check notice on line 291 in backend/openmlr/services/session_manager.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
return None

@property
Expand Down
4 changes: 3 additions & 1 deletion backend/openmlr/tools/compute_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
return target, None


async def _handle_list(user_id: int = None, db=None, **kwargs):

Check notice on line 23 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""List all compute nodes with capabilities."""
if not db:
return "Database connection required for compute_list", False
Expand Down Expand Up @@ -53,7 +53,7 @@
return "\n".join(lines), True


async def _handle_probe(node_name: str, user_id: int = None, db=None, **kwargs):

Check notice on line 56 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""Probe a compute node for capabilities."""
if not db:
return "Database connection required for compute_probe", False
Expand All @@ -67,6 +67,7 @@
from ..compute import WorkspaceManager
from ..sandbox.manager import SandboxManager

sm = None
try:
wm = WorkspaceManager()
sm = SandboxManager(workspace_manager=wm)
Expand All @@ -88,7 +89,7 @@
await sm.destroy()

# Format response
lines = [f"## {node.name} Capabilities\n"]

Check notice on line 92 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Non-optimal list declaration

Multi-step list initialization can be replaced with a list literal
lines.append(f"Platform: {caps.platform}")
lines.append(f"CPU: {caps.cpu_cores} cores ({caps.cpu_arch})")
lines.append(f"RAM: {caps.available_ram_gb:.1f} GB available / {caps.total_ram_gb:.1f} GB total")
Expand All @@ -115,8 +116,9 @@

except Exception as e:
try:
await sm.destroy()
if sm is not None:
await sm.destroy()
except Exception:

Check notice on line 121 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unclear exception clauses

Too broad exception clause
pass
await ops.update_compute_node(
db, node.id, user_id,
Expand All @@ -125,7 +127,7 @@
return f"Probe failed for {node_name}: {str(e)}", False


async def _handle_select(node_name: str, user_id: int = None, db=None, session=None, **kwargs):

Check notice on line 130 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""Select a compute node as active for this conversation."""
if not db:
return "Database connection required for compute_select", False
Expand All @@ -149,7 +151,7 @@
return f"Active compute switched to: {node.name} ({node.type})", True


async def _handle_plan(task: str, requirements: dict = None, user_id: int = None, db=None, **kwargs):

Check notice on line 154 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""Recommend the best compute node for a task."""
if not db:
return "Database connection required for compute_plan", False
Expand Down Expand Up @@ -224,7 +226,7 @@
scores.sort(key=lambda x: x["score"], reverse=True)
best = scores[0]

lines = [f"## Recommended Compute for: {task}\n"]

Check notice on line 229 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Non-optimal list declaration

Multi-step list initialization can be replaced with a list literal
lines.append(f"**Best choice: {best['node'].name}** ({best['node'].type})")
lines.append(f"Score: {best['score']:.1f}")
lines.append(f"Reasons: {', '.join(best['reasons'])}")
Expand All @@ -237,7 +239,7 @@
return "\n".join(lines), True


async def _get_sync_context(user_id, db, session):

Check notice on line 242 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'user_id' value is not used
"""Helper: resolve conversation UUID and workspace path for sync ops."""
from ..db import operations as ops
conv_uuid = None
Expand All @@ -253,7 +255,7 @@
return conv_uuid, local_ws, None


async def _handle_sync_up(paths: list, node_name: str, user_id: int = None, db=None, session=None, **kwargs):

Check notice on line 258 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""Sync files from local workspace to remote compute node."""
if not db:
return "Database connection required", False
Expand Down Expand Up @@ -301,7 +303,7 @@
await ssh_sandbox.execute(f"mkdir -p '{dst_dir}'", timeout=5)
content = src.read_bytes()
await asyncio.to_thread(
lambda d=dst, c=content: ssh_sandbox._sftp.putfo(io.BytesIO(c), d)

Check notice on line 306 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _sftp of a class
)
transferred += 1
else:
Expand All @@ -311,7 +313,7 @@
await ssh_sandbox.execute(f"mkdir -p '{dst_dir}'", timeout=5)
content = local_path.read_bytes()
await asyncio.to_thread(
lambda d=dst, c=content: ssh_sandbox._sftp.putfo(io.BytesIO(c), d)

Check notice on line 316 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _sftp of a class
)
transferred += 1

Expand All @@ -327,7 +329,7 @@
return "Unsupported node type", False


async def _handle_sync_down(paths: list, node_name: str, user_id: int = None, db=None, session=None, **kwargs):

Check notice on line 332 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'kwargs' value is not used
"""Sync files from remote compute node to local workspace."""
if not db:
return "Database connection required", False
Expand Down Expand Up @@ -377,7 +379,7 @@

def _do_get(rpath=rp):
buf = io.BytesIO()
ssh_sandbox._sftp.getfo(rpath, buf)

Check notice on line 382 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _sftp of a class
buf.seek(0)
return buf.read()

Expand All @@ -400,7 +402,7 @@
# Bind rf in default arg to avoid closure-in-loop bug
def _do_get_file(rpath=rf):
buf = io.BytesIO()
ssh_sandbox._sftp.getfo(rpath, buf)

Check notice on line 405 in backend/openmlr/tools/compute_tools.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _sftp of a class
buf.seek(0)
return buf.read()

Expand Down
2 changes: 0 additions & 2 deletions backend/tests/test_agent_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

from openmlr.agent.context import ContextManager
from openmlr.agent.loop import (
_compact,

Check notice on line 9 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _compact of a class
_compact_llm_call,

Check notice on line 10 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _compact_llm_call of a class
_execute_tool,

Check notice on line 11 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _execute_tool of a class
_handle_approval,

Check notice on line 12 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _handle_approval of a class
_non_stream_llm_call,

Check notice on line 13 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _non_stream_llm_call of a class
_run_agent,

Check notice on line 14 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _run_agent of a class
_stream_llm_call,

Check notice on line 15 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _stream_llm_call of a class
_undo,

Check notice on line 16 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Accessing a protected member of a class or a module

Access to a protected member _undo of a class
run_agent_turn,
submission_loop,
)
Expand Down Expand Up @@ -326,7 +326,7 @@
mock_session.is_cancelled.return_value = False
mock_session.config = AgentConfig(model_name="test", stream=True)

async def mock_stream(messages, config, tools):

Check notice on line 329 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'config' value is not used

Check notice on line 329 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'messages' value is not used

Check notice on line 329 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'tools' value is not used
yield "Hello"
yield " world"

Expand All @@ -341,10 +341,8 @@
async def test_cancelled_returns_none(self, mock_session):
mock_session.is_cancelled.return_value = True

async def mock_stream(messages, config, tools):

Check notice on line 344 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'tools' value is not used

Check notice on line 344 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'messages' value is not used

Check notice on line 344 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'config' value is not used
yield "Hello"
if False:
yield

with patch("openmlr.agent.loop.LLMProvider.generate_stream") as mock_str:
mock_str.return_value = mock_stream(None, None, None)
Expand All @@ -357,7 +355,7 @@
mock_session.config = AgentConfig(model_name="test", stream=True)
tc = ToolCall(id="call_1", name="search", arguments={"query": "test"})

async def mock_stream(messages, config, tools):

Check notice on line 358 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'tools' value is not used

Check notice on line 358 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'config' value is not used

Check notice on line 358 in backend/tests/test_agent_loop.py

View workflow job for this annotation

GitHub Actions / Qodana for Python

Unused local symbols

Parameter 'messages' value is not used
yield "Finding..."
yield tc

Expand Down
4 changes: 4 additions & 0 deletions qodana.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

version: "1.0"
linter: jetbrains/qodana-python-community:2025.3
projectJDK: "python3.12"
profile:
name: qodana.recommended
bootstrap: |
# Ensure Qodana uses Python 3.12+ for correct type hint inspection (PEP 604, PEP 585)
python3.12 --version 2>/dev/null || python3 --version
include:
- name: CheckDependencyLicenses
Loading