Skip to content

Commit 009cb32

Browse files
kargarisaacclaude
andauthored
fix: make vllm-mlx optional, fix dashboard memory path in Docker, fix lint
* fix: make vllm-mlx optional, fix dashboard memory path in Docker Move vllm-mlx to optional [mlx] extra so base install stays lightweight and Docker builds succeed. Remove dead embeddings group. Fix dashboard showing no memories in Docker by searching all registered projects' memory dirs instead of only CWD-resolved primary. Add working_dir to compose template for correct scope resolution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: release v0.1.69 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve lint errors in test files Fix E741 (ambiguous variable `l` → `line`), F401 (unused imports), F841 (unused variable), and E402 (import ordering) across test files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove unused variable in build_eval_config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 973661a commit 009cb32

13 files changed

Lines changed: 46 additions & 37 deletions

pyproject.toml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "lerim"
7-
version = "0.1.68"
7+
version = "0.1.69"
88
description = "Continual learning layer for coding agents and software projects."
99
readme = "README.md"
1010
requires-python = ">=3.10"
@@ -21,7 +21,6 @@ dependencies = [
2121
"openrouter>=0.6.0",
2222
"pydantic-ai>=1.61.0",
2323
"logfire[dspy]>=4.25.0",
24-
"vllm-mlx>=0.2.6",
2524
"litellm>=1.81.13",
2625
"rich>=13.0",
2726
]
@@ -34,11 +33,8 @@ Changelog = "https://github.com/lerim-dev/lerim-cli/blob/main/CHANGELOG.md"
3433
Issues = "https://github.com/lerim-dev/lerim-cli/issues"
3534

3635
[project.optional-dependencies]
37-
embeddings = [
38-
"lancedb>=0.27.1",
39-
"pyarrow>=15.0.0",
40-
"torch>=2.2",
41-
"transformers>=5.0.0",
36+
mlx = [
37+
"vllm-mlx>=0.2.6",
4238
]
4339
test = [
4440
"pytest>=8.0",
@@ -73,7 +69,6 @@ markers = [
7369
"smoke: Quick LLM sanity checks (requires ollama)",
7470
"agent: Agent SDK or CLI integration tests",
7571
"llm: Non-agentic LLM integration tests",
76-
"embeddings: Embedding integration tests",
7772
"openrouter: OpenRouter provider tests",
7873
"openai: OpenAI provider tests",
7974
"zai: ZAI provider tests",

src/lerim/app/api.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,21 @@ def _generate_compose_yml(build_local: bool = False) -> str:
347347
else:
348348
image_or_build = f" image: {GHCR_IMAGE}:{__version__}"
349349

350+
# Set working_dir to first registered project so git_root_for() works
351+
# inside the container (otherwise CWD is / and scope falls back to global).
352+
workdir_line = ""
353+
if config.projects:
354+
first_project = next(iter(config.projects.values()))
355+
resolved_project = str(Path(first_project).expanduser().resolve())
356+
workdir_line = f'\n working_dir: "{resolved_project}"'
357+
350358
return f"""\
351359
# Auto-generated by lerim up — do not edit manually.
352360
# Regenerated from ~/.lerim/config.toml on every `lerim up`.
353361
services:
354362
lerim:
355363
{image_or_build}
356-
container_name: lerim
364+
container_name: lerim{workdir_line}
357365
command: ["--host", "0.0.0.0", "--port", "{port}"]
358366
restart: "no"
359367
ports:

src/lerim/app/dashboard.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -405,13 +405,33 @@ def _load_messages_for_run(run_doc: dict[str, Any]) -> list[dict[str, Any]]:
405405

406406

407407
def _list_memory_files_dashboard() -> list[Path]:
408-
"""List all markdown files in canonical memory primitive folders."""
408+
"""List all markdown files across global + all registered project memory dirs."""
409409
config = get_config()
410+
411+
# Collect candidate memory root dirs: primary, global, and all registered projects.
412+
mem_dirs: list[Path] = [
413+
config.memory_dir,
414+
config.global_data_dir / "memory",
415+
]
416+
for _name, project_path in config.projects.items():
417+
mem_dirs.append(
418+
Path(project_path).expanduser().resolve()
419+
/ config.memory_project_dir_name
420+
/ "memory"
421+
)
422+
423+
# Deduplicate by resolved path, then collect .md files from each.
424+
seen: set[Path] = set()
410425
paths: list[Path] = []
411-
for mtype in MemoryType:
412-
folder = config.memory_dir / memory_folder(mtype)
413-
if folder.exists():
414-
paths.extend(sorted(folder.rglob("*.md")))
426+
for d in mem_dirs:
427+
resolved = d.resolve()
428+
if resolved in seen:
429+
continue
430+
seen.add(resolved)
431+
for mtype in MemoryType:
432+
folder = resolved / memory_folder(mtype)
433+
if folder.exists():
434+
paths.extend(sorted(folder.rglob("*.md")))
415435
return paths
416436

417437

src/lerim/config/settings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,6 @@ def build_eval_config(
742742
load_dotenv()
743743
toml_data, _sources = _load_layers()
744744

745-
data = toml_data.get("data", {})
746745
memory = toml_data.get("memory", {})
747746
decay = memory.get("decay", {}) if isinstance(memory.get("decay", {}), dict) else {}
748747
server = toml_data.get("server", {})

tests/integration/test_dspy_adapters.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from __future__ import annotations
1212

13-
import json
1413
import shutil
1514
import tempfile
1615
from pathlib import Path
@@ -19,6 +18,9 @@
1918
import dspy
2019
import pytest
2120

21+
from lerim.memory.extract_pipeline import MemoryExtractSignature
22+
from lerim.memory.summarization_pipeline import TraceSummarySignature
23+
2224
from lerim.memory.schemas import MemoryCandidate
2325

2426
pytestmark = pytest.mark.integration
@@ -102,14 +104,6 @@ def _cleanup_eval_config(temp_dir: Path) -> None:
102104
shutil.rmtree(temp_dir, ignore_errors=True)
103105

104106

105-
# ---------------------------------------------------------------------------
106-
# Extraction signature (duplicated from pipeline to allow direct module calls)
107-
# ---------------------------------------------------------------------------
108-
109-
from lerim.memory.extract_pipeline import MemoryExtractSignature
110-
from lerim.memory.summarization_pipeline import TraceSummarySignature
111-
112-
113107
# ---------------------------------------------------------------------------
114108
# Extraction adapter tests
115109
# ---------------------------------------------------------------------------

tests/integration/test_eval_runners.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66

77
from __future__ import annotations
88

9-
import json
109
import os
11-
import shutil
12-
import tempfile
1310
from pathlib import Path
1411

1512
import pytest

tests/unit/test_catalog_queries.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
from lerim.sessions.catalog import (
1111
claim_session_jobs,
1212
enqueue_session_job,
13-
fetch_session_doc,
14-
get_indexed_run_ids,
1513
init_sessions_db,
1614
index_session_for_fts,
1715
latest_service_run,

tests/unit/test_claude_adapter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def test_compact_trace_drops_noise_types():
264264
),
265265
]
266266
result = compact_trace("\n".join(lines) + "\n")
267-
parsed = [json.loads(l) for l in result.strip().split("\n")]
267+
parsed = [json.loads(line) for line in result.strip().split("\n")]
268268
assert len(parsed) == 2
269269
assert parsed[0]["type"] == "user"
270270
assert parsed[1]["type"] == "assistant"
@@ -395,6 +395,6 @@ def test_compact_trace_keeps_malformed_lines():
395395
+ "\n"
396396
)
397397
result = compact_trace(raw)
398-
lines = [l for l in result.strip().split("\n") if l.strip()]
398+
lines = [line for line in result.strip().split("\n") if line.strip()]
399399
assert lines[0] == "not-json"
400400
assert json.loads(lines[1])["type"] == "user"

tests/unit/test_codex_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def test_compact_trace_drops_turn_context():
160160
),
161161
]
162162
result = compact_trace("\n".join(lines) + "\n")
163-
parsed = [json.loads(l) for l in result.strip().split("\n")]
163+
parsed = [json.loads(line) for line in result.strip().split("\n")]
164164
assert len(parsed) == 1
165165
assert parsed[0]["type"] == "event_msg"
166166

tests/unit/test_cursor_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,6 @@ def test_compact_trace_preserves_user_assistant_text():
322322
json.dumps({"type": 2, "text": "assistant reply"}),
323323
]
324324
result = compact_trace("\n".join(lines) + "\n")
325-
parsed = [json.loads(l) for l in result.strip().split("\n")]
325+
parsed = [json.loads(line) for line in result.strip().split("\n")]
326326
assert parsed[0]["text"] == "user message"
327327
assert parsed[1]["text"] == "assistant reply"

0 commit comments

Comments
 (0)