everalgo-rank 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. everalgo_rank-0.1.0/.gitignore +58 -0
  2. everalgo_rank-0.1.0/CHANGELOG.md +30 -0
  3. everalgo_rank-0.1.0/LICENSE +21 -0
  4. everalgo_rank-0.1.0/PKG-INFO +114 -0
  5. everalgo_rank-0.1.0/README.md +94 -0
  6. everalgo_rank-0.1.0/pyproject.toml +31 -0
  7. everalgo_rank-0.1.0/src/everalgo/rank/__init__.py +76 -0
  8. everalgo_rank-0.1.0/src/everalgo/rank/case.py +87 -0
  9. everalgo_rank-0.1.0/src/everalgo/rank/episodic.py +87 -0
  10. everalgo_rank-0.1.0/src/everalgo/rank/fusion.py +595 -0
  11. everalgo_rank-0.1.0/src/everalgo/rank/profile.py +40 -0
  12. everalgo_rank-0.1.0/src/everalgo/rank/prompts/__init__.py +1 -0
  13. everalgo_rank-0.1.0/src/everalgo/rank/prompts/en/__init__.py +1 -0
  14. everalgo_rank-0.1.0/src/everalgo/rank/prompts/en/agentic.py +63 -0
  15. everalgo_rank-0.1.0/src/everalgo/rank/prompts/en/case.py +26 -0
  16. everalgo_rank-0.1.0/src/everalgo/rank/prompts/en/episodic.py +25 -0
  17. everalgo_rank-0.1.0/src/everalgo/rank/prompts/en/skill.py +25 -0
  18. everalgo_rank-0.1.0/src/everalgo/rank/prompts/zh/__init__.py +1 -0
  19. everalgo_rank-0.1.0/src/everalgo/rank/prompts/zh/agentic.py +59 -0
  20. everalgo_rank-0.1.0/src/everalgo/rank/prompts/zh/case.py +26 -0
  21. everalgo_rank-0.1.0/src/everalgo/rank/prompts/zh/episodic.py +25 -0
  22. everalgo_rank-0.1.0/src/everalgo/rank/prompts/zh/skill.py +25 -0
  23. everalgo_rank-0.1.0/src/everalgo/rank/py.typed +0 -0
  24. everalgo_rank-0.1.0/src/everalgo/rank/rerank.py +309 -0
  25. everalgo_rank-0.1.0/src/everalgo/rank/skill.py +87 -0
  26. everalgo_rank-0.1.0/src/everalgo/rank/weight.py +103 -0
  27. everalgo_rank-0.1.0/tests/rank/__init__.py +0 -0
  28. everalgo_rank-0.1.0/tests/rank/conftest.py +73 -0
  29. everalgo_rank-0.1.0/tests/rank/test_rank_case.py +79 -0
  30. everalgo_rank-0.1.0/tests/rank/test_rank_episodic.py +250 -0
  31. everalgo_rank-0.1.0/tests/rank/test_rank_fusion.py +488 -0
  32. everalgo_rank-0.1.0/tests/rank/test_rank_fusion_expand.py +212 -0
  33. everalgo_rank-0.1.0/tests/rank/test_rank_profile.py +69 -0
  34. everalgo_rank-0.1.0/tests/rank/test_rank_public_api.py +245 -0
  35. everalgo_rank-0.1.0/tests/rank/test_rank_rerank.py +112 -0
  36. everalgo_rank-0.1.0/tests/rank/test_rank_skill.py +53 -0
  37. everalgo_rank-0.1.0/tests/rank/test_rank_weight.py +159 -0
@@ -0,0 +1,58 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ wheels/
12
+
13
+ # Environments
14
+ .env
15
+ .env.local
16
+ .venv
17
+ env/
18
+ venv/
19
+
20
+ # uv
21
+ .uv/
22
+
23
+ # Test / coverage / cache
24
+ .pytest_cache/
25
+ .cache
26
+ .coverage
27
+ .coverage.*
28
+ coverage.xml
29
+ report.xml
30
+ htmlcov/
31
+ .tox/
32
+ .nox/
33
+ .hypothesis/
34
+
35
+ # Type checkers / linters
36
+ .mypy_cache/
37
+ .dmypy.json
38
+ .pyre/
39
+ .pytype/
40
+ .ruff_cache/
41
+
42
+ # Jupyter
43
+ .ipynb_checkpoints/
44
+
45
+ # IDE / OS
46
+ .vscode/
47
+ .idea/
48
+ *.swp
49
+ .DS_Store
50
+
51
+ # Logs
52
+ *.log
53
+
54
+ # Project local artifacts (placed under local/ per project convention)
55
+ local/
56
+
57
+ # Claude Code session-local state (scheduled tasks, agent caches, locks)
58
+ .claude/
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented here. Format follows
4
+ [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). Versioning
5
+ follows [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - `arank(rank_input, **kwargs) -> RankOutput`: async unified entry point; dispatches to the appropriate algorithm via an `_ALGO_REGISTRY` keyed by memory type.
12
+ - `rank(rank_input, **kwargs) -> RankOutput`: sync bridge via `asgiref.async_to_sync`.
13
+ - `EpisodicRanker`, `CaseRanker`, `SkillRanker`, `ProfileRanker`: facade classes that accept `llm=` at construction time and delegate to algorithm-layer functions.
14
+ - `aagentic_rank(query, candidates, *, llm, config) -> RankOutput`: multi-round agentic retrieval — LLM-guided sufficiency check followed by multi-query expansion, then RRF fusion over all rounds.
15
+ - `arerank(query, candidates, *, llm, prompt, config) -> list[Candidate]` and sync `rerank` bridge: LLM-scored pointwise reranker.
16
+ - `RankConfig` and `AgenticConfig` pydantic models for tuning rerank and agentic retrieval parameters.
17
+ - `FusionMode` enum: `rrf`, `lr`, `mrag`, `agentic`.
18
+ - `fusion.rrf(*sources, k) -> list[Candidate]`: Reciprocal Rank Fusion over multiple recall lists.
19
+ - `fusion.lr(candidates, *, weights) -> list[Candidate]`: linear-rank combination.
20
+ - `fusion.cosine_to_lr_score`, `fusion.score_propagation`, `fusion.expand`: score normalisation and episode-to-fact cross-memory expansion helpers.
21
+ - `weight` module: per-route weight configuration helpers.
22
+ - English rerank prompts for episodic, case, and skill memory types in `rank/prompts/en/`.
23
+
24
+ ### Removed
25
+
26
+ - Silent fallback returns in `_acheck_sufficiency` and `_agen_multi_queries`: both functions now raise on unexpected LLM response shapes instead of returning empty / default values.
27
+ - Silent fallback in `_apply_rerank_scores`: the function raises `ValueError` when the LLM response cannot be parsed into a valid score list.
28
+ - Outer `try/except` block in `aagentic_rank`: errors from sub-steps propagate to the caller unchanged.
29
+
30
+ [Unreleased]: https://github.com/EverMind-AI/EverAlgo/compare/main...HEAD
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EverMind
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: everalgo-rank
3
+ Version: 0.1.0
4
+ Summary: EverAlgo rank: 4 business-facing rankers (episodic / profile / case / skill) over a shared fusion / weight / rerank toolkit.
5
+ Project-URL: Homepage, https://github.com/EverMind-AI/EverAlgo
6
+ Project-URL: Repository, https://github.com/EverMind-AI/EverAlgo
7
+ Project-URL: Issues, https://github.com/EverMind-AI/EverAlgo/issues
8
+ Project-URL: Documentation, https://github.com/EverMind-AI/EverAlgo/tree/main/packages/everalgo-rank
9
+ Project-URL: Changelog, https://github.com/EverMind-AI/EverAlgo/blob/main/packages/everalgo-rank/CHANGELOG.md
10
+ Author: EverMind
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: asgiref>=3.0
18
+ Requires-Dist: everalgo-core<2.0.0,>=0.1.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # everalgo-rank
22
+
23
+ Memory ranking for EverAlgo — four business-facing ranker classes (`EpisodicRanker` / `CaseRanker` / `SkillRanker` / profile `rank`) composed over a shared toolkit (`fusion` / `weight` / `rerank`). Pure in-memory rank, no storage I/O.
24
+
25
+ See the umbrella project: [EverAlgo monorepo](../../README.md) and the architecture document at [`docs/concepts/architecture.md`](../../docs/concepts/architecture.md).
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install everalgo-rank
31
+ ```
32
+
33
+ ## What this distribution provides
34
+
35
+ | Symbol | Role |
36
+ |---|---|
37
+ | `EpisodicRanker` | Class facade — episodic memory ranking; LLM bound at construction |
38
+ | `CaseRanker` | Class facade — agent case ranking; LLM bound at construction |
39
+ | `SkillRanker` | Class facade — agent skill ranking; LLM bound at construction |
40
+ | `profile.rank` | Module-level sync function — profile ranking; cosine sort + dedup, no LLM |
41
+ | `RankConfig` | Frozen pydantic config: `fusion_mode`, `rrf_k`, `alpha`, etc. |
42
+ | `FusionMode` | Literal type: `"rrf"` / `"lr"` / `"mrag"` / `"agentic"` |
43
+ | `DEFAULT_RANK_CONFIG` | `RankConfig()` with defaults (`fusion_mode="rrf"`, `rrf_k=60`) |
44
+ | `arank` / `rank` | Top-level async / sync dispatch — routes to the registered ranker by `RankInput.memory_type` |
45
+ | `arerank` / `rerank` | Low-level LLM rerank step; used by the ranker facades internally |
46
+
47
+ ## Quick start
48
+
49
+ ```python
50
+ import asyncio
51
+ import json
52
+
53
+ from everalgo.llm.types import ChatResponse
54
+ from everalgo.rank import EpisodicRanker, DEFAULT_RANK_CONFIG
55
+ from everalgo.testing.fake_llm import FakeLLMClient
56
+ from everalgo.types import Candidate, RankInput
57
+
58
+ _RERANK_JSON = json.dumps({"ranked": [{"id": "ep_a", "score": 0.95}]})
59
+
60
+ async def main() -> None:
61
+ fake = FakeLLMClient(responses=[ChatResponse(content=_RERANK_JSON, model="fake")])
62
+ ranker = EpisodicRanker(llm=fake)
63
+
64
+ rank_input = RankInput(
65
+ query="Python async retry patterns",
66
+ memory_type="episodic",
67
+ dense_candidates=[
68
+ Candidate(id="ep_a", score=0.9, metadata={"episode": "Alice asked about async retries."}),
69
+ Candidate(id="ep_b", score=0.5, metadata={"episode": "Team discussed lunch."}),
70
+ ],
71
+ top_k=1,
72
+ )
73
+
74
+ output = await ranker.arank(rank_input, config=DEFAULT_RANK_CONFIG, enable_rerank=True)
75
+ for item in output.items:
76
+ print(f"{item.id} score={item.score:.2f}")
77
+
78
+ asyncio.run(main())
79
+ ```
80
+
81
+ ## LLM rerank step
82
+
83
+ `arerank` is the standalone LLM reranking primitive used internally by the ranker facades and exposed for direct use:
84
+
85
+ ```python
86
+ from everalgo.rank.rerank import arerank
87
+ from everalgo.rank.prompts.en.episodic import EPISODIC_RERANK_PROMPT_EN
88
+ from everalgo.types import Candidate
89
+
90
+ reranked = await arerank(
91
+ candidates,
92
+ prompt=EPISODIC_RERANK_PROMPT_EN,
93
+ top_k=5,
94
+ llm=client,
95
+ )
96
+ ```
97
+
98
+ ## API surface
99
+
100
+ | Symbol | Module | Signature summary |
101
+ |---|---|---|
102
+ | `EpisodicRanker` | `everalgo.rank` | `__init__(*, llm)` → `arank(rank_input, *, config, prompt, enable_rerank, ...) → RankOutput` |
103
+ | `CaseRanker` | `everalgo.rank` | Same shape as `EpisodicRanker` |
104
+ | `SkillRanker` | `everalgo.rank` | Same shape as `EpisodicRanker` |
105
+ | `profile.rank` | `everalgo.rank.profile` | `(rank_input, *, threshold=0.0) → RankOutput` — sync, no LLM |
106
+ | `RankConfig` | `everalgo.rank` | `fusion_mode: FusionMode = "rrf"`, `rrf_k: int = 60`, `alpha: float = 1.0`, `expand_limit: int = 3` |
107
+ | `arank` | `everalgo.rank` | Top-level async dispatch by `rank_input.memory_type` |
108
+ | `arerank` | `everalgo.rank.rerank` | `(items, *, prompt, top_k, llm) → list[Candidate]` |
109
+
110
+ ## Cross-links
111
+
112
+ - [`everalgo-core`](../everalgo-core/) — `RankInput`, `RankOutput`, `Candidate`, `ScoredItem`, `LLMClient`
113
+ - [`everalgo-user-memory`](../everalgo-user-memory/) — produces `Episode` / `AtomicFact` / `Profile` that EverOS Recall packages into `Candidate` for ranking
114
+ - [`everalgo-agent-memory`](../everalgo-agent-memory/) — produces `AgentCase` / `AgentSkill` candidates
@@ -0,0 +1,94 @@
1
+ # everalgo-rank
2
+
3
+ Memory ranking for EverAlgo — four business-facing ranker classes (`EpisodicRanker` / `CaseRanker` / `SkillRanker` / profile `rank`) composed over a shared toolkit (`fusion` / `weight` / `rerank`). Pure in-memory rank, no storage I/O.
4
+
5
+ See the umbrella project: [EverAlgo monorepo](../../README.md) and the architecture document at [`docs/concepts/architecture.md`](../../docs/concepts/architecture.md).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install everalgo-rank
11
+ ```
12
+
13
+ ## What this distribution provides
14
+
15
+ | Symbol | Role |
16
+ |---|---|
17
+ | `EpisodicRanker` | Class facade — episodic memory ranking; LLM bound at construction |
18
+ | `CaseRanker` | Class facade — agent case ranking; LLM bound at construction |
19
+ | `SkillRanker` | Class facade — agent skill ranking; LLM bound at construction |
20
+ | `profile.rank` | Module-level sync function — profile ranking; cosine sort + dedup, no LLM |
21
+ | `RankConfig` | Frozen pydantic config: `fusion_mode`, `rrf_k`, `alpha`, etc. |
22
+ | `FusionMode` | Literal type: `"rrf"` / `"lr"` / `"mrag"` / `"agentic"` |
23
+ | `DEFAULT_RANK_CONFIG` | `RankConfig()` with defaults (`fusion_mode="rrf"`, `rrf_k=60`) |
24
+ | `arank` / `rank` | Top-level async / sync dispatch — routes to the registered ranker by `RankInput.memory_type` |
25
+ | `arerank` / `rerank` | Low-level LLM rerank step; used by the ranker facades internally |
26
+
27
+ ## Quick start
28
+
29
+ ```python
30
+ import asyncio
31
+ import json
32
+
33
+ from everalgo.llm.types import ChatResponse
34
+ from everalgo.rank import EpisodicRanker, DEFAULT_RANK_CONFIG
35
+ from everalgo.testing.fake_llm import FakeLLMClient
36
+ from everalgo.types import Candidate, RankInput
37
+
38
+ _RERANK_JSON = json.dumps({"ranked": [{"id": "ep_a", "score": 0.95}]})
39
+
40
+ async def main() -> None:
41
+ fake = FakeLLMClient(responses=[ChatResponse(content=_RERANK_JSON, model="fake")])
42
+ ranker = EpisodicRanker(llm=fake)
43
+
44
+ rank_input = RankInput(
45
+ query="Python async retry patterns",
46
+ memory_type="episodic",
47
+ dense_candidates=[
48
+ Candidate(id="ep_a", score=0.9, metadata={"episode": "Alice asked about async retries."}),
49
+ Candidate(id="ep_b", score=0.5, metadata={"episode": "Team discussed lunch."}),
50
+ ],
51
+ top_k=1,
52
+ )
53
+
54
+ output = await ranker.arank(rank_input, config=DEFAULT_RANK_CONFIG, enable_rerank=True)
55
+ for item in output.items:
56
+ print(f"{item.id} score={item.score:.2f}")
57
+
58
+ asyncio.run(main())
59
+ ```
60
+
61
+ ## LLM rerank step
62
+
63
+ `arerank` is the standalone LLM reranking primitive used internally by the ranker facades and exposed for direct use:
64
+
65
+ ```python
66
+ from everalgo.rank.rerank import arerank
67
+ from everalgo.rank.prompts.en.episodic import EPISODIC_RERANK_PROMPT_EN
68
+ from everalgo.types import Candidate
69
+
70
+ reranked = await arerank(
71
+ candidates,
72
+ prompt=EPISODIC_RERANK_PROMPT_EN,
73
+ top_k=5,
74
+ llm=client,
75
+ )
76
+ ```
77
+
78
+ ## API surface
79
+
80
+ | Symbol | Module | Signature summary |
81
+ |---|---|---|
82
+ | `EpisodicRanker` | `everalgo.rank` | `__init__(*, llm)` → `arank(rank_input, *, config, prompt, enable_rerank, ...) → RankOutput` |
83
+ | `CaseRanker` | `everalgo.rank` | Same shape as `EpisodicRanker` |
84
+ | `SkillRanker` | `everalgo.rank` | Same shape as `EpisodicRanker` |
85
+ | `profile.rank` | `everalgo.rank.profile` | `(rank_input, *, threshold=0.0) → RankOutput` — sync, no LLM |
86
+ | `RankConfig` | `everalgo.rank` | `fusion_mode: FusionMode = "rrf"`, `rrf_k: int = 60`, `alpha: float = 1.0`, `expand_limit: int = 3` |
87
+ | `arank` | `everalgo.rank` | Top-level async dispatch by `rank_input.memory_type` |
88
+ | `arerank` | `everalgo.rank.rerank` | `(items, *, prompt, top_k, llm) → list[Candidate]` |
89
+
90
+ ## Cross-links
91
+
92
+ - [`everalgo-core`](../everalgo-core/) — `RankInput`, `RankOutput`, `Candidate`, `ScoredItem`, `LLMClient`
93
+ - [`everalgo-user-memory`](../everalgo-user-memory/) — produces `Episode` / `AtomicFact` / `Profile` that EverOS Recall packages into `Candidate` for ranking
94
+ - [`everalgo-agent-memory`](../everalgo-agent-memory/) — produces `AgentCase` / `AgentSkill` candidates
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "everalgo-rank"
7
+ version = "0.1.0"
8
+ description = "EverAlgo rank: 4 business-facing rankers (episodic / profile / case / skill) over a shared fusion / weight / rerank toolkit."
9
+ requires-python = ">=3.12"
10
+ license = "MIT"
11
+ readme = "README.md"
12
+ authors = [{ name = "EverMind" }]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3.12",
17
+ ]
18
+ dependencies = [
19
+ "asgiref>=3.0",
20
+ "everalgo-core>=0.1.0,<2.0.0",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/EverMind-AI/EverAlgo"
25
+ Repository = "https://github.com/EverMind-AI/EverAlgo"
26
+ Issues = "https://github.com/EverMind-AI/EverAlgo/issues"
27
+ Documentation = "https://github.com/EverMind-AI/EverAlgo/tree/main/packages/everalgo-rank"
28
+ Changelog = "https://github.com/EverMind-AI/EverAlgo/blob/main/packages/everalgo-rank/CHANGELOG.md"
29
+
30
+ [tool.hatch.build.targets.wheel]
31
+ packages = ["src/everalgo"]
@@ -0,0 +1,76 @@
1
+ """Memory ranking — public surface of the rank package."""
2
+
3
+ import logging
4
+
5
+ from asgiref.sync import sync_to_async
6
+
7
+ from everalgo.rank import case, episodic, fusion, profile, rerank, skill, weight
8
+ from everalgo.rank.case import CaseRanker
9
+ from everalgo.rank.episodic import EpisodicRanker
10
+ from everalgo.rank.prompts.en.case import CASE_RERANK_PROMPT_EN
11
+ from everalgo.rank.prompts.en.episodic import EPISODIC_RERANK_PROMPT_EN
12
+ from everalgo.rank.prompts.en.skill import SKILL_RERANK_PROMPT_EN
13
+ from everalgo.rank.rerank import (
14
+ _ALGO_REGISTRY,
15
+ DEFAULT_RANK_CONFIG,
16
+ FusionMode,
17
+ RankConfig,
18
+ _RankerSpec,
19
+ )
20
+ from everalgo.rank.rerank import (
21
+ _arank as arank,
22
+ )
23
+ from everalgo.rank.rerank import (
24
+ _rank as rank,
25
+ )
26
+ from everalgo.rank.skill import SkillRanker
27
+
28
+ __all__ = [
29
+ "DEFAULT_RANK_CONFIG",
30
+ "CaseRanker",
31
+ "EpisodicRanker",
32
+ "FusionMode",
33
+ "RankConfig",
34
+ "SkillRanker",
35
+ "arank",
36
+ "case",
37
+ "episodic",
38
+ "fusion",
39
+ "profile",
40
+ "rank",
41
+ "rerank",
42
+ "skill",
43
+ "weight",
44
+ ]
45
+
46
+ # Library logging setup (ADR-013): NullHandler on each subpackage logger.
47
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
48
+
49
+ _ALGO_REGISTRY.update(
50
+ {
51
+ "case": _RankerSpec(
52
+ arank=case.arank,
53
+ modes=("rrf", "lr", "agentic"),
54
+ rerank_prompt=CASE_RERANK_PROMPT_EN,
55
+ item_type="case",
56
+ ),
57
+ "skill": _RankerSpec(
58
+ arank=skill.arank,
59
+ modes=("rrf", "lr", "agentic"),
60
+ rerank_prompt=SKILL_RERANK_PROMPT_EN,
61
+ item_type="skill",
62
+ ),
63
+ "episodic": _RankerSpec(
64
+ arank=episodic.arank,
65
+ modes=("rrf", "lr", "mrag", "agentic"),
66
+ rerank_prompt=EPISODIC_RERANK_PROMPT_EN,
67
+ item_type="episode",
68
+ ),
69
+ "profile": _RankerSpec(
70
+ arank=sync_to_async(profile.rank),
71
+ modes=(),
72
+ rerank_prompt="",
73
+ item_type="profile",
74
+ ),
75
+ }
76
+ )
@@ -0,0 +1,87 @@
1
+ """Case ranker facade — thin wrapper over ``rerank._basic_arank``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from asgiref.sync import async_to_sync
8
+
9
+ from everalgo.rank.rerank import DEFAULT_RANK_CONFIG, RankConfig, _basic_arank
10
+
11
+ if TYPE_CHECKING:
12
+ from everalgo.llm.protocols import LLMClient
13
+ from everalgo.rank.fusion import RerankFn, RetrieveFn
14
+ from everalgo.types import RankInput, RankOutput
15
+
16
+ __all__ = ["CaseRanker"]
17
+
18
+
19
+ class CaseRanker:
20
+ """Class-style facade for the case ranker.
21
+
22
+ The LLM client is bound to the instance at construction time.
23
+ """
24
+
25
+ def __init__(self, *, llm: LLMClient) -> None:
26
+ self._llm = llm
27
+
28
+ async def arank(
29
+ self,
30
+ rank_input: RankInput,
31
+ *,
32
+ config: RankConfig = DEFAULT_RANK_CONFIG,
33
+ prompt: str | None = None,
34
+ enable_rerank: bool = False,
35
+ retrieve_fn: RetrieveFn | None = None,
36
+ rerank_fn: RerankFn | None = None,
37
+ ) -> RankOutput:
38
+ """Case ranker — see ``rerank._basic_arank`` for the pipeline body.
39
+
40
+ Args:
41
+ rank_input: Query + candidate sets for agent-case memory ranking.
42
+ config: Fusion mode and hyperparameters.
43
+ prompt: Per-call rerank prompt override; ``None`` uses the built-in default.
44
+ enable_rerank: When ``True``, run the LLM rerank stage after fusion.
45
+ retrieve_fn: Optional retrieval callback for the ``'agentic'`` fusion mode Round 2.
46
+ rerank_fn: Required for ``fusion_mode='agentic'``; cross-encoder callback for Round 1 rerank.
47
+
48
+ Returns:
49
+ Ranked and optionally LLM-reranked case items.
50
+ """
51
+ return await _basic_arank(
52
+ rank_input,
53
+ config=config,
54
+ llm=self._llm,
55
+ prompt=prompt,
56
+ enable_rerank=enable_rerank,
57
+ retrieve_fn=retrieve_fn,
58
+ rerank_fn=rerank_fn,
59
+ )
60
+
61
+ rank = async_to_sync(arank)
62
+ """Sync bridge — only callable from non-event-loop contexts."""
63
+
64
+
65
+ async def arank(
66
+ rank_input: RankInput,
67
+ *,
68
+ config: RankConfig = DEFAULT_RANK_CONFIG,
69
+ llm: LLMClient | None = None,
70
+ prompt: str | None = None,
71
+ enable_rerank: bool = False,
72
+ retrieve_fn: RetrieveFn | None = None,
73
+ rerank_fn: RerankFn | None = None,
74
+ ) -> RankOutput:
75
+ """Case module-level ranker — delegates to ``rerank._basic_arank``."""
76
+ return await _basic_arank(
77
+ rank_input,
78
+ config=config,
79
+ llm=llm,
80
+ prompt=prompt,
81
+ enable_rerank=enable_rerank,
82
+ retrieve_fn=retrieve_fn,
83
+ rerank_fn=rerank_fn,
84
+ )
85
+
86
+
87
+ rank = async_to_sync(arank)
@@ -0,0 +1,87 @@
1
+ """Episodic ranker facade — thin wrapper over ``rerank._basic_arank``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from asgiref.sync import async_to_sync
8
+
9
+ from everalgo.rank.rerank import DEFAULT_RANK_CONFIG, RankConfig, _basic_arank
10
+
11
+ if TYPE_CHECKING:
12
+ from everalgo.llm.protocols import LLMClient
13
+ from everalgo.rank.fusion import RerankFn, RetrieveFn
14
+ from everalgo.types import RankInput, RankOutput
15
+
16
+ __all__ = ["EpisodicRanker"]
17
+
18
+
19
+ class EpisodicRanker:
20
+ """Class-style facade for the episodic ranker.
21
+
22
+ The LLM client is bound to the instance at construction time.
23
+ """
24
+
25
+ def __init__(self, *, llm: LLMClient) -> None:
26
+ self._llm = llm
27
+
28
+ async def arank(
29
+ self,
30
+ rank_input: RankInput,
31
+ *,
32
+ config: RankConfig = DEFAULT_RANK_CONFIG,
33
+ prompt: str | None = None,
34
+ enable_rerank: bool = False,
35
+ retrieve_fn: RetrieveFn | None = None,
36
+ rerank_fn: RerankFn | None = None,
37
+ ) -> RankOutput:
38
+ """Episodic ranker — see ``rerank._basic_arank`` for the pipeline body.
39
+
40
+ Args:
41
+ rank_input: Query + candidate sets for episodic memory ranking.
42
+ config: Fusion mode and hyperparameters.
43
+ prompt: Per-call rerank prompt override; ``None`` uses the built-in default.
44
+ enable_rerank: When ``True``, run the LLM rerank stage after fusion.
45
+ retrieve_fn: Optional retrieval callback for the ``'agentic'`` fusion mode Round 2.
46
+ rerank_fn: Required for ``fusion_mode='agentic'``; cross-encoder callback for Round 1 rerank.
47
+
48
+ Returns:
49
+ Ranked and optionally LLM-reranked episodic items.
50
+ """
51
+ return await _basic_arank(
52
+ rank_input,
53
+ config=config,
54
+ llm=self._llm,
55
+ prompt=prompt,
56
+ enable_rerank=enable_rerank,
57
+ retrieve_fn=retrieve_fn,
58
+ rerank_fn=rerank_fn,
59
+ )
60
+
61
+ rank = async_to_sync(arank)
62
+ """Sync bridge — only callable from non-event-loop contexts."""
63
+
64
+
65
+ async def arank(
66
+ rank_input: RankInput,
67
+ *,
68
+ config: RankConfig = DEFAULT_RANK_CONFIG,
69
+ llm: LLMClient | None = None,
70
+ prompt: str | None = None,
71
+ enable_rerank: bool = False,
72
+ retrieve_fn: RetrieveFn | None = None,
73
+ rerank_fn: RerankFn | None = None,
74
+ ) -> RankOutput:
75
+ """Episodic module-level ranker — delegates to ``rerank._basic_arank``."""
76
+ return await _basic_arank(
77
+ rank_input,
78
+ config=config,
79
+ llm=llm,
80
+ prompt=prompt,
81
+ enable_rerank=enable_rerank,
82
+ retrieve_fn=retrieve_fn,
83
+ rerank_fn=rerank_fn,
84
+ )
85
+
86
+
87
+ rank = async_to_sync(arank)