From 2280d1637db194730dfb5be5af3d813105474457 Mon Sep 17 00:00:00 2001 From: Platform Bot Date: Fri, 3 Jul 2026 16:53:08 +0000 Subject: [PATCH 1/2] fix(recall): prefer smart_score as ranking key in RecalledMemory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Server sorts recall results by smart_score (fallback weighted_score → score) but RecalledMemory.from_dict and RecallResponse._normalize_memory only propagated the raw score field. Fix prioritizes smart_score, exposing smart_score and weighted_score as optional dataclass fields. Tests: 5 unit tests covering all fallback paths and nested envelope normalization. Co-Authored-By: Paperclip --- src/dakera/models.py | 18 ++++++++-- tests/test_smart_score.py | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 tests/test_smart_score.py diff --git a/src/dakera/models.py b/src/dakera/models.py index fc699ea..d0664f8 100644 --- a/src/dakera/models.py +++ b/src/dakera/models.py @@ -699,6 +699,11 @@ class RecalledMemory: memory_type: str importance: float score: float + """Ranking score — equals smart_score when present, then weighted_score, then raw score.""" + smart_score: float | None = None + """Raw smart_score from the server (the primary ranking key).""" + weighted_score: float | None = None + """Raw weighted_score from the server.""" metadata: dict[str, Any] | None = None created_at: str | None = None depth: int | None = None @@ -706,12 +711,17 @@ class RecalledMemory: @classmethod def from_dict(cls, data: dict[str, Any]) -> "RecalledMemory": + smart_score = data.get("smart_score") + weighted_score = data.get("weighted_score") + score = smart_score if smart_score is not None else (weighted_score if weighted_score is not None else data.get("score", 0.0)) return cls( id=data["id"], content=data["content"], memory_type=data.get("memory_type", "episodic"), importance=data.get("importance", 0.5), - score=data.get("score", 0.0), + score=score, + smart_score=smart_score, + weighted_score=weighted_score, metadata=data.get("metadata"), created_at=data.get("created_at"), depth=data.get("depth"), @@ -733,9 +743,13 @@ class RecallResponse: @classmethod def _normalize_memory(cls, m: dict[str, Any]) -> dict[str, Any]: - """Flatten nested {memory: {...}, score: ...} into a single dict.""" + """Flatten nested {memory: {...}, score, weighted_score, smart_score} into a single dict.""" if "memory" in m and isinstance(m["memory"], dict): flat = {**m["memory"], "score": m.get("score", 0.0)} + if "smart_score" in m: + flat["smart_score"] = m["smart_score"] + if "weighted_score" in m: + flat["weighted_score"] = m["weighted_score"] return flat return m diff --git a/tests/test_smart_score.py b/tests/test_smart_score.py new file mode 100644 index 0000000..8460382 --- /dev/null +++ b/tests/test_smart_score.py @@ -0,0 +1,76 @@ +"""Tests for RecalledMemory.score priority: smart_score > weighted_score > raw score.""" + +from dakera.models import RecalledMemory, RecallResponse + + +def test_smart_score_takes_priority(): + data = { + "id": "m1", "content": "test", "memory_type": "episodic", "importance": 0.8, + "score": 0.5, "weighted_score": 0.7, "smart_score": 0.9, + } + m = RecalledMemory.from_dict(data) + assert m.score == pytest.approx(0.9), ".score must equal smart_score when present" + assert m.smart_score == pytest.approx(0.9) + assert m.weighted_score == pytest.approx(0.7) + + +def test_weighted_score_fallback(): + data = { + "id": "m2", "content": "test", "memory_type": "episodic", "importance": 0.8, + "score": 0.5, "weighted_score": 0.7, + } + m = RecalledMemory.from_dict(data) + assert m.score == pytest.approx(0.7), ".score must equal weighted_score when smart_score absent" + assert m.smart_score is None + assert m.weighted_score == pytest.approx(0.7) + + +def test_raw_score_fallback(): + data = { + "id": "m3", "content": "test", "memory_type": "episodic", "importance": 0.8, + "score": 0.55, + } + m = RecalledMemory.from_dict(data) + assert m.score == pytest.approx(0.55), ".score must equal raw score when neither smart_score nor weighted_score" + assert m.smart_score is None + assert m.weighted_score is None + + +def test_recall_response_normalize_forwards_smart_score(): + raw = { + "memories": [ + { + "memory": {"id": "m4", "content": "nested", "memory_type": "episodic", "importance": 0.9, + "created_at": "2026-01-01T00:00:00Z", "tags": []}, + "score": 0.4, + "weighted_score": 0.6, + "smart_score": 0.85, + } + ] + } + resp = RecallResponse.from_dict(raw) + assert len(resp.memories) == 1 + m = resp.memories[0] + assert m.score == pytest.approx(0.85) + assert m.smart_score == pytest.approx(0.85) + assert m.weighted_score == pytest.approx(0.6) + + +def test_recall_response_normalize_without_smart_score(): + raw = { + "memories": [ + { + "memory": {"id": "m5", "content": "nested2", "memory_type": "semantic", "importance": 0.7, + "created_at": "2026-01-01T00:00:00Z", "tags": []}, + "score": 0.3, + "weighted_score": 0.55, + } + ] + } + resp = RecallResponse.from_dict(raw) + m = resp.memories[0] + assert m.score == pytest.approx(0.55) + assert m.smart_score is None + + +import pytest From cef886c68c4110b744274af4a48f06e1fa5c58d0 Mon Sep 17 00:00:00 2001 From: Platform Bot Date: Fri, 3 Jul 2026 17:43:07 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(lint):=20ruff=20E501/E402=20=E2=80=94?= =?UTF-8?q?=20wrap=20long=20lines,=20move=20pytest=20import=20to=20top?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- src/dakera/models.py | 7 ++++++- tests/test_smart_score.py | 29 +++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/dakera/models.py b/src/dakera/models.py index d0664f8..6bdca49 100644 --- a/src/dakera/models.py +++ b/src/dakera/models.py @@ -713,7 +713,12 @@ class RecalledMemory: def from_dict(cls, data: dict[str, Any]) -> "RecalledMemory": smart_score = data.get("smart_score") weighted_score = data.get("weighted_score") - score = smart_score if smart_score is not None else (weighted_score if weighted_score is not None else data.get("score", 0.0)) + if smart_score is not None: + score = smart_score + elif weighted_score is not None: + score = weighted_score + else: + score = data.get("score", 0.0) return cls( id=data["id"], content=data["content"], diff --git a/tests/test_smart_score.py b/tests/test_smart_score.py index 8460382..085db39 100644 --- a/tests/test_smart_score.py +++ b/tests/test_smart_score.py @@ -1,5 +1,7 @@ """Tests for RecalledMemory.score priority: smart_score > weighted_score > raw score.""" +import pytest + from dakera.models import RecalledMemory, RecallResponse @@ -31,7 +33,9 @@ def test_raw_score_fallback(): "score": 0.55, } m = RecalledMemory.from_dict(data) - assert m.score == pytest.approx(0.55), ".score must equal raw score when neither smart_score nor weighted_score" + assert m.score == pytest.approx(0.55), ( + ".score must equal raw score when neither smart_score nor weighted_score" + ) assert m.smart_score is None assert m.weighted_score is None @@ -40,8 +44,14 @@ def test_recall_response_normalize_forwards_smart_score(): raw = { "memories": [ { - "memory": {"id": "m4", "content": "nested", "memory_type": "episodic", "importance": 0.9, - "created_at": "2026-01-01T00:00:00Z", "tags": []}, + "memory": { + "id": "m4", + "content": "nested", + "memory_type": "episodic", + "importance": 0.9, + "created_at": "2026-01-01T00:00:00Z", + "tags": [], + }, "score": 0.4, "weighted_score": 0.6, "smart_score": 0.85, @@ -60,8 +70,14 @@ def test_recall_response_normalize_without_smart_score(): raw = { "memories": [ { - "memory": {"id": "m5", "content": "nested2", "memory_type": "semantic", "importance": 0.7, - "created_at": "2026-01-01T00:00:00Z", "tags": []}, + "memory": { + "id": "m5", + "content": "nested2", + "memory_type": "semantic", + "importance": 0.7, + "created_at": "2026-01-01T00:00:00Z", + "tags": [], + }, "score": 0.3, "weighted_score": 0.55, } @@ -71,6 +87,3 @@ def test_recall_response_normalize_without_smart_score(): m = resp.memories[0] assert m.score == pytest.approx(0.55) assert m.smart_score is None - - -import pytest