(
self,
task_type: str,
*,
topic: str = "",
tags: list[str] | None = None,
text: str = "",
project_key: str = "",
top_k: int | None = None,
)
| 613 | return changed + research_changed |
| 614 | |
| 615 | def retrieve( |
| 616 | self, |
| 617 | task_type: str, |
| 618 | *, |
| 619 | topic: str = "", |
| 620 | tags: list[str] | None = None, |
| 621 | text: str = "", |
| 622 | project_key: str = "", |
| 623 | top_k: int | None = None, |
| 624 | ) -> list[MemoryRecord]: |
| 625 | if not self.enabled: |
| 626 | return [] |
| 627 | weights = _TASK_TYPE_WEIGHTS.get(task_type, _TASK_TYPE_WEIGHTS.get("planning", {})) |
| 628 | query_tags = set(self._normalize_tags(tags)) |
| 629 | query_tokens = self._tokenize(" ".join([topic, text, " ".join(query_tags)])) |
| 630 | query_anchor_tokens = self._anchor_tokens(query_tokens) |
| 631 | scored: list[tuple[float, MemoryRecord]] = [] |
| 632 | for record in self._load_records(): |
| 633 | memory_weight = weights.get(record.memory_type, 1.0) |
| 634 | record_tokens = self._tokenize(record.content) |
| 635 | record_anchor_tokens = self._anchor_tokens(record_tokens) |
| 636 | token_overlap, overlap_ratio = self._overlap_stats(query_tokens, record_tokens) |
| 637 | anchor_overlap = len(query_anchor_tokens & record_anchor_tokens) |
| 638 | tag_overlap = len(set(record.tags) & query_tags) |
| 639 | same_project = bool(project_key and record.project_key == project_key) |
| 640 | cross_project = bool(project_key and record.project_key and record.project_key != project_key) |
| 641 | if project_key and record.project_key and not same_project: |
| 642 | continue |
| 643 | if record.memory_type == MemoryType.PROJECT_CONTEXT and not same_project: |
| 644 | continue |
| 645 | if cross_project and not self._is_strong_cross_project_match( |
| 646 | task_type=task_type, |
| 647 | memory_type=record.memory_type, |
| 648 | overlap=token_overlap, |
| 649 | overlap_ratio=overlap_ratio, |
| 650 | tag_overlap=tag_overlap, |
| 651 | anchor_overlap=anchor_overlap, |
| 652 | ): |
| 653 | continue |
| 654 | project_bonus = 0.45 if same_project else 0.0 |
| 655 | score = ( |
| 656 | memory_weight * (1.2 + record.importance + record.recency_weight) |
| 657 | + 0.55 * token_overlap |
| 658 | + 0.9 * tag_overlap |
| 659 | + project_bonus |
| 660 | ) |
| 661 | if score >= 1.45: |
| 662 | scored.append((score, record)) |
| 663 | scored.sort(key=lambda item: (item[0], item[1].timestamp), reverse=True) |
| 664 | limit = max(1, top_k or self.top_k) |
| 665 | return [record for _, record in scored[:limit]] |
| 666 | |
| 667 | def retrieve_research( |
| 668 | self, |
no test coverage detected